@lexnode/legal-data-sdk 1.30.0 → 1.32.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 +223 -191
- package/dist/client.d.ts +217 -24
- package/dist/client.js +6 -103
- package/dist/errors.d.ts +86 -41
- package/dist/errors.js +1 -49
- package/dist/freshness.d.ts +88 -41
- package/dist/freshness.js +0 -47
- package/dist/index.d.ts +10 -6
- package/dist/index.js +0 -10
- package/dist/lookup.d.ts +105 -39
- package/dist/lookup.js +0 -40
- package/dist/paginate.d.ts +15 -5
- package/dist/paginate.js +0 -30
- package/dist/search.d.ts +57 -23
- package/dist/search.js +0 -17
- package/dist/types.d.ts +77 -68
- package/dist/watch.d.ts +78 -43
- package/dist/watch.js +0 -35
- package/dist/webhooks.d.ts +184 -93
- package/dist/webhooks.js +0 -65
- package/package.json +7 -4
- package/schema.d.ts +611 -521
package/README.md
CHANGED
|
@@ -5,20 +5,20 @@ processos e movimentações, publicações dos diários oficiais, jurisprudênci
|
|
|
5
5
|
monitores e webhooks.
|
|
6
6
|
|
|
7
7
|
O pacote traz **os tipos gerados do contrato OpenAPI** e um **cliente de
|
|
8
|
-
runtime** construído sobre eles:
|
|
8
|
+
runtime** construído sobre eles: chamadas com os cabeçalhos certos, erros
|
|
9
9
|
classificados, verificação de assinatura de webhook, espera de busca
|
|
10
|
-
assíncrona, leitura do
|
|
10
|
+
assíncrona, leitura do frescor da fonte e a vigília de um processo para vários
|
|
11
11
|
interessados.
|
|
12
12
|
|
|
13
13
|
- **Sem dependências de runtime.** `fetch` global e `node:crypto`.
|
|
14
14
|
- **Node >= 20**, ESM.
|
|
15
15
|
|
|
16
|
-
> ⚠️ **
|
|
17
|
-
> no browser ela
|
|
18
|
-
>
|
|
19
|
-
>
|
|
20
|
-
> backend
|
|
21
|
-
>
|
|
16
|
+
> ⚠️ **Só no servidor, e só por TLS.** A credencial é uma chave de **conta**:
|
|
17
|
+
> no browser ela fica exposta, e em `http://` qualquer um no caminho a lê —
|
|
18
|
+
> uma `baseUrl` sem https é recusada no construtor (exceto no host local, para
|
|
19
|
+
> desenvolvimento). Um app com usuários finais chama o próprio backend, e o
|
|
20
|
+
> backend chama a API, atribuindo cada chamada ao sub-tenant dela (um
|
|
21
|
+
> escritório, um usuário final) pelo cabeçalho `X-Office-Id`.
|
|
22
22
|
|
|
23
23
|
## Instalação
|
|
24
24
|
|
|
@@ -34,33 +34,33 @@ import { createLexNodeClient } from "@lexnode/legal-data-sdk";
|
|
|
34
34
|
const lexnode = createLexNodeClient({
|
|
35
35
|
baseUrl: "https://api.lexnode.com.br",
|
|
36
36
|
apiKey: process.env.LEXNODE_API_KEY!,
|
|
37
|
-
//
|
|
37
|
+
// Escritório padrão; cada chamada pode trocá-lo.
|
|
38
38
|
officeId: "escritorio-01",
|
|
39
39
|
timeoutMs: 30_000,
|
|
40
40
|
userAgent: "meu-app/1.0",
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
const { data, meta } = await lexnode.processes.get("00012345620268260100", {
|
|
44
|
-
tribunalAlias: "
|
|
44
|
+
tribunalAlias: "TJSP",
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
console.log(data.formattedNumber, meta.credits, meta.rateLimit?.remaining);
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
Toda chamada
|
|
51
|
-
quando
|
|
52
|
-
|
|
53
|
-
é o do contrato mais `status` (o código HTTP) e `rateLimit` (os
|
|
54
|
-
`RateLimit-*`, lidos **
|
|
50
|
+
Toda chamada envia `Authorization: Bearer`, `X-Request-Id`, `X-Trace-Id` e,
|
|
51
|
+
quando houver, `X-Office-Id`; respeita o prazo **e** o `signal` que você
|
|
52
|
+
passar, o que vier primeiro; e devolve `{ data, meta }` tipados pela rota. O
|
|
53
|
+
`meta` é o do contrato mais `status` (o código HTTP) e `rateLimit` (os
|
|
54
|
+
cabeçalhos `RateLimit-*`, lidos **também no sucesso**, e o `Retry-After` da
|
|
55
|
+
recusa).
|
|
55
56
|
|
|
56
|
-
Em `rateLimit`, use `remaining` para desacelerar
|
|
57
|
-
cabeçalho `RateLimit-Reset
|
|
58
|
-
|
|
57
|
+
Em `rateLimit`, use `remaining` para desacelerar. `resetSeconds` repete o
|
|
58
|
+
cabeçalho `RateLimit-Reset`, que tem dois sentidos: na recusa, os segundos até
|
|
59
|
+
a janela reabrir; no sucesso, a duração da janela (60 s).
|
|
59
60
|
|
|
60
61
|
O pacote **não valida a resposta em tempo de execução**: `data` e `meta` chegam
|
|
61
|
-
tipados pelo contrato
|
|
62
|
-
|
|
63
|
-
dado alimenta um banco, por exemplo — valida o que consome.
|
|
62
|
+
tipados pelo contrato da versão instalada. Se o dado alimenta um banco, por
|
|
63
|
+
exemplo, valide o que consumir.
|
|
64
64
|
|
|
65
65
|
### Métodos nomeados e a chamada genérica
|
|
66
66
|
|
|
@@ -80,8 +80,8 @@ await lexnode.webhooks.unsubscribedEventTypes();
|
|
|
80
80
|
await lexnode.usage.get();
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
Qualquer rota do contrato
|
|
84
|
-
|
|
83
|
+
Qualquer rota do contrato, inclusive as que não têm método nomeado, sai pela
|
|
84
|
+
chamada genérica, tipada por `paths`:
|
|
85
85
|
|
|
86
86
|
```ts
|
|
87
87
|
const { data } = await lexnode.request("/v1/precedents", "get", {
|
|
@@ -89,11 +89,37 @@ const { data } = await lexnode.request("/v1/precedents", "get", {
|
|
|
89
89
|
});
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
+
Para consultar também os atos datados do calendário forense:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
const { data: calendar } = await lexnode.request("/v1/court-calendar", "get", {
|
|
96
|
+
params: {
|
|
97
|
+
query: {
|
|
98
|
+
court: "TJSP",
|
|
99
|
+
municipalityIbgeCode: 3509502,
|
|
100
|
+
from: "2026-06-01",
|
|
101
|
+
to: "2026-06-30",
|
|
102
|
+
includeCatalog: true,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
for (const reference of calendar.catalog?.references ?? []) {
|
|
108
|
+
console.log(reference.date, reference.provenance.url);
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`catalog.references` exige conferir o ato e sua aplicação ao caso antes de excluir
|
|
113
|
+
dias da contagem. Todos os itens são `REFERENCE_ONLY`; os provisórios identificam
|
|
114
|
+
a fonte secundária. Não os some automaticamente a `entries`. A situação declarada
|
|
115
|
+
é a da coleta em `sourceAsOf`, e a cobertura parcial ou desconhecida não prova
|
|
116
|
+
ausência de feriados nas outras datas. Sem `includeCatalog`, esse bloco não vem.
|
|
117
|
+
|
|
92
118
|
### Páginas
|
|
93
119
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
120
|
+
A API pagina de três jeitos: cursor no `meta`, cursor no `data`, e página e
|
|
121
|
+
tamanho ou deslocamento e limite. `paginate` percorre qualquer um deles, até
|
|
122
|
+
`maxPages` páginas (padrão 100) — cada página é uma chamada:
|
|
97
123
|
|
|
98
124
|
```ts
|
|
99
125
|
import { paginate } from "@lexnode/legal-data-sdk";
|
|
@@ -116,7 +142,7 @@ try {
|
|
|
116
142
|
error.class; // "RETRYABLE" | "TERMINAL"
|
|
117
143
|
error.retryable;
|
|
118
144
|
error.status;
|
|
119
|
-
error.upstreamStatus; // o status
|
|
145
|
+
error.upstreamStatus; // o status que a fonte respondeu, quando informado
|
|
120
146
|
error.requestId; // o que o suporte pede
|
|
121
147
|
error.fieldErrors; // recusa de validação, por campo
|
|
122
148
|
error.retryAfterSeconds;
|
|
@@ -126,17 +152,17 @@ try {
|
|
|
126
152
|
```
|
|
127
153
|
|
|
128
154
|
Prazo esgotado vira `CLIENT_TIMEOUT` (504, retentável); falha de rede vira
|
|
129
|
-
`CLIENT_NETWORK_ERROR` (502, retentável); resposta fora do
|
|
130
|
-
`INVALID_RESPONSE` (502) com o
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
155
|
+
`CLIENT_NETWORK_ERROR` (502, retentável); resposta fora do formato da API vira
|
|
156
|
+
`INVALID_RESPONSE` (502), com o início do corpo na mensagem; e o pedido que não
|
|
157
|
+
se monta — cabeçalho com quebra de linha, corpo que não vira JSON — vira
|
|
158
|
+
`CLIENT_INVALID_REQUEST` (400, **não** retentável), porque não chegou a ser
|
|
159
|
+
enviado.
|
|
134
160
|
|
|
135
161
|
`LEXNODE_ERROR_CODES` traz o catálogo para o `switch`, e `LexNodeErrorCode`
|
|
136
|
-
mantém o autocompletar
|
|
137
|
-
|
|
138
|
-
existe na fonte) quanto para `MOVEMENTS_NOT_AVAILABLE` (existe, mas as
|
|
139
|
-
movimentações não
|
|
162
|
+
mantém o autocompletar e aceita um código novo da API. Na leitura de processo
|
|
163
|
+
isso importa: a API responde 404 tanto para `PROCESS_NOT_FOUND` (o processo não
|
|
164
|
+
existe na fonte) quanto para `MOVEMENTS_NOT_AVAILABLE` (ele existe, mas as
|
|
165
|
+
movimentações não vieram) — trate os dois pelo `code`.
|
|
140
166
|
|
|
141
167
|
### Retentativa (opcional, desligada por padrão)
|
|
142
168
|
|
|
@@ -148,19 +174,22 @@ const lexnode = createLexNodeClient({
|
|
|
148
174
|
});
|
|
149
175
|
```
|
|
150
176
|
|
|
151
|
-
Repete só o que é `RETRYABLE`, respeitando `Retry-After
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
declara
|
|
177
|
+
Repete só o que é `RETRYABLE`, respeitando `Retry-After`: quando a recusa pede
|
|
178
|
+
uma espera maior que `maxDelayMs` (8 s por padrão), como a da manutenção
|
|
179
|
+
declarada pela fonte, ela é lançada sem repetição, e `retryAfterSeconds` diz
|
|
180
|
+
quando vale tentar de novo. `GET` e `DELETE` são repetidos por definição do
|
|
181
|
+
HTTP. Uma **escrita** só é repetida quando o contrato declara a repetição
|
|
182
|
+
segura — hoje `POST /v1/publications/text-searches`, que usa o `requestId` que
|
|
183
|
+
você fixar como chave de reenvio — ou quando você mesmo o declara na chamada:
|
|
156
184
|
|
|
157
185
|
```ts
|
|
158
186
|
await lexnode.webhooks.endpoints.create(corpo, { idempotent: true });
|
|
159
187
|
```
|
|
160
188
|
|
|
161
|
-
A
|
|
162
|
-
endpoints para a mesma URL entregam cada evento em dobro, e o segredo do
|
|
163
|
-
primeiro
|
|
189
|
+
A declaração é sua: sem ela, um `POST` repetido cria um **segundo** recurso —
|
|
190
|
+
dois endpoints para a mesma URL entregam cada evento em dobro, e o segredo do
|
|
191
|
+
primeiro se perde. Nas outras rotas, o `requestId` só serve para rastrear a
|
|
192
|
+
chamada.
|
|
164
193
|
|
|
165
194
|
A exceção é o `UPSTREAM_TIMEOUT` da leitura de um processo, que a política não
|
|
166
195
|
repete — ver [a seção da fonte lenta](#ler-um-processo-quando-a-fonte-está-lenta).
|
|
@@ -173,15 +202,16 @@ import {
|
|
|
173
202
|
webhookRejectionStatus,
|
|
174
203
|
} from "@lexnode/legal-data-sdk";
|
|
175
204
|
|
|
176
|
-
// O corpo
|
|
205
|
+
// O corpo como chegou, nunca um JSON serializado de novo: a assinatura vale
|
|
206
|
+
// para os bytes.
|
|
177
207
|
const resultado = parseWebhookEvent(
|
|
178
208
|
rawBody,
|
|
179
209
|
request.headers,
|
|
180
210
|
process.env.LEXNODE_WEBHOOK_SIGNING_SECRET!,
|
|
181
211
|
);
|
|
182
212
|
|
|
183
|
-
//
|
|
184
|
-
//
|
|
213
|
+
// Cada recusa tem o seu status: a assinatura que não confere é 401; o segredo
|
|
214
|
+
// ausente no seu receptor é 503.
|
|
185
215
|
if (!resultado.ok) {
|
|
186
216
|
return reply.status(webhookRejectionStatus(resultado.reason)).send();
|
|
187
217
|
}
|
|
@@ -210,22 +240,22 @@ switch (resultado.event.type) {
|
|
|
210
240
|
}
|
|
211
241
|
break;
|
|
212
242
|
case "PROCESS_LOOKUP_COMPLETED":
|
|
213
|
-
//
|
|
243
|
+
// Aponta a consulta: o processo se lê em payload.pollUrl, sem nova cobrança.
|
|
214
244
|
resultado.event.payload.lookupId;
|
|
215
245
|
break;
|
|
216
246
|
case "WEBHOOK_TEST":
|
|
217
|
-
// A entrega de teste
|
|
218
|
-
//
|
|
247
|
+
// A entrega de teste (`webhooks.endpoints.test` ou o portal). Chega a
|
|
248
|
+
// qualquer endpoint sem constar de `eventTypes`; use-a para validar o
|
|
249
|
+
// receptor antes do primeiro evento.
|
|
219
250
|
break;
|
|
220
251
|
default:
|
|
221
252
|
break;
|
|
222
253
|
}
|
|
223
254
|
```
|
|
224
255
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
deduplicação e todas as seguintes parecerem repetição dela.
|
|
256
|
+
Entrega sem `id` ou sem `occurredAt` é recusada como `INVALID_ENVELOPE`. A
|
|
257
|
+
mesma entrega pode chegar mais de uma vez: use o `id` para descartar a
|
|
258
|
+
repetida.
|
|
229
259
|
|
|
230
260
|
`WEBHOOK_EVENT_TYPES` é o catálogo **assinável** (o que entra em `eventTypes`
|
|
231
261
|
ao cadastrar um endpoint) e não inclui `WEBHOOK_TEST`, que chega sem ser
|
|
@@ -234,22 +264,20 @@ pedido — use `isWebhookTest(event)` para separá-lo.
|
|
|
234
264
|
`verifyWebhookSignature(rawBody, headers, secret)` faz só a conferência e
|
|
235
265
|
devolve o motivo da recusa (`MISSING_SIGNATURE`, `MALFORMED_SIGNATURE`,
|
|
236
266
|
`TIMESTAMP_MISMATCH`, `TIMESTAMP_OUT_OF_TOLERANCE`, `SIGNATURE_MISMATCH`,
|
|
237
|
-
`RAW_BODY_REQUIRED`),
|
|
238
|
-
diferentes virarem a mesma resposta.
|
|
267
|
+
`RAW_BODY_REQUIRED`), para você tratar cada caso.
|
|
239
268
|
|
|
240
|
-
O corpo entra como `string` ou `Buffer
|
|
241
|
-
|
|
242
|
-
|
|
269
|
+
O corpo entra como `string` ou `Buffer`, como chegou. Um objeto já convertido
|
|
270
|
+
de JSON é recusado como `RAW_BODY_REQUIRED`: serializar de novo muda a ordem
|
|
271
|
+
das chaves, e a assinatura deixa de conferir.
|
|
243
272
|
|
|
244
|
-
A
|
|
245
|
-
cabeçalho `x-lexnode-timestamp`
|
|
246
|
-
|
|
247
|
-
ausência dele um motivo de recusa, porque ela não prova nada.
|
|
273
|
+
A tolerância do instante e o digest usam o `t` que vem **dentro** da
|
|
274
|
+
assinatura. O cabeçalho `x-lexnode-timestamp` repete esse valor: quando vem,
|
|
275
|
+
precisa ser igual; quando falta, não é motivo de recusa.
|
|
248
276
|
|
|
249
277
|
## Busca síncrona ou assíncrona
|
|
250
278
|
|
|
251
279
|
`POST /v1/processes/search` responde **200** com o resultado pronto ou **202**
|
|
252
|
-
com
|
|
280
|
+
com uma busca enfileirada. O SDK diz qual foi, no tipo:
|
|
253
281
|
|
|
254
282
|
```ts
|
|
255
283
|
import { searchProcesses, waitForSearchJob } from "@lexnode/legal-data-sdk";
|
|
@@ -259,9 +287,8 @@ const desfecho = await searchProcesses(lexnode, { tribunalAlias, number });
|
|
|
259
287
|
if (desfecho.kind === "sync") {
|
|
260
288
|
desfecho.result.items;
|
|
261
289
|
} else {
|
|
262
|
-
//
|
|
263
|
-
//
|
|
264
|
-
// SEARCH_JOB_COMPLETED.
|
|
290
|
+
// Espere com orçamento — num ambiente serverless, dentro do prazo da
|
|
291
|
+
// função — ou receba o SEARCH_JOB_COMPLETED por webhook.
|
|
265
292
|
const job = await waitForSearchJob(lexnode, desfecho.job.jobId, {
|
|
266
293
|
budgetMs: 20_000,
|
|
267
294
|
});
|
|
@@ -272,30 +299,30 @@ if (desfecho.kind === "sync") {
|
|
|
272
299
|
## Um número, várias instâncias
|
|
273
300
|
|
|
274
301
|
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
|
|
276
|
-
na sua instância.
|
|
302
|
+
grau, turma recursal… —, às vezes dois do mesmo grau, e o LexNode guarda cada
|
|
303
|
+
um na sua instância.
|
|
277
304
|
|
|
278
305
|
**O topo não troca.** O topo da ficha (`data`) e do retrato (`data.process` e
|
|
279
306
|
`data.movements`) é sempre a instância principal do número, com o grau em
|
|
280
307
|
`degree`: a mesma de uma leitura para a outra, qualquer que seja a ordem em que
|
|
281
308
|
a fonte devolve os documentos. Ela só muda quando uma resposta completa da
|
|
282
|
-
fonte pelo número deixa de trazê-la.
|
|
283
|
-
|
|
309
|
+
fonte pelo número deixa de trazê-la. Se você compara movimentos pela chave, o
|
|
310
|
+
histórico de outro grau não aparece como novo no topo — e o topo pode não ser o
|
|
284
311
|
grau que anda: o 2º grau guardado primeiro continua no topo enquanto o 1º se
|
|
285
312
|
move.
|
|
286
313
|
|
|
287
314
|
**Todos os graus em `instances`.** A ficha e o retrato listam em `instances`
|
|
288
|
-
todos os documentos
|
|
315
|
+
todos os documentos guardados do número, a principal primeiro
|
|
289
316
|
(`primary: true`). Cada um diz de onde veio nesta resposta (`origin`: `SOURCE`
|
|
290
|
-
quando a fonte o trouxe, `LAKE` quando
|
|
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
|
|
293
|
-
dela, do mais recente ao mais antigo e sem o payload bruto da fonte; a
|
|
294
|
-
|
|
295
|
-
com lista vazia, que diria
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
lista.
|
|
317
|
+
quando a fonte o trouxe, `LAKE` quando veio da cópia guardada), quando foi
|
|
318
|
+
buscado (`fetchedAt`) e desde quando a resposta completa da fonte vem sem ele
|
|
319
|
+
(`absentSince`). No retrato, cada instância traz os movimentos da última
|
|
320
|
+
captura dela, do mais recente ao mais antigo e sem o payload bruto da fonte; a
|
|
321
|
+
instância cujos movimentos nunca foram capturados vem com
|
|
322
|
+
`movementsCaptured: false` e `movements` nulo, nunca com lista vazia, que diria
|
|
323
|
+
que o grau não andou. Todos os documentos levam a classificação do número
|
|
324
|
+
inteiro — basta um em segredo de justiça para todos saírem marcados —, e a
|
|
325
|
+
ficha retida pelo controle de confidencialidade sai sem a lista.
|
|
299
326
|
|
|
300
327
|
```ts
|
|
301
328
|
const { data } = await lexnode.processes.snapshot(numero, { tribunalAlias });
|
|
@@ -309,9 +336,9 @@ for (const instancia of data.instances) {
|
|
|
309
336
|
|
|
310
337
|
No lote (`processes.snapshotBatch`), `instances` traz só o cabeçalho de cada
|
|
311
338
|
documento; os movimentos de cada instância vêm no retrato de um processo. A
|
|
312
|
-
busca por número completo
|
|
313
|
-
fonte ainda traz do número, a principal primeiro; quando eles
|
|
314
|
-
`limit`, a busca vai à fonte, que pagina.
|
|
339
|
+
busca por número completo respondida com os dados guardados devolve um item por
|
|
340
|
+
documento que a fonte ainda traz do número, a principal primeiro; quando eles
|
|
341
|
+
não cabem em `limit`, a busca vai à fonte, que pagina.
|
|
315
342
|
|
|
316
343
|
**Recorte por grau.** A lista de movimentações aceita `degree` e devolve só os
|
|
317
344
|
movimentos que o documento daquele grau trouxe na última captura; cada item diz
|
|
@@ -327,21 +354,21 @@ data.items; // só o que o 1º grau trouxe
|
|
|
327
354
|
```
|
|
328
355
|
|
|
329
356
|
**O grau novo chega num evento só.** Quando outro grau de um processo assinado
|
|
330
|
-
aparece na fonte, o histórico dele
|
|
331
|
-
`PROCESS_MOVEMENT_CREATED
|
|
332
|
-
|
|
333
|
-
`
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
357
|
+
aparece na fonte, o histórico dele não sai movimento a movimento em
|
|
358
|
+
`PROCESS_MOVEMENT_CREATED`: chega um `PROCESS_INSTANCE_DISCOVERED`, com o grau,
|
|
359
|
+
o órgão julgador e as contagens — `historyMovementCount` não saiu em aviso
|
|
360
|
+
próprio, `announcedMovementCount` saiu também como movimento novo. O
|
|
361
|
+
`PROCESS_MOVEMENT_CREATED` diz o grau do movimento mais recente (`degree`,
|
|
362
|
+
`instanceSourceId`) e quantos movimentos novos vieram de cada grau
|
|
363
|
+
(`instances`). Assine os dois: só com o movimento, você não fica sabendo do
|
|
364
|
+
grau que apareceu.
|
|
338
365
|
|
|
339
366
|
**`meta.otherInstances`: o resumo do que veio.** Quando a resposta da fonte traz
|
|
340
367
|
outros documentos do número além da principal, `meta.otherInstances` resume cada
|
|
341
368
|
um com o grau (`grau`), a data em que a fonte o atualizou (`updatedAt`) e o
|
|
342
369
|
órgão julgador (`courtBody`, quando vem). A lista não sai para processo restrito
|
|
343
|
-
e não inclui documento
|
|
344
|
-
|
|
370
|
+
e não inclui documento em segredo de justiça; os documentos inteiros estão em
|
|
371
|
+
`instances`.
|
|
345
372
|
|
|
346
373
|
```ts
|
|
347
374
|
for (const outra of meta.otherInstances ?? []) {
|
|
@@ -350,24 +377,24 @@ for (const outra of meta.otherInstances ?? []) {
|
|
|
350
377
|
```
|
|
351
378
|
|
|
352
379
|
**Continuação.** Na API nada é cortado: o retrato traz os movimentos guardados
|
|
353
|
-
de cada instância, e a lista de movimentações lê
|
|
354
|
-
à fonte. No canal para agentes (MCP),
|
|
355
|
-
resposta: de cada grau vêm os movimentos
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
ou o acompanha.
|
|
380
|
+
de cada instância, e a lista de movimentações lê os movimentos guardados, grau a
|
|
381
|
+
grau, sem ir à fonte. No canal para agentes (MCP), que não passa por este
|
|
382
|
+
pacote, `consultar_processo` cabe numa resposta: de cada grau vêm os movimentos
|
|
383
|
+
mais recentes, o grau que se moveu por último primeiro, e a mesma tool com
|
|
384
|
+
`grau` e `pagina` traz os seguintes, por 1 crédito e sem ir à fonte — só para
|
|
385
|
+
quem já leu o processo ou o acompanha.
|
|
359
386
|
|
|
360
387
|
## Ler um processo quando a fonte está lenta
|
|
361
388
|
|
|
362
|
-
A ficha (`processes.get`) vai à fonte processual quando
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
perto de um minuto por consulta. `waitSeconds` diz quanto
|
|
366
|
-
|
|
389
|
+
A ficha (`processes.get`) vai à fonte processual quando não há uma cópia recente
|
|
390
|
+
guardada; o retrato (`processes.snapshot`) vai sempre. Os dois só respondem com
|
|
391
|
+
a cópia guardada quando a fonte falha (seção seguinte). A fonte às vezes leva
|
|
392
|
+
perto de um minuto por consulta. `waitSeconds` diz quanto a API espera por ela:
|
|
393
|
+
de 10 a 180 segundos, padrão 20.
|
|
367
394
|
|
|
368
395
|
```ts
|
|
369
396
|
const { data, meta } = await lexnode.processes.get(numero, {
|
|
370
|
-
tribunalAlias: "
|
|
397
|
+
tribunalAlias: "TJSP",
|
|
371
398
|
waitSeconds: 120,
|
|
372
399
|
});
|
|
373
400
|
```
|
|
@@ -384,27 +411,27 @@ chamada genérica (`request`) nessas duas rotas.
|
|
|
384
411
|
duas leituras é lentidão da fonte, não ausência do processo, e a política de
|
|
385
412
|
retentativa não o repete: a espera já correu inteira, e repetir na hora a
|
|
386
413
|
dobraria diante da mesma fonte lenta. As outras recusas retentáveis seguem a
|
|
387
|
-
política. Para insistir, a decisão é sua — uma nova chamada com espera maior,
|
|
388
|
-
|
|
414
|
+
política. Para insistir, a decisão é sua — uma nova chamada com espera maior, a
|
|
415
|
+
leitura que segue em segundo plano (`readProcessWithRecovery`, abaixo) ou a
|
|
416
|
+
vigília do processo (`watchProcess`).
|
|
389
417
|
|
|
390
418
|
**`meta.partialIndex`: o processo veio de parte do índice.** Quando a fonte
|
|
391
419
|
responde com só parte do índice e o processo estava na parte que respondeu, ele
|
|
392
420
|
é servido, e `meta.partialIndex` diz quantas partes falharam (`shardsFailed`),
|
|
393
421
|
de quantas (`shardsTotal`, nulo quando a fonte não as contou) e se o prazo
|
|
394
|
-
interno dela estourou (`timedOut`). O documento
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
retentável, nunca 404.
|
|
422
|
+
interno dela estourou (`timedOut`). O documento já guardado que não veio sai em
|
|
423
|
+
`instances` com `origin: "LAKE"` e a data dele, e outro grau ainda não guardado,
|
|
424
|
+
se existir, pode estar na parte que não respondeu. A resposta parcial sem o
|
|
425
|
+
processo é 502 `UPSTREAM_UNAVAILABLE` retentável, nunca 404.
|
|
399
426
|
|
|
400
427
|
```ts
|
|
401
428
|
if (meta.partialIndex) {
|
|
402
|
-
//
|
|
429
|
+
// Um grau deste número ainda não guardado pode não ter vindo.
|
|
403
430
|
}
|
|
404
431
|
```
|
|
405
432
|
|
|
406
433
|
Antes de recusar a resposta parcial que veio sem o processo porque partes do
|
|
407
|
-
índice ficaram fora,
|
|
434
|
+
índice ficaram fora, a API consulta a fonte de novo — até duas vezes, com uma
|
|
408
435
|
pausa curta, enquanto a espera couber.
|
|
409
436
|
|
|
410
437
|
**Agentes têm a espera deles.** No canal para agentes (MCP), as tools
|
|
@@ -415,7 +442,7 @@ mesma faixa e com padrão de 120 s; esse canal não passa pelo SDK.
|
|
|
415
442
|
|
|
416
443
|
Quando a fonte processual falha — não responde dentro de `waitSeconds`, fica
|
|
417
444
|
indisponível, responde com parte do índice sem poder servir o processo ou pede
|
|
418
|
-
para esperar por volume — e
|
|
445
|
+
para esperar por volume — e há uma cópia guardada do processo, a ficha
|
|
419
446
|
(`processes.get`) e o retrato (`processes.snapshot`) respondem com essa cópia em
|
|
420
447
|
vez do erro. A resposta diz que é cópia, e de quando:
|
|
421
448
|
|
|
@@ -423,38 +450,39 @@ vez do erro. A resposta diz que é cópia, e de quando:
|
|
|
423
450
|
`UPSTREAM_UNAVAILABLE` ou `UPSTREAM_RATE_LIMITED`;
|
|
424
451
|
- `meta.lakeRescue.retryAfterSeconds`, repetido no header `Retry-After`, diz na
|
|
425
452
|
recusa por volume quanto esperar antes de consultar a fonte de novo. É a
|
|
426
|
-
espera
|
|
427
|
-
fica `null` no sucesso;
|
|
453
|
+
espera pedida pela fonte, não pelo limite de vazão da API:
|
|
454
|
+
`meta.rateLimit.retryAfterSeconds` fica `null` no sucesso;
|
|
428
455
|
- `meta.sourceFetchedAt` diz quando a cópia foi buscada na fonte. Esse campo
|
|
429
|
-
acompanha toda resposta das duas leituras,
|
|
430
|
-
que o controle de confidencialidade entrega retida, sem o teor.
|
|
456
|
+
acompanha toda resposta das duas leituras, venha ela da fonte ou da cópia,
|
|
457
|
+
menos a ficha que o controle de confidencialidade entrega retida, sem o teor.
|
|
431
458
|
|
|
432
459
|
A cópia custa 1 crédito, na ficha e no retrato. O retrato confere o saldo pelo
|
|
433
460
|
preço cheio, 8, antes de ir à fonte; a ficha confere pelo preço do que
|
|
434
461
|
entregou, depois da leitura. No retrato guardado, cada instância traz os
|
|
435
|
-
movimentos da última vez que
|
|
462
|
+
movimentos da última vez que ela foi buscada, com a data em
|
|
436
463
|
`instances[].fetchedAt`, e `sourcePayload` é nulo: o que andou depois dessas
|
|
437
464
|
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
|
|
439
|
-
data vale para os dados do processo, e o resumo das publicações
|
|
440
|
-
relido na hora.
|
|
465
|
+
fonte já não trazia em documento nenhum não tem cópia servida. Na ficha
|
|
466
|
+
guardada, a data vale para os dados do processo, e o resumo das publicações
|
|
467
|
+
(`djen`) é relido na hora.
|
|
441
468
|
|
|
442
|
-
**Até que idade.** Sem pedir nada, só a cópia de até 24 h
|
|
443
|
-
nessas duas rotas, uma resposta de sucesso já
|
|
444
|
-
desse prazo. A cópia de qualquer idade vem com
|
|
469
|
+
**Até que idade.** Sem pedir nada, só a cópia de até 24 h responde na falha da
|
|
470
|
+
fonte — nessas duas rotas, uma resposta de sucesso já pode ser uma cópia
|
|
471
|
+
guardada dentro desse prazo. A cópia de qualquer idade vem com
|
|
472
|
+
`staleOnFailure: true`:
|
|
445
473
|
|
|
446
474
|
```ts
|
|
447
475
|
import { describeFreshness, lakeRescueOf } from "@lexnode/legal-data-sdk";
|
|
448
476
|
|
|
449
477
|
const retrato = await lexnode.processes.snapshot(numero, {
|
|
450
|
-
tribunalAlias: "
|
|
478
|
+
tribunalAlias: "TJSP",
|
|
451
479
|
staleOnFailure: true,
|
|
452
480
|
});
|
|
453
481
|
|
|
454
|
-
const
|
|
455
|
-
if (
|
|
482
|
+
const copia = lakeRescueOf(retrato);
|
|
483
|
+
if (copia) {
|
|
456
484
|
// A fonte falhou e isto é a cópia guardada: o que andou depois de
|
|
457
|
-
//
|
|
485
|
+
// copia.sourceFetchedAt não está aqui.
|
|
458
486
|
mostrar(describeFreshness(retrato));
|
|
459
487
|
// "cópia guardada em 26/09/2026, servida porque a fonte não respondeu a tempo"
|
|
460
488
|
}
|
|
@@ -465,16 +493,17 @@ if (socorro) {
|
|
|
465
493
|
devolve a data de qualquer resposta dessas leituras. As duas aceitam o envelope
|
|
466
494
|
inteiro e o item do lote.
|
|
467
495
|
|
|
468
|
-
**
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
confidencialidade da leitura; além de 24 h, só a recebe
|
|
472
|
-
registrado no processo — de uma leitura anterior dele ou de uma
|
|
473
|
-
ativa —, e
|
|
496
|
+
**Quando a cópia não é servida.** A resposta da fonte que não traz o processo segue 404
|
|
497
|
+
`PROCESS_NOT_FOUND`, com cópia guardada ou sem ela: é a fonte dizendo que não
|
|
498
|
+
tem o número, e não uma falha dela. A cópia passa pelo mesmo controle de
|
|
499
|
+
confidencialidade da leitura; além de 24 h, só a recebe a conta que já tem
|
|
500
|
+
interesse registrado no processo — de uma leitura anterior dele ou de uma
|
|
501
|
+
assinatura ativa —, e as demais recebem a falha da fonte, como se não houvesse
|
|
502
|
+
cópia.
|
|
474
503
|
|
|
475
|
-
**No lote.** `processes.snapshotBatch`
|
|
476
|
-
|
|
477
|
-
de 8.
|
|
504
|
+
**No lote.** `processes.snapshotBatch` só usa a cópia de até 24 h. O item
|
|
505
|
+
respondido com ela traz `lakeRescue`, com a causa e a data, e custa 1 crédito
|
|
506
|
+
em vez de 8.
|
|
478
507
|
|
|
479
508
|
## Leitura que não coube na espera
|
|
480
509
|
|
|
@@ -488,23 +517,23 @@ em segundo plano em vez de virar erro:
|
|
|
488
517
|
`PROCESS`) ou `snapshot` (visão `SNAPSHOT`), com as instâncias do número em
|
|
489
518
|
`instances`, o mesmo `meta` e o mesmo preço da leitura direta;
|
|
490
519
|
- **202**: a fonte falhou — não respondeu a tempo, ficou indisponível ou pediu
|
|
491
|
-
para esperar —, e
|
|
492
|
-
tentativa, por até 6 h (`giveUpAt`). Nada é cobrado na hora: o preço
|
|
493
|
-
leitura fica retido em `creditsReserved`, o máximo que a entrega cobra, e
|
|
520
|
+
para esperar —, e a API abriu uma consulta que segue tentando sozinha, até
|
|
521
|
+
60 s por tentativa, por até 6 h (`giveUpAt`). Nada é cobrado na hora: o preço
|
|
522
|
+
da leitura fica retido em `creditsReserved`, o máximo que a entrega cobra, e
|
|
494
523
|
só é cobrado se o processo vier. Se não vier, a retenção volta;
|
|
495
524
|
- qualquer outra recusa é a da leitura direta: 404 quando a fonte diz não ter o
|
|
496
525
|
processo, 403 no segredo de justiça, 402 sem saldo.
|
|
497
526
|
|
|
498
527
|
Para uma integração que precisa continuar mesmo quando a fonte demora, use
|
|
499
|
-
`readProcessWithRecovery`. A aceitação da cópia antiga é explícita
|
|
500
|
-
total é limitada. O fim da espera devolve `pending`, com a mesma consulta e
|
|
501
|
-
|
|
528
|
+
`readProcessWithRecovery`. A aceitação da cópia antiga é explícita, e a espera
|
|
529
|
+
total é limitada. O fim da espera devolve `pending`, com a mesma consulta e a
|
|
530
|
+
próxima leitura útil, sem cancelar a consulta nem abrir outra:
|
|
502
531
|
|
|
503
532
|
```ts
|
|
504
533
|
import { readProcessWithRecovery } from "@lexnode/legal-data-sdk";
|
|
505
534
|
|
|
506
535
|
const leitura = await readProcessWithRecovery(lexnode, {
|
|
507
|
-
tribunalAlias: "
|
|
536
|
+
tribunalAlias: "TJSP",
|
|
508
537
|
processNumber: numeroDoProcesso,
|
|
509
538
|
view: "PROCESS",
|
|
510
539
|
waitSeconds: 5,
|
|
@@ -523,10 +552,10 @@ if (leitura.kind === "ready") {
|
|
|
523
552
|
}
|
|
524
553
|
```
|
|
525
554
|
|
|
526
|
-
Sem `completionBudgetMs`,
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
555
|
+
Sem `completionBudgetMs`, a função devolve na hora o desfecho da abertura (200
|
|
556
|
+
ou 202). O orçamento cobre só o acompanhamento, e cada chamada mantém o próprio
|
|
557
|
+
prazo. Abortar a espera não cancela a consulta. O custo, o controle de
|
|
558
|
+
confidencialidade e a cobrança única são os de `processLookups.create`.
|
|
530
559
|
|
|
531
560
|
`lookupProcess` diz, no tipo, qual dos dois desfechos aconteceu, e
|
|
532
561
|
`waitForProcessLookup` espera a consulta terminar:
|
|
@@ -535,7 +564,7 @@ O custo, o gate de confidencialidade e a cobrança única são os do endpoint ex
|
|
|
535
564
|
import { lookupProcess, waitForProcessLookup } from "@lexnode/legal-data-sdk";
|
|
536
565
|
|
|
537
566
|
const desfecho = await lookupProcess(lexnode, {
|
|
538
|
-
tribunalAlias: "
|
|
567
|
+
tribunalAlias: "TJSP",
|
|
539
568
|
processNumber: numero,
|
|
540
569
|
view: "SNAPSHOT",
|
|
541
570
|
});
|
|
@@ -543,9 +572,9 @@ const desfecho = await lookupProcess(lexnode, {
|
|
|
543
572
|
if (desfecho.kind === "ready") {
|
|
544
573
|
desfecho.data.movements; // o retrato, como processes.snapshot o devolveria
|
|
545
574
|
} else {
|
|
546
|
-
//
|
|
547
|
-
//
|
|
548
|
-
// uma tentativa em curso
|
|
575
|
+
// Espere com orçamento. A consulta é lida de novo na hora da próxima
|
|
576
|
+
// tentativa (nextAttemptAt), quando o estado pode mudar, e a cada 10 s
|
|
577
|
+
// enquanto uma tentativa está em curso.
|
|
549
578
|
const consulta = await waitForProcessLookup(
|
|
550
579
|
lexnode,
|
|
551
580
|
desfecho.lookup.lookupId!,
|
|
@@ -565,22 +594,23 @@ chamada repetida tenta a fonte na hora, dentro da espera dela. O tempo
|
|
|
565
594
|
esgotado da fonte continua sem repetição automática.
|
|
566
595
|
|
|
567
596
|
**A consulta se lê de graça, por 24 h.** `processLookups.get(lookupId)` custa 0
|
|
568
|
-
e, depois da entrega, traz o processo por 24 h (`resultExpiresAt`), relido
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
completam a superfície; o cancelamento devolve a
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
597
|
+
e, depois da entrega, traz o processo por 24 h (`resultExpiresAt`), relido e
|
|
598
|
+
passado de novo pelo controle de confidencialidade: o processo que passou a
|
|
599
|
+
segredo de justiça depois responde 403. O retrato lido da consulta traz a
|
|
600
|
+
instância principal no topo e cada instância com os movimentos da última
|
|
601
|
+
captura dela, e `sourcePayload` é nulo. `processLookups.list` e
|
|
602
|
+
`processLookups.cancel` completam a superfície; o cancelamento devolve a
|
|
603
|
+
retenção e não gera evento.
|
|
604
|
+
|
|
605
|
+
**Por webhook, sem esperar nada.** O fim sai em `PROCESS_LOOKUP_COMPLETED`, que
|
|
606
|
+
aponta a consulta e nunca traz o processo; o movimento novo que a entrega
|
|
607
|
+
trouxer chega no `PROCESS_MOVEMENT_CREATED` de sempre.
|
|
578
608
|
|
|
579
609
|
**A cópia guardada e a atualização, uma compra só.** Com `staleOnFailure: true`,
|
|
580
|
-
o 202 traz em `stale` a cópia
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
610
|
+
o 202 traz em `stale` a cópia guardada, com a data e a causa, por 1 crédito, e
|
|
611
|
+
a consulta segue buscando a versão atual. A entrega cobra só o resto do preço
|
|
612
|
+
(`alreadyCharged` diz quanto já foi): as duas juntas custam o mesmo que a
|
|
613
|
+
leitura direta, e a atualização que não vier não cobra mais nada.
|
|
584
614
|
|
|
585
615
|
**A leitura direta fecha a consulta.** A ficha ou o retrato do mesmo processo
|
|
586
616
|
lidos com sucesso por `processes.get` ou `processes.snapshot` fecham a consulta
|
|
@@ -593,8 +623,8 @@ consulta.
|
|
|
593
623
|
## Frescor: o `total: 0` qualificado
|
|
594
624
|
|
|
595
625
|
Um resultado vazio não distingue sozinho "não existe" de "a fonte ainda não
|
|
596
|
-
indexou".
|
|
597
|
-
(processo e diário):
|
|
626
|
+
indexou". A API publica a data-limite do índice da fonte; o SDK a lê nos dois
|
|
627
|
+
eixos (processo e diário):
|
|
598
628
|
|
|
599
629
|
```ts
|
|
600
630
|
import {
|
|
@@ -610,15 +640,15 @@ if (isNotYetIndexed(busca, { since: "2026-09-15" })) {
|
|
|
610
640
|
mostrar(describeFreshness(busca)); // "fonte lida até 10/09/2026"
|
|
611
641
|
}
|
|
612
642
|
|
|
613
|
-
readThrough(busca); // Date | null — null
|
|
643
|
+
readThrough(busca); // Date | null — null quando a resposta não declara a data-limite
|
|
614
644
|
```
|
|
615
645
|
|
|
616
646
|
## Vigília com vários interessados
|
|
617
647
|
|
|
618
|
-
|
|
619
|
-
conta e
|
|
620
|
-
`externalRef`, sem
|
|
621
|
-
um
|
|
648
|
+
A vigília de um processo tem duas partes: o **monitor**, que consulta a fonte —
|
|
649
|
+
um por processo na conta, e o plano limita quantos —, e a **assinatura**, que
|
|
650
|
+
recebe o aviso — uma por `externalRef`, sem limite, e o `externalRef` volta no
|
|
651
|
+
evento. N interessados no mesmo processo são um monitor e N assinaturas.
|
|
622
652
|
|
|
623
653
|
```ts
|
|
624
654
|
import { unwatchProcess, watchProcess } from "@lexnode/legal-data-sdk";
|
|
@@ -627,23 +657,26 @@ const { monitorId, monitorAlreadyExisted, subscription } = await watchProcess(
|
|
|
627
657
|
lexnode,
|
|
628
658
|
{
|
|
629
659
|
processNumber: "00012345620268260100",
|
|
630
|
-
tribunalAlias: "
|
|
660
|
+
tribunalAlias: "TJSP",
|
|
631
661
|
officeId: "usuario-4711",
|
|
632
662
|
externalRef: "caso-42",
|
|
633
663
|
},
|
|
634
664
|
);
|
|
635
665
|
|
|
636
|
-
// Um interessado
|
|
666
|
+
// Um interessado sai; o monitor continua ativo para os demais.
|
|
637
667
|
await unwatchProcess(lexnode, {
|
|
638
668
|
externalRef: "caso-42",
|
|
639
669
|
officeId: "usuario-4711",
|
|
640
670
|
});
|
|
641
671
|
```
|
|
642
672
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
673
|
+
Quando o último interessado sair, remova o monitor com
|
|
674
|
+
`lexnode.monitors.delete(monitorId)`.
|
|
675
|
+
|
|
676
|
+
**Limitação conhecida:** uma assinatura criada **antes** de o processo aparecer
|
|
677
|
+
na fonte não recebe `PROCESS_MOVEMENT_CREATED` até a primeira aparição dele. O
|
|
678
|
+
contorno é refazer a assinatura quando chegar o `MONITOR_SYNC_SUCCEEDED` com
|
|
679
|
+
`firstAppearance: true`:
|
|
647
680
|
|
|
648
681
|
```ts
|
|
649
682
|
import { resubscribeOnFirstAppearance } from "@lexnode/legal-data-sdk";
|
|
@@ -653,10 +686,9 @@ await resubscribeOnFirstAppearance(lexnode, evento, [
|
|
|
653
686
|
]);
|
|
654
687
|
```
|
|
655
688
|
|
|
656
|
-
##
|
|
689
|
+
## Os tipos do contrato
|
|
657
690
|
|
|
658
|
-
O
|
|
659
|
-
sempre:
|
|
691
|
+
O pacote exporta `paths` e `operations`, gerados do contrato OpenAPI:
|
|
660
692
|
|
|
661
693
|
```ts
|
|
662
694
|
import type { operations, paths } from "@lexnode/legal-data-sdk";
|
|
@@ -669,7 +701,7 @@ type Tribunals =
|
|
|
669
701
|
operations["listTribunals"]["responses"][200]["content"]["application/json"]["data"];
|
|
670
702
|
```
|
|
671
703
|
|
|
672
|
-
E
|
|
704
|
+
E atalhos derivados deles:
|
|
673
705
|
|
|
674
706
|
```ts
|
|
675
707
|
import type { Body, Data, Query } from "@lexnode/legal-data-sdk";
|
|
@@ -681,11 +713,11 @@ type Tribunais = Data<"/v1/tribunals", "get">;
|
|
|
681
713
|
|
|
682
714
|
## A chave de teste
|
|
683
715
|
|
|
684
|
-
A chave `lapi_test_`
|
|
685
|
-
cria trabalho
|
|
686
|
-
respondem 403 `SANDBOX_UPSTREAM_DISABLED`.
|
|
687
|
-
`async` de `searchProcesses` só
|
|
688
|
-
|
|
716
|
+
A chave `lapi_test_` relê o que a conta já buscou com a chave de produção, mas
|
|
717
|
+
**não consulta a fonte nem cria trabalho em segundo plano**: monitor, vigília,
|
|
718
|
+
colheita e busca assíncrona respondem 403 `SANDBOX_UPSTREAM_DISABLED`. Por isso
|
|
719
|
+
`watchProcess` e o ramo `async` de `searchProcesses` só funcionam com a chave
|
|
720
|
+
de produção.
|
|
689
721
|
|
|
690
722
|
## Referências
|
|
691
723
|
|