@lexnode/legal-data-sdk 1.26.0 → 1.28.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 CHANGED
@@ -73,6 +73,7 @@ await lexnode.publications.list({ oabNumber: "123456", oabState: "SP" });
73
73
  await lexnode.monitors.create({ type: "OAB", oabNumber: "123456", oabState: "SP" });
74
74
  await lexnode.subscriptions.create({ tribunalAlias, processNumber, externalRef });
75
75
  await lexnode.searchJobs.get(jobId);
76
+ await lexnode.processLookups.get(lookupId);
76
77
  await lexnode.events.list({ limit: 50 });
77
78
  await lexnode.webhooks.endpoints.list();
78
79
  await lexnode.webhooks.unsubscribedEventTypes();
@@ -194,12 +195,24 @@ switch (resultado.event.type) {
194
195
  break;
195
196
  case "PROCESS_MOVEMENT_CREATED":
196
197
  resultado.event.payload.externalRef;
198
+ resultado.event.payload.degree; // o grau do movimento mais recente
199
+ break;
200
+ case "PROCESS_INSTANCE_DISCOVERED":
201
+ // Outro grau do processo apareceu na fonte; o histórico dele está no
202
+ // retrato, em `instances`. O processo retido vem sem o grau.
203
+ if (!resultado.event.payload.contentWithheld) {
204
+ resultado.event.payload.degree;
205
+ }
197
206
  break;
198
207
  case "SEARCH_JOB_COMPLETED":
199
208
  if (resultado.event.payload.status === "FAILED") {
200
209
  resultado.event.payload.error.code;
201
210
  }
202
211
  break;
212
+ case "PROCESS_LOOKUP_COMPLETED":
213
+ // Um ponteiro: o processo se lê em payload.pollUrl, sem nova cobrança.
214
+ resultado.event.payload.lookupId;
215
+ break;
203
216
  case "WEBHOOK_TEST":
204
217
  // A entrega de teste do console. Chega a qualquer endpoint, não se assina
205
218
  // e não se recusa — é ela que valida o receptor antes do primeiro evento.
@@ -256,6 +269,94 @@ if (desfecho.kind === "sync") {
256
269
  }
257
270
  ```
258
271
 
272
+ ## Um número, várias instâncias
273
+
274
+ A fonte processual guarda um documento por instância do processo — 1º grau, 2º
275
+ grau, turma recursal… —, às vezes dois do mesmo grau, e o motor guarda cada um
276
+ na sua instância.
277
+
278
+ **O topo não troca.** O topo da ficha (`data`) e do retrato (`data.process` e
279
+ `data.movements`) é sempre a instância principal do número, com o grau em
280
+ `degree`: a mesma de uma leitura para a outra, qualquer que seja a ordem em que
281
+ a fonte devolve os documentos. Ela só muda quando uma resposta completa da
282
+ fonte pelo número deixa de trazê-la. Quem compara movimentos pela chave não vê
283
+ o histórico de outro grau aparecer como novo no topo — e o topo pode não ser o
284
+ grau que anda: o 2º grau guardado primeiro continua no topo enquanto o 1º se
285
+ move.
286
+
287
+ **Todos os graus em `instances`.** A ficha e o retrato listam em `instances`
288
+ todos os documentos que o motor guarda do número, a principal primeiro
289
+ (`primary: true`). Cada um diz de onde veio nesta resposta (`origin`: `SOURCE`
290
+ quando a fonte o trouxe, `LAKE` quando saiu do acervo), quando foi buscado
291
+ (`fetchedAt`) e desde quando a resposta completa da fonte vem sem ele
292
+ (`absentSince`). No retrato, cada instância traz os movimentos da última captura
293
+ dela, do mais recente ao mais antigo e sem o payload bruto da fonte; a que o
294
+ motor nunca capturou vem com `movementsCaptured: false` e `movements` nulo, nunca
295
+ com lista vazia, que diria que o grau não andou. Todos os documentos levam a
296
+ classificação do número inteiro — basta um em segredo de justiça para todos
297
+ saírem marcados —, e a ficha retida pelo controle de confidencialidade sai sem a
298
+ lista.
299
+
300
+ ```ts
301
+ const { data } = await lexnode.processes.snapshot(numero, { tribunalAlias });
302
+
303
+ for (const instancia of data.instances) {
304
+ instancia.degree; // "G1", "G2", "TR"…
305
+ instancia.primary; // true só na do topo
306
+ instancia.movements ?? "movimentos nunca capturados";
307
+ }
308
+ ```
309
+
310
+ No lote (`processes.snapshotBatch`), `instances` traz só o cabeçalho de cada
311
+ documento; os movimentos de cada instância vêm no retrato de um processo. A
312
+ busca por número completo servida do acervo devolve um item por documento que a
313
+ fonte ainda traz do número, a principal primeiro; quando eles não cabem em
314
+ `limit`, a busca vai à fonte, que pagina.
315
+
316
+ **Recorte por grau.** A lista de movimentações aceita `degree` e devolve só os
317
+ movimentos que o documento daquele grau trouxe na última captura; cada item diz
318
+ em `degrees` o grau — ou os graus, quando o mesmo ato está nos dois documentos
319
+ — que o trouxe, e vem vazio no movimento que nenhuma captura atual traz.
320
+
321
+ ```ts
322
+ const { data } = await lexnode.processes.movements(numero, {
323
+ tribunalAlias,
324
+ degree: "G1",
325
+ });
326
+ data.items; // só o que o 1º grau trouxe
327
+ ```
328
+
329
+ **O grau novo chega num evento só.** Quando outro grau de um processo assinado
330
+ aparece na fonte, o histórico dele entra no acervo sem virar
331
+ `PROCESS_MOVEMENT_CREATED` movimento a movimento: chega um
332
+ `PROCESS_INSTANCE_DISCOVERED`, com o grau, o órgão julgador e as contagens —
333
+ `historyMovementCount` entrou sem aviso próprio, `announcedMovementCount` saiu
334
+ também como movimento novo. O `PROCESS_MOVEMENT_CREATED` diz o grau do
335
+ movimento mais recente (`degree`, `instanceSourceId`) e quantos movimentos novos
336
+ vieram de cada grau (`instances`). Assine os dois: quem assina só o movimento
337
+ não fica sabendo do grau que apareceu.
338
+
339
+ **`meta.otherInstances`: o resumo do que veio.** Quando a resposta da fonte traz
340
+ outros documentos do número além da principal, `meta.otherInstances` resume cada
341
+ um com o grau (`grau`), a data em que a fonte o atualizou (`updatedAt`) e o
342
+ órgão julgador (`courtBody`, quando vem). A lista não sai para processo restrito
343
+ e não inclui documento que o motor classificaria como segredo de justiça; os
344
+ documentos inteiros estão em `instances`.
345
+
346
+ ```ts
347
+ for (const outra of meta.otherInstances ?? []) {
348
+ // Ex.: { grau: "G1", updatedAt: "2026-04-15T12:00:00.000Z" }
349
+ }
350
+ ```
351
+
352
+ **Continuação.** Na API nada é cortado: o retrato traz os movimentos guardados
353
+ de cada instância, e a lista de movimentações lê do acervo, grau a grau, sem ir
354
+ à fonte. No canal para agentes (MCP), `consultar_processo` cabe no teto de uma
355
+ resposta: de cada grau vêm os movimentos mais recentes, o grau que se moveu por
356
+ último primeiro, e a mesma tool com `grau` e `pagina` traz os seguintes do que o
357
+ motor guardou, por 1 crédito e sem ir à fonte — só para quem já leu o processo
358
+ ou o acompanha.
359
+
259
360
  ## Ler um processo quando a fonte está lenta
260
361
 
261
362
  A ficha (`processes.get`) vai à fonte processual quando o acervo não tem o
@@ -290,15 +391,15 @@ ou a vigília do processo (`watchProcess`), que consulta em segundo plano.
290
391
  responde com só parte do índice e o processo estava na parte que respondeu, ele
291
392
  é servido, e `meta.partialIndex` diz quantas partes falharam (`shardsFailed`),
292
393
  de quantas (`shardsTotal`, nulo quando a fonte não as contou) e se o prazo
293
- interno dela estourou (`timedOut`). O processo servido é o que a fonte tem, mas
294
- outra instância do mesmo número — outro grau — pode estar na parte que não
295
- respondeu. A resposta parcial que não serve o processo — sem ele, ou com uma
296
- instância diferente da que o acervo já guarda — é 502 `UPSTREAM_UNAVAILABLE`
394
+ interno dela estourou (`timedOut`). O documento que o acervo já guardava e não
395
+ veio sai em `instances` do acervo (`origin: "LAKE"`), com a data dele, e outro
396
+ grau que o acervo não conhece, se existir, pode estar na parte que não
397
+ respondeu. A resposta parcial sem o processo é 502 `UPSTREAM_UNAVAILABLE`
297
398
  retentável, nunca 404.
298
399
 
299
400
  ```ts
300
401
  if (meta.partialIndex) {
301
- // Outro grau deste número, se existir, pode não ter vindo.
402
+ // Outro grau deste número que o acervo não conhece pode não ter vindo.
302
403
  }
303
404
  ```
304
405
 
@@ -306,21 +407,6 @@ Antes de recusar a resposta parcial que veio sem o processo porque partes do
306
407
  índice ficaram fora, o motor consulta a fonte de novo — até duas vezes, com uma
307
408
  pausa curta, enquanto a espera couber.
308
409
 
309
- **`meta.otherInstances`: o número tem outro documento na fonte.** A fonte pode
310
- guardar mais de um documento por número — em geral um por instância (1º grau,
311
- 2º grau, turma recursal…), às vezes dois no mesmo grau —, e o motor serve e
312
- guarda um só: o de `data`, cujo grau está em `degree`. Quando a resposta da
313
- fonte trouxe outros, `meta.otherInstances` lista cada um com o grau (`grau`), a
314
- data em que a fonte o atualizou (`updatedAt`) e o órgão julgador (`courtBody`,
315
- quando vem). A lista não sai para processo restrito e não inclui documento que o
316
- motor classificaria como segredo de justiça.
317
-
318
- ```ts
319
- for (const outra of meta.otherInstances ?? []) {
320
- // Ex.: { grau: "G1", updatedAt: "2026-04-15T12:00:00.000Z" }
321
- }
322
- ```
323
-
324
410
  **Agentes têm a espera deles.** No canal para agentes (MCP), as tools
325
411
  `ler_processo` e `consultar_processo` escolhem a espera em `maxWaitSeconds`, na
326
412
  mesma faixa e com padrão de 120 s; esse canal não passa pelo SDK.
@@ -345,10 +431,13 @@ vez do erro. A resposta diz que é cópia, e de quando:
345
431
 
346
432
  A cópia custa 1 crédito, na ficha e no retrato. O retrato confere o saldo pelo
347
433
  preço cheio, 8, antes de ir à fonte; a ficha confere pelo preço do que
348
- entregou, depois da leitura. No retrato guardado, os movimentos são os da
349
- última vez que o motor buscou o processo, e `sourcePayload` é nulo: o que andou
350
- depois dessa data não está na resposta. Na ficha guardada, a data vale para os
351
- dados do processo, e o resumo das publicações (`djen`) é relido na hora.
434
+ entregou, depois da leitura. No retrato guardado, cada instância traz os
435
+ movimentos da última vez que o motor a buscou, com a data em
436
+ `instances[].fetchedAt`, e `sourcePayload` é nulo: o que andou depois dessas
437
+ datas não está na resposta. O número que a resposta completa mais recente da
438
+ fonte já não trazia em documento nenhum não é socorrido. Na ficha guardada, a
439
+ data vale para os dados do processo, e o resumo das publicações (`djen`) é
440
+ relido na hora.
352
441
 
353
442
  **Até que idade.** Sem pedir nada, só a cópia de até 24 h socorre a leitura —
354
443
  nessas duas rotas, uma resposta de sucesso já podia ser cópia do acervo dentro
@@ -387,6 +476,87 @@ ativa —, e os demais recebem a falha da fonte, como se não houvesse cópia.
387
476
  item socorrido traz `lakeRescue` com a causa e a data, e custa 1 crédito em vez
388
477
  de 8.
389
478
 
479
+ ## Leitura que não coube na espera
480
+
481
+ Quando a fonte processual não entrega dentro de `waitSeconds`, a ficha e o
482
+ retrato respondem com o erro dela (ou com a cópia guardada, seção anterior).
483
+ `processLookups.create` faz a MESMA leitura, e o que não coube na espera segue
484
+ em segundo plano em vez de virar erro:
485
+
486
+ - **200**: a leitura coube. `data` é uma consulta `SUCCEEDED` sem consulta
487
+ aberta (`lookupId` nulo) que traz o processo em `process` (visão
488
+ `PROCESS`) ou `snapshot` (visão `SNAPSHOT`), com as instâncias do número em
489
+ `instances`, o mesmo `meta` e o mesmo preço da leitura direta;
490
+ - **202**: a fonte falhou — não respondeu a tempo, ficou indisponível ou pediu
491
+ para esperar —, e o motor abriu uma consulta que tenta sozinha, até 60 s por
492
+ tentativa, por até 6 h (`giveUpAt`). Nada é cobrado na hora: o preço da
493
+ leitura fica retido em `creditsReserved`, o máximo que a entrega cobra, e
494
+ só é cobrado se o processo vier. Se não vier, a retenção volta;
495
+ - qualquer outra recusa é a da leitura direta: 404 quando a fonte diz não ter o
496
+ processo, 403 no segredo de justiça, 402 sem saldo.
497
+
498
+ `lookupProcess` diz, no tipo, qual dos dois desfechos aconteceu, e
499
+ `waitForProcessLookup` espera a consulta terminar:
500
+
501
+ ```ts
502
+ import { lookupProcess, waitForProcessLookup } from "@lexnode/legal-data-sdk";
503
+
504
+ const desfecho = await lookupProcess(lexnode, {
505
+ tribunalAlias: "api_publica_tjsp",
506
+ processNumber: numero,
507
+ view: "SNAPSHOT",
508
+ });
509
+
510
+ if (desfecho.kind === "ready") {
511
+ desfecho.data.movements; // o retrato, como processes.snapshot o devolveria
512
+ } else {
513
+ // O orçamento é explícito. A leitura seguinte só acontece na hora da
514
+ // próxima tentativa (nextAttemptAt): antes dela, o estado não muda. Com
515
+ // uma tentativa em curso, a consulta é lida de novo a cada 10 s.
516
+ const consulta = await waitForProcessLookup(
517
+ lexnode,
518
+ desfecho.lookup.lookupId!,
519
+ { budgetMs: 10 * 60_000 },
520
+ );
521
+ if (consulta.status === "SUCCEEDED" && consulta.snapshot) {
522
+ consulta.snapshot.movements;
523
+ }
524
+ }
525
+ ```
526
+
527
+ **Repetir é seguro.** A mesma leitura pedida de novo — mesma conta,
528
+ escritório, processo e visão — devolve a mesma consulta (`deduped: true`), sem
529
+ nova retenção; por isso `processLookups.create` entra na política de
530
+ retentativa como uma leitura. Quando a próxima tentativa agendada está longe, a
531
+ chamada repetida tenta a fonte na hora, dentro da espera dela. O tempo
532
+ esgotado da fonte continua sem repetição automática.
533
+
534
+ **A consulta se lê de graça, por 24 h.** `processLookups.get(lookupId)` custa 0
535
+ e, depois da entrega, traz o processo por 24 h (`resultExpiresAt`), relido do
536
+ acervo e passado de novo pelo controle de confidencialidade: o processo que
537
+ passou a segredo de justiça depois responde 403. O retrato lido da consulta
538
+ traz a instância principal no topo e cada instância com os movimentos da
539
+ última captura dela, e `sourcePayload` é nulo. `processLookups.list` e `processLookups.cancel`
540
+ completam a superfície; o cancelamento devolve a retenção e não gera evento.
541
+
542
+ **Por webhook, sem esperar nada.** O fim sai em `PROCESS_LOOKUP_COMPLETED`, um
543
+ ponteiro para a consulta que nunca traz o processo; o movimento novo que a
544
+ entrega trouxer chega no `PROCESS_MOVEMENT_CREATED` de sempre.
545
+
546
+ **A cópia guardada e a atualização, uma compra só.** Com `staleOnFailure: true`,
547
+ o 202 traz em `stale` a cópia que o acervo guarda, com a data e a causa, por 1
548
+ crédito, e a consulta segue buscando a versão atual. A entrega cobra só o resto
549
+ do preço (`alreadyCharged` diz quanto já foi): as duas juntas custam o mesmo que
550
+ a leitura direta, e a atualização que não vier não cobra mais nada.
551
+
552
+ **A leitura direta fecha a consulta.** A ficha ou o retrato do mesmo processo
553
+ lidos com sucesso por `processes.get` ou `processes.snapshot` fecham a consulta
554
+ aberta sem cobrar — a leitura já cobrou.
555
+
556
+ **Tetos.** Até 5 consultas abertas por chave e 20 por conta; além disso, a
557
+ falha da fonte volta como a leitura direta a daria. A chave de teste nunca abre
558
+ consulta.
559
+
390
560
  ## Frescor: o `total: 0` qualificado
391
561
 
392
562
  Um resultado vazio não distingue sozinho "não existe" de "a fonte ainda não
package/dist/client.d.ts CHANGED
@@ -12,8 +12,9 @@ export interface LexNodeClientOptions {
12
12
  officeId?: string;
13
13
  /**
14
14
  * Prazo de cada chamada, em ms. Padrão: 30 s. A ficha e o retrato de um
15
- * processo levam o maior entre este prazo e a espera pela fonte mais 15 s —
16
- * `waitSeconds`, ou o padrão de 20 s da API quando ele falta.
15
+ * processo, e a leitura que segue em segundo plano, levam o maior entre este
16
+ * prazo e a espera pela fonte mais 15 s — `waitSeconds`, ou o padrão de 20 s
17
+ * da API quando ele falta.
17
18
  */
18
19
  timeoutMs?: number;
19
20
  /** Transporte alternativo — o `fetch` global é o padrão. */
@@ -71,6 +72,19 @@ export declare function createLexNodeClient(options: LexNodeClientOptions): {
71
72
  list: (query?: Query<"/v1/subscriptions", "get">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/subscriptions", "get">>;
72
73
  delete: (body: Body<"/v1/subscriptions", "delete">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/subscriptions", "delete">>;
73
74
  };
75
+ processLookups: {
76
+ /**
77
+ * A leitura de UM processo que segue em segundo plano quando a fonte não
78
+ * entrega dentro de `waitSeconds`: 200 com o processo, ou 202 com a
79
+ * consulta aberta. Repetir é seguro — o motor devolve a consulta já
80
+ * aberta da mesma leitura em vez de abrir outra —, então a retentativa
81
+ * vale para ela como para uma leitura.
82
+ */
83
+ create: (body: Body<"/v1/processes/lookups", "post">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/processes/lookups", "post">>;
84
+ get: (lookupId: string, opts?: CallOptions) => Promise<LexNodeResult<"/v1/processes/lookups/{lookupId}", "get">>;
85
+ list: (query?: Query<"/v1/processes/lookups", "get">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/processes/lookups", "get">>;
86
+ cancel: (lookupId: string, opts?: CallOptions) => Promise<LexNodeResult<"/v1/processes/lookups/{lookupId}/cancel", "post">>;
87
+ };
74
88
  searchJobs: {
75
89
  get: (jobId: string, opts?: CallOptions) => Promise<LexNodeResult<"/v1/search-jobs/{jobId}", "get">>;
76
90
  list: (query?: Query<"/v1/search-jobs", "get">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/search-jobs", "get">>;
package/dist/client.js CHANGED
@@ -18,12 +18,14 @@ const REQUEST_ID_IDEMPOTENT_WRITES = new Set([
18
18
  "post /v1/publications/text-searches",
19
19
  ]);
20
20
  /**
21
- * As leituras de UM processo em que quem chama escolhe, em `waitSeconds`,
22
- * quanto o motor espera pela fonte processual.
21
+ * As chamadas em que quem chama escolhe, em `waitSeconds`, quanto o motor
22
+ * espera pela fonte processual, e onde a espera viaja: na consulta das duas
23
+ * leituras de UM processo, no corpo da leitura que segue em segundo plano.
23
24
  */
24
- const SOURCE_WAIT_ROUTES = new Set([
25
- "get /v1/processes/{processNumber}",
26
- "get /v1/processes/{processNumber}/snapshot",
25
+ const SOURCE_WAIT_ROUTES = new Map([
26
+ ["get /v1/processes/{processNumber}", "query"],
27
+ ["get /v1/processes/{processNumber}/snapshot", "query"],
28
+ ["post /v1/processes/lookups", "body"],
27
29
  ]);
28
30
  /**
29
31
  * A espera que o motor aplica a essas leituras quando a chamada não traz
@@ -117,10 +119,14 @@ function appendQuery(url, query) {
117
119
  * prazo cobre essa espera mais a margem e nunca fica abaixo do prazo do
118
120
  * cliente. Nas outras rotas, vale o prazo do cliente.
119
121
  */
120
- function defaultCallTimeoutMs(method, path, query, clientTimeoutMs) {
121
- if (!SOURCE_WAIT_ROUTES.has(`${method} ${path}`))
122
+ function defaultCallTimeoutMs(method, path, carriers, clientTimeoutMs) {
123
+ const carrier = SOURCE_WAIT_ROUTES.get(`${method} ${path}`);
124
+ if (!carrier)
122
125
  return clientTimeoutMs;
123
- const requested = Number(query?.waitSeconds);
126
+ const source = carriers[carrier];
127
+ const requested = Number(source && typeof source === "object"
128
+ ? source.waitSeconds
129
+ : undefined);
124
130
  const waitSeconds = Number.isFinite(requested) && requested > 0
125
131
  ? requested
126
132
  : SOURCE_WAIT_API_DEFAULT_SECONDS;
@@ -261,7 +267,7 @@ export function createLexNodeClient(options) {
261
267
  throw LexNodeError.invalidRequest("O corpo da chamada não é serializável em JSON.", error);
262
268
  }
263
269
  const timeoutMs = args.timeoutMs ??
264
- defaultCallTimeoutMs(String(method), String(path), bag.params?.query, defaultTimeoutMs);
270
+ defaultCallTimeoutMs(String(method), String(path), { query: bag.params?.query, body: bag.body }, defaultTimeoutMs);
265
271
  const link = linkAbort(timeoutMs, args.signal);
266
272
  let response;
267
273
  let raw;
@@ -423,6 +429,29 @@ export function createLexNodeClient(options) {
423
429
  list: (query, opts = {}) => request("/v1/subscriptions", "get", { params: { query }, ...opts }),
424
430
  delete: (body, opts = {}) => request("/v1/subscriptions", "delete", { body, ...opts }),
425
431
  },
432
+ processLookups: {
433
+ /**
434
+ * A leitura de UM processo que segue em segundo plano quando a fonte não
435
+ * entrega dentro de `waitSeconds`: 200 com o processo, ou 202 com a
436
+ * consulta aberta. Repetir é seguro — o motor devolve a consulta já
437
+ * aberta da mesma leitura em vez de abrir outra —, então a retentativa
438
+ * vale para ela como para uma leitura.
439
+ */
440
+ create: (body, opts = {}) => request("/v1/processes/lookups", "post", {
441
+ body,
442
+ idempotent: true,
443
+ ...opts,
444
+ }),
445
+ get: (lookupId, opts = {}) => request("/v1/processes/lookups/{lookupId}", "get", {
446
+ params: { path: { lookupId } },
447
+ ...opts,
448
+ }),
449
+ list: (query, opts = {}) => request("/v1/processes/lookups", "get", { params: { query }, ...opts }),
450
+ cancel: (lookupId, opts = {}) => request("/v1/processes/lookups/{lookupId}/cancel", "post", {
451
+ params: { path: { lookupId } },
452
+ ...opts,
453
+ }),
454
+ },
426
455
  searchJobs: {
427
456
  get: (jobId, opts = {}) => request("/v1/search-jobs/{jobId}", "get", {
428
457
  params: { path: { jobId } },
package/dist/errors.d.ts CHANGED
@@ -9,7 +9,7 @@ import type { RateLimitSnapshot } from "./types.js";
9
9
  * os dois por literal redigitado descobre o engano em produção. A lista é
10
10
  * fechada para o que se conhece e aberta para o que vier (ver `LexNodeError`).
11
11
  */
12
- export declare const LEXNODE_ERROR_CODES: readonly ["INVALID_MONITOR", "TRIBUNAL_NOT_SUPPORTED", "PERSONAL_DOCUMENT_QUERY_NOT_ALLOWED", "VALIDATION_ERROR", "UNAUTHORIZED", "QUOTA_EXCEEDED", "INSUFFICIENT_SCOPE", "LGPD_FORBIDDEN", "PLAN_FEATURE_NOT_INCLUDED", "SUB_TENANT_LIMIT_EXCEEDED", "SANDBOX_UPSTREAM_DISABLED", "MOVEMENTS_NOT_AVAILABLE", "PRECEDENT_NOT_FOUND", "PROCESS_NOT_FOUND", "RESOURCE_NOT_FOUND", "RESOURCE_CONFLICT", "QUERY_TOO_BROAD", "RATE_LIMITED", "UPSTREAM_RATE_LIMITED", "INTERNAL_ERROR", "UPSTREAM_UNAVAILABLE", "DATABASE_TIMEOUT", "DATABASE_UNAVAILABLE", "SYNC_ABANDONED", "UPSTREAM_TIMEOUT", "ACCOUNT_SUSPENDED", "ENTITLEMENT_EXPIRED", "PROJECT_DISABLED", "SUBSCRIPTION_INACTIVE", "MONITOR_ALREADY_EXISTS", "MONITOR_NOT_FOUND", "SEARCH_JOB_NOT_FOUND", "PUBLICATION_NOT_FOUND", "EVENT_NOT_FOUND", "TEXT_ALERT_NOT_FOUND", "TEXT_SEARCH_NOT_FOUND", "CLIENT_TIMEOUT", "CLIENT_NETWORK_ERROR", "CLIENT_INVALID_REQUEST", "CLIENT_MISSING_PATH_PARAM", "INVALID_RESPONSE", "SEARCH_JOB_BUDGET_EXCEEDED", "PAGINATION_LIMIT_REACHED"];
12
+ export declare const LEXNODE_ERROR_CODES: readonly ["INVALID_MONITOR", "TRIBUNAL_NOT_SUPPORTED", "PERSONAL_DOCUMENT_QUERY_NOT_ALLOWED", "VALIDATION_ERROR", "UNAUTHORIZED", "QUOTA_EXCEEDED", "INSUFFICIENT_SCOPE", "LGPD_FORBIDDEN", "PLAN_FEATURE_NOT_INCLUDED", "SUB_TENANT_LIMIT_EXCEEDED", "SANDBOX_UPSTREAM_DISABLED", "MOVEMENTS_NOT_AVAILABLE", "PRECEDENT_NOT_FOUND", "PROCESS_NOT_FOUND", "RESOURCE_NOT_FOUND", "RESOURCE_CONFLICT", "QUERY_TOO_BROAD", "RATE_LIMITED", "UPSTREAM_RATE_LIMITED", "INTERNAL_ERROR", "UPSTREAM_UNAVAILABLE", "DATABASE_TIMEOUT", "DATABASE_UNAVAILABLE", "SYNC_ABANDONED", "UPSTREAM_TIMEOUT", "ACCOUNT_SUSPENDED", "ENTITLEMENT_EXPIRED", "PROJECT_DISABLED", "SUBSCRIPTION_INACTIVE", "MONITOR_ALREADY_EXISTS", "MONITOR_NOT_FOUND", "SEARCH_JOB_NOT_FOUND", "PROCESS_LOOKUP_NOT_FOUND", "PUBLICATION_NOT_FOUND", "EVENT_NOT_FOUND", "TEXT_ALERT_NOT_FOUND", "TEXT_SEARCH_NOT_FOUND", "CLIENT_TIMEOUT", "CLIENT_NETWORK_ERROR", "CLIENT_INVALID_REQUEST", "CLIENT_MISSING_PATH_PARAM", "INVALID_RESPONSE", "SEARCH_JOB_BUDGET_EXCEEDED", "PROCESS_LOOKUP_BUDGET_EXCEEDED", "PAGINATION_LIMIT_REACHED"];
13
13
  /**
14
14
  * Um código conhecido — ou qualquer outro.
15
15
  *
package/dist/errors.js CHANGED
@@ -43,6 +43,7 @@ export const LEXNODE_ERROR_CODES = [
43
43
  "MONITOR_ALREADY_EXISTS",
44
44
  "MONITOR_NOT_FOUND",
45
45
  "SEARCH_JOB_NOT_FOUND",
46
+ "PROCESS_LOOKUP_NOT_FOUND",
46
47
  "PUBLICATION_NOT_FOUND",
47
48
  "EVENT_NOT_FOUND",
48
49
  "TEXT_ALERT_NOT_FOUND",
@@ -54,6 +55,7 @@ export const LEXNODE_ERROR_CODES = [
54
55
  "CLIENT_MISSING_PATH_PARAM",
55
56
  "INVALID_RESPONSE",
56
57
  "SEARCH_JOB_BUDGET_EXCEEDED",
58
+ "PROCESS_LOOKUP_BUDGET_EXCEEDED",
57
59
  "PAGINATION_LIMIT_REACHED",
58
60
  ];
59
61
  const RAW_MESSAGE_MAX_CHARS = 500;
package/dist/index.d.ts CHANGED
@@ -15,9 +15,11 @@ export { LEXNODE_ERROR_CODES, LexNodeError, isLexNodeError } from "./errors.js";
15
15
  export type { LexNodeErrorClass, LexNodeErrorCode, LexNodeErrorInit, } from "./errors.js";
16
16
  export type { Body, CallOptions, Data, HttpMethod, LexNodeResult, Meta, MetaExtras, MethodOf, Operation, PathParams, Query, RateLimitSnapshot, RequestArgs, RetryPolicy, } from "./types.js";
17
17
  export { DEFAULT_WEBHOOK_TOLERANCE_SECONDS, LEXNODE_WEBHOOK_HEADERS, WEBHOOK_EVENT_TYPES, WEBHOOK_TEST_EVENT_TYPE, isKnownWebhookEventType, isReceiverFault, isWebhookTest, parseWebhookEvent, verifyWebhookSignature, webhookRejectionStatus, } from "./webhooks.js";
18
- export type { MonitorSyncFailedPayload, MonitorSyncSucceededPayload, PeriodEndingPayload, ProcessMovementCreatedPayload, ProcessSourceIndex, PublicationCreatedPayload, PublicationHarvestCompletedPayload, PublicationTextAlertMatch, PublicationTextAlertMatchedPayload, QuotaLowPayload, SubscribableWebhookEventType, SearchJobFailedPayload, SearchJobSucceededPayload, SubscriptionPastDuePayload, SuspensionSignal, UnknownWebhookEvent, VerifyWebhookOptions, WebhookEvent, WebhookEventEnvelope, WebhookEventType, WebhookHeaders, WebhookParseRejection, WebhookParseResult, WebhookRawBody, WebhookRejection, WebhookTestPayload, WebhookVerification, } from "./webhooks.js";
18
+ export type { MonitorSyncFailedPayload, MonitorSyncInstance, MonitorSyncSucceededPayload, PeriodEndingPayload, ProcessInstanceDiscoveredPayload, ProcessInstanceDiscoveredWithheldPayload, ProcessLookupFailedPayload, ProcessLookupSucceededPayload, ProcessMovementCreatedPayload, ProcessMovementInstanceCount, ProcessSourceIndex, PublicationCreatedPayload, PublicationHarvestCompletedPayload, PublicationTextAlertMatch, PublicationTextAlertMatchedPayload, QuotaLowPayload, SubscribableWebhookEventType, SearchJobFailedPayload, SearchJobSucceededPayload, SubscriptionPastDuePayload, SuspensionSignal, UnknownWebhookEvent, VerifyWebhookOptions, WebhookEvent, WebhookEventEnvelope, WebhookEventType, WebhookHeaders, WebhookParseRejection, WebhookParseResult, WebhookRawBody, WebhookRejection, WebhookTestPayload, WebhookVerification, } from "./webhooks.js";
19
19
  export { paginate } from "./paginate.js";
20
20
  export type { PaginateOptions } from "./paginate.js";
21
+ export { lookupProcess, waitForProcessLookup } from "./lookup.js";
22
+ export type { ProcessLookup, ProcessLookupInput, ProcessLookupOutcome, ProcessLookupRead, ProcessLookupState, ProcessLookupView, StaleProcessCopy, WaitForProcessLookupOptions, } from "./lookup.js";
21
23
  export { searchProcesses, waitForSearchJob } from "./search.js";
22
24
  export type { ProcessSearchOutcome, ProcessSearchResult, QueuedSearchJob, SearchJob, SearchJobState, WaitForSearchJobOptions, } from "./search.js";
23
25
  export { describeFreshness, freshnessOf, isNotYetIndexed, lakeRescueOf, readThrough, sourceFetchedAtOf, } from "./freshness.js";
package/dist/index.js CHANGED
@@ -12,6 +12,7 @@ export { createLexNodeClient } from "./client.js";
12
12
  export { LEXNODE_ERROR_CODES, LexNodeError, isLexNodeError } from "./errors.js";
13
13
  export { DEFAULT_WEBHOOK_TOLERANCE_SECONDS, LEXNODE_WEBHOOK_HEADERS, WEBHOOK_EVENT_TYPES, WEBHOOK_TEST_EVENT_TYPE, isKnownWebhookEventType, isReceiverFault, isWebhookTest, parseWebhookEvent, verifyWebhookSignature, webhookRejectionStatus, } from "./webhooks.js";
14
14
  export { paginate } from "./paginate.js";
15
+ export { lookupProcess, waitForProcessLookup } from "./lookup.js";
15
16
  export { searchProcesses, waitForSearchJob } from "./search.js";
16
17
  export { describeFreshness, freshnessOf, isNotYetIndexed, lakeRescueOf, readThrough, sourceFetchedAtOf, } from "./freshness.js";
17
18
  export { isFirstAppearance, resubscribeOnFirstAppearance, unwatchProcess, watchProcess, } from "./watch.js";
@@ -0,0 +1,79 @@
1
+ import type { LexNodeClient } from "./client.js";
2
+ import type { Body, CallOptions, Data, Meta, MetaExtras } from "./types.js";
3
+ /**
4
+ * A leitura de UM processo que segue em segundo plano responde de dois jeitos
5
+ * na MESMA operação: 200 com o processo, quando ele coube na espera, ou 202
6
+ * com a consulta que segue tentando a fonte sozinha. O discriminador é o
7
+ * código HTTP, como na busca: a consulta aberta também tem `status`, mas quem
8
+ * afirma o desfecho da chamada é o 200 ou o 202.
9
+ */
10
+ type CreateData = Data<"/v1/processes/lookups", "post">;
11
+ type CreateMeta = Meta<"/v1/processes/lookups", "post"> & MetaExtras;
12
+ /** A consulta como a leitura dela a devolve. */
13
+ export type ProcessLookup = Data<"/v1/processes/lookups/{lookupId}", "get">;
14
+ export type ProcessLookupState = ProcessLookup["status"];
15
+ export type ProcessLookupView = ProcessLookup["view"];
16
+ /** O que se pede: tribunal, número, visão, espera e a cópia na falha. */
17
+ export type ProcessLookupInput = Body<"/v1/processes/lookups", "post">;
18
+ /** A cópia guardada que o 202 entrega enquanto a consulta segue. */
19
+ export type StaleProcessCopy = NonNullable<CreateData["stale"]>;
20
+ /** O processo entregue na visão pedida: a ficha ou o retrato. */
21
+ export type ProcessLookupRead<V extends ProcessLookupView> = V extends "SNAPSHOT" ? NonNullable<CreateData["snapshot"]> : NonNullable<CreateData["process"]>;
22
+ export type ProcessLookupOutcome<V extends ProcessLookupView = ProcessLookupView> = {
23
+ kind: "ready";
24
+ /** A ficha ou o retrato, como a leitura direta os devolveria. */
25
+ data: ProcessLookupRead<V>;
26
+ lookup: CreateData;
27
+ meta: CreateMeta;
28
+ } | {
29
+ kind: "pending";
30
+ /** A consulta aberta, a ser acompanhada por `waitForProcessLookup`. */
31
+ lookup: CreateData;
32
+ /** A cópia guardada, com a data, quando pedida em `staleOnFailure`. */
33
+ stale: StaleProcessCopy | null;
34
+ meta: CreateMeta;
35
+ };
36
+ /**
37
+ * Lê um processo e diz, no tipo, qual dos dois desfechos aconteceu.
38
+ *
39
+ * Sem isto, o consumidor lê `data.process` num corpo que é uma consulta
40
+ * aberta e chama de "sem dados" o que é "ainda estou buscando". A mesma
41
+ * leitura pedida de novo devolve a mesma consulta — repetir é seguro, e o
42
+ * cliente repete sozinho quando a política de retentativa estiver ligada.
43
+ */
44
+ export declare function lookupProcess<V extends ProcessLookupView>(client: LexNodeClient, input: ProcessLookupInput & {
45
+ view: V;
46
+ }, opts?: CallOptions): Promise<ProcessLookupOutcome<V>>;
47
+ export interface WaitForProcessLookupOptions {
48
+ /**
49
+ * Teto de espera total, em ms, incluindo as leituras e suas retentativas.
50
+ * EXPLÍCITO de propósito, como na busca: a consulta
51
+ * tenta por horas, e um laço sem orçamento gasta a requisição inteira de um
52
+ * ambiente serverless esperando uma fonte fora do ar.
53
+ */
54
+ budgetMs?: number;
55
+ signal?: AbortSignal;
56
+ /** Chamado a cada leitura da consulta, para a UI acompanhar. */
57
+ onState?: (state: ProcessLookupState, lookup: ProcessLookup) => void;
58
+ officeId?: string | null;
59
+ }
60
+ /**
61
+ * Espera a consulta terminar, dentro do orçamento.
62
+ *
63
+ * Lê a consulta de novo só quando há o que mudar: na hora da próxima tentativa
64
+ * (`nextAttemptAt`) — antes dela, a leitura devolve o mesmo estado —, a cada
65
+ * 10 s enquanto uma tentativa está em curso ou espera a vez na fila, e depois
66
+ * do `Retry-After` quando a própria leitura é recusada por vazão. Leitura não
67
+ * cobra, mas conta no teto por minuto da chave.
68
+ *
69
+ * O estouro do orçamento é um erro PRÓPRIO e retentável
70
+ * (`PROCESS_LOOKUP_BUDGET_EXCEEDED`): a consulta continua no motor, e quem
71
+ * espera pode voltar a lê-la depois — `details.nextReadAt` diz quando vale a
72
+ * pena — ou receber o `PROCESS_LOOKUP_COMPLETED` por webhook e não esperar
73
+ * nada. Quando a próxima leitura útil cai depois do orçamento, o erro sai na
74
+ * hora: esperar até o fim dele não mudaria nada. Devolve a consulta
75
+ * terminada: `SUCCEEDED`, com o processo enquanto o resultado vale; `FAILED`,
76
+ * com `error`; ou `CANCELED`.
77
+ */
78
+ export declare function waitForProcessLookup(client: LexNodeClient, lookupId: string, options?: WaitForProcessLookupOptions): Promise<ProcessLookup>;
79
+ export {};