@lexnode/legal-data-sdk 1.0.0 → 1.18.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
@@ -1,25 +1,327 @@
1
1
  # @lexnode/legal-data-sdk
2
2
 
3
- Tipos TypeScript do contrato da API do **LexNode**, o motor de dados jurídicos
4
- do Brasil: processos e movimentações, publicações dos diários oficiais,
5
- jurisprudência, monitores e webhooks. O pacote traz **só tipos** — nenhum
6
- cliente HTTP embutido —, para que você escolha o transporte e o compilador
7
- confira o resto.
3
+ Cliente TypeScript do **LexNode**, o motor de dados jurídicos do Brasil:
4
+ processos e movimentações, publicações dos diários oficiais, jurisprudência,
5
+ monitores e webhooks.
6
+
7
+ O pacote traz **os tipos gerados do contrato OpenAPI** e um **cliente de
8
+ runtime** construído sobre eles: transporte com os cabeçalhos certos, erros
9
+ classificados, verificação de assinatura de webhook, espera de busca
10
+ assíncrona, leitura do alcance da fonte e a composição de vigília com vários
11
+ interessados.
12
+
13
+ - **Sem dependências de runtime.** `fetch` global e `node:crypto`.
14
+ - **Node >= 20**, ESM.
15
+
16
+ > ⚠️ **Servidor apenas, e só por TLS.** A credencial é uma chave de **conta**:
17
+ > no browser ela está publicada, e em `http://` ela é lida por quem estiver no
18
+ > caminho — uma `baseUrl` sem https é recusada no construtor (host local é a
19
+ > exceção, para desenvolvimento). Um app com usuários finais fala com o próprio
20
+ > backend, e é o backend que fala com o motor — atribuindo cada chamada ao seu
21
+ > sub-tenant pelo cabeçalho `X-Office-Id`.
8
22
 
9
23
  ## Instalação
10
24
 
11
25
  ```sh
12
- npm install -D @lexnode/legal-data-sdk
26
+ npm install @lexnode/legal-data-sdk
27
+ ```
28
+
29
+ ## O cliente
30
+
31
+ ```ts
32
+ import { createLexNodeClient } from "@lexnode/legal-data-sdk";
33
+
34
+ const lexnode = createLexNodeClient({
35
+ baseUrl: "https://api.lexnode.com.br",
36
+ apiKey: process.env.LEXNODE_API_KEY!,
37
+ // Sub-tenant padrão; cada chamada pode trocá-lo.
38
+ officeId: "escritorio-01",
39
+ timeoutMs: 30_000,
40
+ userAgent: "meu-app/1.0",
41
+ });
42
+
43
+ const { data, meta } = await lexnode.processes.get("00012345620268260100", {
44
+ tribunalAlias: "api_publica_tjsp",
45
+ });
46
+
47
+ console.log(data.formattedNumber, meta.credits, meta.rateLimit?.remaining);
48
+ ```
49
+
50
+ Toda chamada manda `Authorization: Bearer`, `X-Request-Id`, `X-Trace-Id` e,
51
+ quando há um, `X-Office-Id`; respeita o prazo do cliente **combinado** com o
52
+ `signal` de quem chamou; e devolve `{ data, meta }` tipados pela rota. O `meta`
53
+ é o do contrato mais `status` (o código HTTP) e `rateLimit` (os cabeçalhos
54
+ `RateLimit-*` / `Retry-After`, lidos **inclusive no sucesso**).
55
+
56
+ Em `rateLimit`, use `remaining` para desacelerar: `resetSeconds` repete o que o
57
+ cabeçalho `RateLimit-Reset` trouxe, e o motor lhe dá dois sentidos — segundos
58
+ até reabrir na recusa, comprimento da janela (60 s) no sucesso.
59
+
60
+ O pacote **não valida a resposta em tempo de execução**: `data` e `meta` chegam
61
+ tipados pelo contrato, e o que garante a correspondência é a versão fixada, não
62
+ uma conferência a cada chamada. Quem precisa de barreira na borda — porque o
63
+ dado alimenta um banco, por exemplo — valida o que consome.
64
+
65
+ ### Métodos nomeados e a chamada genérica
66
+
67
+ Os métodos nomeados cobrem o uso diário:
68
+
69
+ ```ts
70
+ await lexnode.tribunals.list();
71
+ await lexnode.processes.movements(numero, { tribunalAlias });
72
+ await lexnode.publications.list({ oabNumber: "123456", oabState: "SP" });
73
+ await lexnode.monitors.create({ type: "OAB", oabNumber: "123456", oabState: "SP" });
74
+ await lexnode.subscriptions.create({ tribunalAlias, processNumber, externalRef });
75
+ await lexnode.searchJobs.get(jobId);
76
+ await lexnode.events.list({ limit: 50 });
77
+ await lexnode.webhooks.endpoints.list();
78
+ await lexnode.usage.get();
79
+ ```
80
+
81
+ Qualquer rota do contrato — inclusive uma que o pacote ainda não batizou — sai
82
+ pela chamada genérica, tipada por `paths`:
83
+
84
+ ```ts
85
+ const { data } = await lexnode.request("/v1/precedents", "get", {
86
+ params: { query: { query: "dano moral", limit: 20 } },
87
+ });
88
+ ```
89
+
90
+ ### Páginas
91
+
92
+ O motor pagina de três jeitos (cursor no `meta`, cursor no `data`, e
93
+ página/tamanho ou deslocamento/teto). `paginate` percorre qualquer um deles, com
94
+ teto explícito de páginas — cada página é uma chamada medida:
95
+
96
+ ```ts
97
+ import { paginate } from "@lexnode/legal-data-sdk";
98
+
99
+ for await (const page of paginate(lexnode, "/v1/monitors", "get", {})) {
100
+ for (const monitor of page) console.log(monitor.id);
101
+ }
102
+ ```
103
+
104
+ ### Erros
105
+
106
+ ```ts
107
+ import { LexNodeError } from "@lexnode/legal-data-sdk";
108
+
109
+ try {
110
+ await lexnode.processes.search({ tribunalAlias, number });
111
+ } catch (error) {
112
+ if (error instanceof LexNodeError) {
113
+ error.code; // "RATE_LIMITED", "PROCESS_NOT_FOUND", …
114
+ error.class; // "RETRYABLE" | "TERMINAL"
115
+ error.retryable;
116
+ error.status;
117
+ error.upstreamStatus; // o status real da fonte, quando preservado
118
+ error.requestId; // o que o suporte pede
119
+ error.fieldErrors; // recusa de validação, por campo
120
+ error.retryAfterSeconds;
121
+ error.rateLimit;
122
+ }
123
+ }
124
+ ```
125
+
126
+ Prazo esgotado vira `CLIENT_TIMEOUT` (504, retentável); falha de rede vira
127
+ `CLIENT_NETWORK_ERROR` (502, retentável); resposta fora do envelope vira
128
+ `INVALID_RESPONSE` (502) com o corpo cru truncado na mensagem; o que o
129
+ transporte recusa mandar — cabeçalho com quebra de linha, corpo que não
130
+ serializa — vira `CLIENT_INVALID_REQUEST` (400, **não** retentável), porque
131
+ repetir o que nunca saiu não cura.
132
+
133
+ `LEXNODE_ERROR_CODES` traz o catálogo para o `switch`, e `LexNodeErrorCode`
134
+ mantém o autocompletar sem fechar a porta a um código novo. Importa na leitura
135
+ de processo: o motor responde 404 tanto para `PROCESS_NOT_FOUND` (o processo não
136
+ existe na fonte) quanto para `MOVEMENTS_NOT_AVAILABLE` (existe, mas as
137
+ movimentações não vêm) — quem trata os dois igual conta a história errada.
138
+
139
+ ### Retentativa (opcional, desligada por padrão)
140
+
141
+ ```ts
142
+ const lexnode = createLexNodeClient({
143
+ baseUrl,
144
+ apiKey,
145
+ retry: { attempts: 3, baseDelayMs: 500 },
146
+ });
147
+ ```
148
+
149
+ Repete só o que é `RETRYABLE`, respeitando `Retry-After`. `GET` e `DELETE` são
150
+ repetidos por definição do HTTP. Uma **escrita** só é repetida quando o contrato
151
+ declara a repetição segura — hoje `POST /v1/publications/text-searches`, que usa
152
+ o `requestId` que você fixar como chave de replay — ou quando você mesmo o
153
+ declara na chamada:
154
+
155
+ ```ts
156
+ await lexnode.webhooks.endpoints.create(corpo, { idempotent: true });
157
+ ```
158
+
159
+ A afirmação é sua: sem ela, um `POST` repetido cria um **segundo** recurso — dois
160
+ endpoints para a mesma URL entregam cada evento em dobro, e o segredo do
161
+ primeiro fica órfão. Em toda outra rota o `requestId` é só rastreio.
162
+
163
+ ## Webhooks
164
+
165
+ ```ts
166
+ import {
167
+ parseWebhookEvent,
168
+ webhookRejectionStatus,
169
+ } from "@lexnode/legal-data-sdk";
170
+
171
+ // O corpo CRU, nunca um JSON reserializado: o digest é sobre os bytes.
172
+ const resultado = parseWebhookEvent(
173
+ rawBody,
174
+ request.headers,
175
+ process.env.LEXNODE_WEBHOOK_SIGNING_SECRET!,
176
+ );
177
+
178
+ // O status de cada recusa vem junto: um corpo que não se autentica é 401 e não
179
+ // volta; segredo ausente é 503, porque a falha é SUA e o motor precisa insistir.
180
+ if (!resultado.ok) {
181
+ return reply.status(webhookRejectionStatus(resultado.reason)).send();
182
+ }
183
+ // Tipo que o catálogo ainda não descreve: ignore e responda 2xx.
184
+ if (!resultado.known) return reply.status(200).send();
185
+
186
+ switch (resultado.event.type) {
187
+ case "PUBLICATION_CREATED":
188
+ resultado.event.payload.publicationKey;
189
+ resultado.event.payload.excerpt; // null quando o teor foi retido
190
+ break;
191
+ case "PROCESS_MOVEMENT_CREATED":
192
+ resultado.event.payload.externalRef;
193
+ break;
194
+ case "SEARCH_JOB_COMPLETED":
195
+ if (resultado.event.payload.status === "FAILED") {
196
+ resultado.event.payload.error.code;
197
+ }
198
+ break;
199
+ case "WEBHOOK_TEST":
200
+ // A entrega de teste do console. Chega a qualquer endpoint, não se assina
201
+ // e não se recusa — é ela que valida o receptor antes do primeiro evento.
202
+ break;
203
+ default:
204
+ break;
205
+ }
13
206
  ```
14
207
 
15
- ## Uso
208
+ O envelope precisa ser endereçável: entrega sem `id` ou sem `occurredAt` é
209
+ recusada como `INVALID_ENVELOPE`. O `id` é a chave de idempotência de todo
210
+ receptor — aceitá-lo vazio faria a primeira entrega ocupar a única vaga de
211
+ deduplicação e todas as seguintes parecerem repetição dela.
16
212
 
17
- Os tipos são gerados do documento OpenAPI publicado pela API e expõem as
18
- interfaces `paths` e `operations`. Combine-os com o cliente de sua preferência
19
- (por exemplo, `openapi-fetch`):
213
+ `WEBHOOK_EVENT_TYPES` é o catálogo **assinável** (o que entra em `eventTypes`
214
+ ao cadastrar um endpoint) e não inclui `WEBHOOK_TEST`, que chega sem ser
215
+ pedido — use `isWebhookTest(event)` para separá-lo.
216
+
217
+ `verifyWebhookSignature(rawBody, headers, secret)` faz só a conferência e
218
+ devolve o motivo da recusa (`MISSING_SIGNATURE`, `MALFORMED_SIGNATURE`,
219
+ `TIMESTAMP_MISMATCH`, `TIMESTAMP_OUT_OF_TOLERANCE`, `SIGNATURE_MISMATCH`,
220
+ `RAW_BODY_REQUIRED`), em vez de um `false` que faria vários incidentes
221
+ diferentes virarem a mesma resposta.
222
+
223
+ O corpo entra como `string` ou `Buffer` — os bytes como chegaram. Passar o JSON
224
+ já parseado é recusado como `RAW_BODY_REQUIRED`, e não confundido com
225
+ adulteração: reserializar reordena as chaves e o digest deixa de bater.
226
+
227
+ A janela de replay e o digest saem do `t` que viaja **dentro** da assinatura; o
228
+ cabeçalho `x-lexnode-timestamp` é redundante e só é conferido quando vem. Um
229
+ receptor escrito à mão que o exigia continua correto — o SDK apenas não faz da
230
+ ausência dele um motivo de recusa, porque ela não prova nada.
231
+
232
+ ## Busca síncrona ou assíncrona
233
+
234
+ `POST /v1/processes/search` responde **200** com o resultado pronto ou **202**
235
+ com um trabalho enfileirado. O SDK diz qual foi, no tipo:
20
236
 
21
237
  ```ts
22
- import type { paths, operations } from "@lexnode/legal-data-sdk";
238
+ import { searchProcesses, waitForSearchJob } from "@lexnode/legal-data-sdk";
239
+
240
+ const desfecho = await searchProcesses(lexnode, { tribunalAlias, number });
241
+
242
+ if (desfecho.kind === "sync") {
243
+ desfecho.result.items;
244
+ } else {
245
+ // O orçamento é explícito: num ambiente serverless, esperar sem teto gasta
246
+ // a requisição inteira. Quem integrou por webhook nem espera — recebe o
247
+ // SEARCH_JOB_COMPLETED.
248
+ const job = await waitForSearchJob(lexnode, desfecho.job.jobId, {
249
+ budgetMs: 20_000,
250
+ });
251
+ job.status; // "SUCCEEDED" | "FAILED" | "CANCELED"
252
+ }
253
+ ```
254
+
255
+ ## Frescor: o `total: 0` qualificado
256
+
257
+ Um resultado vazio não distingue sozinho "não existe" de "a fonte ainda não
258
+ indexou". O motor publica a data-limite do índice; o SDK a lê nos dois eixos
259
+ (processo e diário):
260
+
261
+ ```ts
262
+ import {
263
+ describeFreshness,
264
+ isNotYetIndexed,
265
+ readThrough,
266
+ } from "@lexnode/legal-data-sdk";
267
+
268
+ const busca = await lexnode.processes.search({ tribunalAlias, number });
269
+
270
+ if (isNotYetIndexed(busca, { since: "2026-09-15" })) {
271
+ // Não diga "não existe": diga até quando a fonte foi lida.
272
+ mostrar(describeFreshness(busca)); // "fonte lida até 10/09/2026"
273
+ }
274
+
275
+ readThrough(busca); // Date | null — null é ESTADO indeterminado, não erro
276
+ ```
277
+
278
+ ## Vigília com vários interessados
279
+
280
+ O motor separa duas primitivas: o **sensor** (`Monitor`), único por alvo na
281
+ conta e com teto, e a **assinatura** (`ProcessSubscription`), única por
282
+ `externalRef`, sem teto e ecoada no aviso. N interessados no mesmo processo são
283
+ um sensor e N assinaturas.
284
+
285
+ ```ts
286
+ import { unwatchProcess, watchProcess } from "@lexnode/legal-data-sdk";
287
+
288
+ const { monitorId, monitorAlreadyExisted, subscription } = await watchProcess(
289
+ lexnode,
290
+ {
291
+ processNumber: "00012345620268260100",
292
+ tribunalAlias: "api_publica_tjsp",
293
+ officeId: "usuario-4711",
294
+ externalRef: "caso-42",
295
+ },
296
+ );
297
+
298
+ // Um interessado desiste; o sensor continua varrendo para os demais.
299
+ await unwatchProcess(lexnode, {
300
+ externalRef: "caso-42",
301
+ officeId: "usuario-4711",
302
+ });
303
+ ```
304
+
305
+ **Limitação conhecida:** uma assinatura criada **antes** de o processo entrar no
306
+ acervo não recebe `PROCESS_MOVEMENT_CREATED` até a primeira aparição do alvo na
307
+ fonte. O contorno é refazer a assinatura quando chegar o
308
+ `MONITOR_SYNC_SUCCEEDED` com `firstAppearance: true`:
309
+
310
+ ```ts
311
+ import { resubscribeOnFirstAppearance } from "@lexnode/legal-data-sdk";
312
+
313
+ await resubscribeOnFirstAppearance(lexnode, evento, [
314
+ { externalRef: "caso-42", officeId: "usuario-4711" },
315
+ ]);
316
+ ```
317
+
318
+ ## Só os tipos
319
+
320
+ O uso antigo continua valendo — o pacote exporta `paths` e `operations` como
321
+ sempre:
322
+
323
+ ```ts
324
+ import type { operations, paths } from "@lexnode/legal-data-sdk";
23
325
 
24
326
  // Uma operação inteira, pela rota e pelo método:
25
327
  type SearchProcesses = paths["/v1/processes/search"]["post"];
@@ -29,6 +331,24 @@ type Tribunals =
29
331
  operations["listTribunals"]["responses"][200]["content"]["application/json"]["data"];
30
332
  ```
31
333
 
334
+ E os atalhos derivados deles, que o cliente usa internamente:
335
+
336
+ ```ts
337
+ import type { Body, Data, Query } from "@lexnode/legal-data-sdk";
338
+
339
+ type CorpoDaBusca = Body<"/v1/processes/search", "post">;
340
+ type ConsultaDeProcesso = Query<"/v1/processes/{processNumber}", "get">;
341
+ type Tribunais = Data<"/v1/tribunals", "get">;
342
+ ```
343
+
344
+ ## A chave de teste
345
+
346
+ A chave `lapi_test_` lê o acervo já formado, mas **não consulta a fonte viva nem
347
+ cria trabalho de fundo**: monitor, vigília, colheita e busca assíncrona
348
+ respondem 403 `SANDBOX_UPSTREAM_DISABLED`. Na prática, `watchProcess` e o ramo
349
+ `async` de `searchProcesses` só fecham com chave viva — vale saber antes de
350
+ achar que a integração está errada.
351
+
32
352
  ## Referências
33
353
 
34
354
  - Documentação: <https://www.lexnode.com.br/docs>
@@ -0,0 +1,95 @@
1
+ import type { paths } from "../schema.js";
2
+ import type { Body, CallOptions, LexNodeResult, MethodOf, Query, RequestArgs, RetryPolicy } from "./types.js";
3
+ export interface LexNodeClientOptions {
4
+ /** Base da API, por exemplo `https://api.lexnode.com.br`. */
5
+ baseUrl: string;
6
+ /**
7
+ * Chave de CONTA (`Authorization: Bearer`). É credencial de servidor: ver o
8
+ * aviso de `createLexNodeClient`.
9
+ */
10
+ apiKey: string;
11
+ /** Sub-tenant padrão (`X-Office-Id`). Cada chamada pode trocá-lo ou omiti-lo. */
12
+ officeId?: string;
13
+ /** Prazo de cada chamada, em ms. Padrão: 30 s. */
14
+ timeoutMs?: number;
15
+ /** Transporte alternativo — o `fetch` global é o padrão. */
16
+ fetch?: typeof globalThis.fetch;
17
+ /** Identifica a sua integração no `User-Agent`. */
18
+ userAgent?: string;
19
+ /** Política de retentativa padrão. Ausente = desligada. */
20
+ retry?: RetryPolicy;
21
+ }
22
+ /**
23
+ * O cliente de runtime do motor de dados jurídicos.
24
+ *
25
+ * **Servidor apenas, e só por TLS.** A credencial é de CONTA: uma chave no
26
+ * browser é uma chave publicada, e uma chave em `http://` é uma chave lida por
27
+ * quem estiver no caminho — `baseUrl` sem https é recusada aqui, exceto em
28
+ * host local. Um app com usuários finais fala com o próprio backend, e é o
29
+ * backend que fala com o motor — atribuindo cada chamada ao seu sub-tenant por
30
+ * `X-Office-Id`.
31
+ *
32
+ * Sem dependências de runtime: `fetch` global e `node:crypto`.
33
+ */
34
+ export declare function createLexNodeClient(options: LexNodeClientOptions): {
35
+ request: <P extends keyof paths, M extends MethodOf<P>>(path: P, method: M, args: RequestArgs<P, M>) => Promise<LexNodeResult<P, M>>;
36
+ tribunals: {
37
+ list: (query?: Query<"/v1/tribunals", "get">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/tribunals", "get">>;
38
+ };
39
+ processes: {
40
+ search: (body: Body<"/v1/processes/search", "post">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/processes/search", "post">>;
41
+ get: (processNumber: string, query: Query<"/v1/processes/{processNumber}", "get">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/processes/{processNumber}", "get">>;
42
+ movements: (processNumber: string, query: Query<"/v1/processes/{processNumber}/movements", "get">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/processes/{processNumber}/movements", "get">>;
43
+ snapshot: (processNumber: string, query: Query<"/v1/processes/{processNumber}/snapshot", "get">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/processes/{processNumber}/snapshot", "get">>;
44
+ related: (processNumber: string, query: Query<"/v1/processes/{processNumber}/related", "get">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/processes/{processNumber}/related", "get">>;
45
+ snapshotBatch: (body: Body<"/v1/processes/snapshot-batch", "post">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/processes/snapshot-batch", "post">>;
46
+ };
47
+ publications: {
48
+ list: (query?: Query<"/v1/publications", "get">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/publications", "get">>;
49
+ read: (publicationKey: string, opts?: CallOptions) => Promise<LexNodeResult<"/v1/publications/{publicationKey}", "get">>;
50
+ textSearch: (body: Body<"/v1/publications/text-searches", "post">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/publications/text-searches", "post">>;
51
+ textAlerts: {
52
+ create: (body: Body<"/v1/publications/text-alerts", "post">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/publications/text-alerts", "post">>;
53
+ list: (query?: Query<"/v1/publications/text-alerts", "get">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/publications/text-alerts", "get">>;
54
+ delete: (alertId: string, opts?: CallOptions) => Promise<LexNodeResult<"/v1/publications/text-alerts/{alertId}", "delete">>;
55
+ };
56
+ };
57
+ monitors: {
58
+ create: (body: Body<"/v1/monitors", "post">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/monitors", "post">>;
59
+ list: (query?: Query<"/v1/monitors", "get">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/monitors", "get">>;
60
+ get: (monitorId: string, opts?: CallOptions) => Promise<LexNodeResult<"/v1/monitors/{monitorId}", "get">>;
61
+ update: (monitorId: string, body: Body<"/v1/monitors/{monitorId}", "patch">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/monitors/{monitorId}", "patch">>;
62
+ delete: (monitorId: string, opts?: CallOptions) => Promise<LexNodeResult<"/v1/monitors/{monitorId}", "delete">>;
63
+ sync: (monitorId: string, opts?: CallOptions) => Promise<LexNodeResult<"/v1/monitors/{monitorId}/sync", "post">>;
64
+ };
65
+ subscriptions: {
66
+ create: (body: Body<"/v1/subscriptions", "post">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/subscriptions", "post">>;
67
+ list: (query?: Query<"/v1/subscriptions", "get">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/subscriptions", "get">>;
68
+ delete: (body: Body<"/v1/subscriptions", "delete">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/subscriptions", "delete">>;
69
+ };
70
+ searchJobs: {
71
+ get: (jobId: string, opts?: CallOptions) => Promise<LexNodeResult<"/v1/search-jobs/{jobId}", "get">>;
72
+ list: (query?: Query<"/v1/search-jobs", "get">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/search-jobs", "get">>;
73
+ cancel: (jobId: string, opts?: CallOptions) => Promise<LexNodeResult<"/v1/search-jobs/{jobId}/cancel", "post">>;
74
+ };
75
+ events: {
76
+ list: (query?: Query<"/v1/events", "get">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/events", "get">>;
77
+ get: (eventId: string, opts?: CallOptions) => Promise<LexNodeResult<"/v1/events/{eventId}", "get">>;
78
+ };
79
+ usage: {
80
+ get: (query?: Query<"/v1/usage", "get">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/usage", "get">>;
81
+ };
82
+ webhooks: {
83
+ endpoints: {
84
+ list: (query?: Query<"/v1/webhooks/endpoints", "get">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/webhooks/endpoints", "get">>;
85
+ create: (body: Body<"/v1/webhooks/endpoints", "post">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/webhooks/endpoints", "post">>;
86
+ update: (endpointId: string, body: Body<"/v1/webhooks/endpoints/{endpointId}", "patch">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/webhooks/endpoints/{endpointId}", "patch">>;
87
+ delete: (endpointId: string, opts?: CallOptions) => Promise<LexNodeResult<"/v1/webhooks/endpoints/{endpointId}", "delete">>;
88
+ test: (endpointId: string, opts?: CallOptions) => Promise<LexNodeResult<"/v1/webhooks/endpoints/{endpointId}/test", "post">>;
89
+ rotateSecret: (endpointId: string, opts?: CallOptions) => Promise<LexNodeResult<"/v1/webhooks/endpoints/{endpointId}/rotate-secret", "post">>;
90
+ };
91
+ deliveries: (query?: Query<"/v1/webhooks/deliveries", "get">, opts?: CallOptions) => Promise<LexNodeResult<"/v1/webhooks/deliveries", "get">>;
92
+ health: (opts?: CallOptions) => Promise<LexNodeResult<"/v1/webhooks/health", "get">>;
93
+ };
94
+ };
95
+ export type LexNodeClient = ReturnType<typeof createLexNodeClient>;