SDK do conector (ctx)
Gerada dos tipos do pacote @zoppy-connect/connect-sdk (Zoppy-crm/zoppy-connect@f1ae3a72be71). Um conector é um arquivo TypeScript que exporta uma função e recebe o ctx:
import type { ConnectorContext, ConnectorResult } from '@zoppy-connect/connect-sdk';
export default async function run(ctx: ConnectorContext): Promise<ConnectorResult> { let cursor = (ctx.state.get('cursor') as string | undefined) ?? '1970-01-01T00:00:00Z'; for (;;) { const resposta = await ctx.http.request({ method: 'GET', url: 'https://api.exemplo.com.br/v1/clientes', headers: { Authorization: `Bearer ${ctx.secret('EXEMPLO_TOKEN')}` }, query: { alteradoDesde: cursor, limite: '100' }, }); const clientes = resposta.json() as { id: string; alteradoEm: string }[]; ctx.count('clientes', 'read', clientes.length); if (clientes.length === 0) { return { done: true }; } cursor = clientes[clientes.length - 1].alteradoEm; ctx.state.set('cursor', cursor); if (ctx.shouldYield()) { return { done: false }; } }}O código não tem rede nem variáveis de ambiente: só o que está aqui. Imports só do Node ou de tipos; o resto é recusado na compilação. Os limites de cada fatia estão em Limites.
O conector
Seção intitulada “O conector”ConnectorMain
Seção intitulada “ConnectorMain”A função que o arquivo do conector exporta como default. Recebe o ctx e devolve nada, ou um ConnectorResult.
type ConnectorMain = (ctx: ConnectorContext) => Promise<ConnectorResult | undefined>;ConnectorResult
Seção intitulada “ConnectorResult”O que a função do conector devolve. Sem retorno, ou com done: true, a execução termina.
| Membro | Tipo | Descrição |
|---|---|---|
done |
boolean (opcional) |
false pede mais uma fatia: guarde o cursor em ctx.state antes de devolver. Nada ou true termina a execução. |
output |
Readonly<Record<string, JsonValue>> (opcional) |
O que a execução devolve a quem a chamou, na fatia que termina. Ignorado quando o manifesto não declara saída (o caso de todo conector na V1, que só roda pelo cron) e nas fatias que continuam. |
ConnectorContext
Seção intitulada “ConnectorContext”O ctx: tudo o que o código do conector enxerga. O código roda sem rede; cada chamada abaixo passa pelo gateway, que só deixa sair o que o manifesto declara.
| Membro | Tipo | Descrição |
|---|---|---|
http |
{ … } |
Chamadas HTTP pelo gateway, separadas entre ler e escrever. |
http.request |
request(request: HttpRequest): Promise<HttpResponse> |
Lê do outro sistema, seja qual for o método: um POST que só consulta (comum em APIs que pesquisam por POST e em SOAP) também vai aqui. É de verdade também no ensaio. Um POST, PUT, PATCH ou DELETE feito aqui aparece na lista de escritas feitas como leitura (writesAsReads) do ensaio, para uma pessoa conferir. |
http.write |
write(request: HttpRequest): Promise<HttpResponse> |
Cria, altera ou apaga algo no outro sistema. No ensaio, a chamada é registrada sem sair (planned: true). Em produção, exige externalWrites: true no manifesto, e a primeira escrita do conector em cada host espera uma pessoa confirmar: até lá ela fica guardada, as outras escritas daquela execução não saem e cada uma responde planned: true. Nada enviado aqui é desfeito. |
soap |
soap(wsdlUrl: string, options?: SoapOptions): Promise<SoapClient> |
Um serviço SOAP pelo WSDL (buscado pelo gateway, num host do manifesto, com os imports). Cada operação vira uma função: client.read.<Operação>(args) quando só consulta, client.write.<Operação>(args) quando cria ou altera algo, com as mesmas regras de http.request e http.write. O WSDL é buscado uma vez por fatia. |
xmlToJson |
xmlToJson(xml: string): JsonValue |
Converte XML em dados simples, do mesmo jeito que uma resposta SOAP chega: para um serviço que responde com XML dentro de um texto. |
db |
LocalDatabases |
Consultas só de leitura num banco dentro da rede da loja (SQL Server, Oracle, Firebird, MySQL ou Postgres), pelo agente local que o manifesto indica em agents. O agente roda a consulta lá com o usuário só leitura dos segredos do conector; um único SELECT por chamada, e a lista local da máquina decide o que ele alcança. |
secret |
secret(name: string): string |
Uma referência a um segredo do manifesto. O gateway troca a referência pelo valor na saída; o código nunca vê o valor. |
state |
ConnectorState |
Memória que sobrevive entre fatias e entre execuções. Uma execução começa de onde a última que terminou bem (com sucesso ou parcial) parou. |
log |
log(message: string, data?: JsonValue, level?: LogLevel): void |
Registra uma linha nos passos da execução, com dados opcionais. Dados pessoais são mascarados. |
shouldYield |
shouldYield(): boolean |
Fica true quando a fatia está perto do fim: guarde o cursor em ctx.state e devolva { done: false } para continuar na próxima fatia. |
mode |
RunMode |
live aplica as escritas; dry_run (o ensaio) as registra como planejadas. Leituras externas são de verdade nos dois. |
quarantine |
quarantine(record: JsonValue, reason: string): void |
Separa um registro em vez de movê-lo, com o motivo, para uma pessoa revisar depois; a execução segue com o próximo e termina partial. Use para dado que o outro lado recusa (um 4xx) ou que não dá para mapear (CPF/CNPJ faltando, código de produto desconhecido). Há um teto de registros por fatia, e cada um conta para o limite de tamanho do log. |
count |
count(object: string, kind: CountKind, amount?: number): void |
Conta o que aconteceu com os registros de um objeto nesta execução (pedidos, clientes, produtos): lidos na origem, criados ou atualizados do outro lado, ignorados (nada a mudar) ou com falha. O resumo da execução são essas contagens, por objeto e tipo. |
input |
JsonValue | null |
O que iniciou a execução. No reprocesso da quarentena, { quarantined: [{ id, record, reason }] } com os registros escolhidos; numa execução do cron, manual ou de ensaio, null. |
ConnectorState
Seção intitulada “ConnectorState”Guardado entre fatias e execuções.
| Membro | Tipo | Descrição |
|---|---|---|
get |
get(key: string): JsonValue | undefined |
Lê um valor guardado. Guarde aqui o cursor da origem (a data da última alteração lida, a última chave) e zere o que só uma execução usa (uma página). |
set |
set(key: string, value: JsonValue): void |
Guarda um valor JSON para a próxima fatia e para a próxima execução. |
RunMode
Seção intitulada “RunMode”live (produção) ou dry_run (ensaio).
type RunMode = 'live' | 'dry_run';CountKind
Seção intitulada “CountKind”O tipo de contagem de ctx.count: lidos, criados, atualizados, ignorados ou com falha.
type CountKind = 'read' | 'created' | 'updated' | 'skipped' | 'failed';LogLevel
Seção intitulada “LogLevel”Nível de uma linha de ctx.log: info (o padrão), warn ou error; warn e error ficam marcados para quem lê a execução.
type LogLevel = 'info' | 'warn' | 'error';HttpRequest
Seção intitulada “HttpRequest”Uma chamada HTTP de ctx.http.request ou ctx.http.write.
| Membro | Tipo | Descrição |
|---|---|---|
method |
HttpMethod |
Método HTTP. |
url |
string |
URL absoluta: https num host de hosts do manifesto, ou http(s)://host:porta de uma API de um agente do manifesto, que desce pelo túnel do agente até a rede da loja. O gateway recusa qualquer outra. |
headers |
Readonly<Record<string, string>> (opcional) |
Cabeçalhos. Use ctx.secret('NOME') no valor de um cabeçalho de autenticação. |
query |
Readonly<Record<string, string>> (opcional) |
Parâmetros da query string. |
body |
unknown (opcional) |
Um texto vai como está; qualquer outro valor vai como JSON. |
HttpResponse
Seção intitulada “HttpResponse”A resposta de uma chamada HTTP.
| Membro | Tipo | Descrição |
|---|---|---|
planned |
boolean |
true quando uma escrita não chegou ao outro sistema: no ensaio, ou numa escrita real esperando a primeira confirmação. |
status |
number |
Código HTTP da resposta. |
headers |
Readonly<Record<string, string>> |
Cabeçalhos da resposta. |
body |
string |
Corpo da resposta como texto. |
json |
json(): unknown |
O corpo interpretado como JSON. |
HttpMethod
Seção intitulada “HttpMethod”Os métodos HTTP aceitos.
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD';Banco de dados local (pelo agente)
Seção intitulada “Banco de dados local (pelo agente)”LocalDatabases
Seção intitulada “LocalDatabases”Os bancos dos agentes do manifesto.
| Membro | Tipo | Descrição |
|---|---|---|
query |
query(query: SqlQuery): Promise<SqlResult> |
Roda uma consulta só de leitura num banco dos agentes do manifesto. É de verdade também no ensaio, como toda leitura. |
SqlQuery
Seção intitulada “SqlQuery”Uma consulta de ctx.db.query.
| Membro | Tipo | Descrição |
|---|---|---|
database |
string |
O nome de um banco dos agentes do manifesto (agents[].databases[].name). |
sql |
string |
Um SELECT (ou WITH ... SELECT), nada que mude dados. Os marcadores são os do próprio banco, por posição: SQL Server @p1, @p2...; Oracle :1, :2...; Firebird e MySQL ?; Postgres $1, $2.... Pagine na própria consulta: ORDER BY uma chave e WHERE chave > última lida, com a última guardada em ctx.state. |
params |
readonly SqlParam[] (opcional) |
Os parâmetros, na ordem dos marcadores. |
maxRows |
number (opcional) |
No máximo esta quantidade de linhas (o gateway limita); se houver mais, a resposta vem com truncated: true. |
SqlParam
Seção intitulada “SqlParam”Um parâmetro da consulta. Um Date vai como data e hora; para decimal exato, data sem hora ou bytes, diga o tipo: { type: 'decimal', value: '1234.50' }, { type: 'date', value: '2026-10-31' }, { type: 'binary', value: base64 }.
type SqlParam = | string | number | boolean | null | Date | { readonly type: 'datetime' | 'date' | 'decimal' | 'binary'; readonly value: string };SqlResult
Seção intitulada “SqlResult”O resultado de uma consulta.
| Membro | Tipo | Descrição |
|---|---|---|
columns |
readonly SqlColumn[] |
As colunas, na ordem do SELECT, com o tipo de cada uma. |
rows |
readonly SqlRow[] |
As linhas, cada uma por nome de coluna. |
rowCount |
number |
Quantas linhas vieram. |
truncated |
boolean |
true quando a consulta tinha mais linhas que maxRows (ou que o tamanho de uma resposta): leia a próxima página. |
SqlColumn
Seção intitulada “SqlColumn”Uma coluna do resultado.
| Membro | Tipo | Descrição |
|---|---|---|
name |
string |
Nome (ou apelido) da coluna. |
type |
SqlColumnType |
Como os valores da coluna chegam. |
SqlColumnType
Seção intitulada “SqlColumnType”Decimais e inteiros grandes chegam como texto exato, datas e horas como texto ISO, bytes em base64.
type SqlColumnType = | 'text' | 'integer' | 'decimal' | 'float' | 'boolean' | 'date' | 'time' | 'datetime' | 'datetimeoffset' | 'binary' | 'other';Uma linha por nome de coluna. Dê um apelido único a cada coluna: nome repetido fica com o último valor.
type SqlRow = { readonly [column: string]: JsonValue };SoapOptions
Seção intitulada “SoapOptions”Opções de ctx.soap.
| Membro | Tipo | Descrição |
|---|---|---|
endpoint |
string (opcional) |
O endereço a chamar no lugar do soap:address do WSDL: https, num host do manifesto. |
port |
string (opcional) |
A porta do WSDL, pelo nome; por padrão, a primeira porta SOAP 1.1. |
headers |
Readonly<Record<string, string>> (opcional) |
Cabeçalhos HTTP de toda chamada, inclusive a busca do WSDL (um Authorization com ctx.secret). |
soapHeader |
string (opcional) |
XML que vai dentro do soap:Header de toda chamada (WS-Security, um token de sessão), com segredos como ctx.secret('NOME'). |
SoapClient
Seção intitulada “SoapClient”O cliente de um serviço SOAP.
| Membro | Tipo | Descrição |
|---|---|---|
endpoint |
string |
O endereço que o cliente chama. |
operations |
readonly string[] |
As operações da porta, por nome. |
read |
{ … } |
Operações que só consultam: de verdade também no ensaio. |
read.[operation: string] |
SoapOperation |
Uma operação de leitura, pelo nome. |
write |
{ … } |
Operações que criam, alteram ou apagam algo no outro sistema: escrita externa, planejada no ensaio. |
write.[operation: string] |
SoapOperation |
Uma operação de escrita, pelo nome. |
SoapOperation
Seção intitulada “SoapOperation”Uma operação do serviço: recebe os argumentos e devolve a resposta.
type SoapOperation = (args?: SoapArguments) => Promise<SoapResponse>;SoapArguments
Seção intitulada “SoapArguments”Os argumentos de uma operação: os campos de entrada por nome, em qualquer ordem (o cliente escreve na ordem do WSDL).
| Membro | Tipo | Descrição |
|---|---|---|
[field: string] |
JsonValue |
Um campo de entrada. |
SoapResponse
Seção intitulada “SoapResponse”A resposta de uma operação SOAP.
| Membro | Tipo | Descrição |
|---|---|---|
planned |
boolean |
true quando uma escrita não chegou ao outro sistema (ensaio, ou esperando a primeira confirmação): data vem null. |
status |
number |
Código HTTP da resposta. |
fault |
SoapFault | null |
O soap:Fault que o serviço respondeu, ou null. |
data |
JsonValue |
O conteúdo do elemento de saída da operação como dados simples, por nome de elemento, sem namespaces: todo valor é texto (converta números e datas), xsi:nil vira null, e um campo que o WSDL diz que repete é sempre uma lista. |
xml |
string |
A resposta como chegou, para o que data deixa de fora (atributos). |
SoapFault
Seção intitulada “SoapFault”Um soap:Fault.
| Membro | Tipo | Descrição |
|---|---|---|
code |
string |
Código da falha. |
message |
string |
Mensagem da falha. |
detail |
JsonValue |
Detalhe da falha, como dados simples. |
Dados e erros
Seção intitulada “Dados e erros”JsonValue
Seção intitulada “JsonValue”Qualquer valor JSON.
type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };ConnectGatewayError
Seção intitulada “ConnectGatewayError”O gateway recusou ou não completou a chamada: host fora do manifesto, segredo desconhecido, endereço bloqueado, conector pausado. O code é um dos códigos connect.* do catálogo de erros.
| Membro | Tipo | Descrição |
|---|---|---|
status |
number |
Código HTTP da recusa. |
code |
string |
Código estável do erro (ex.: connect.route_not_allowed). |
ConnectLimitError
Seção intitulada “ConnectLimitError”Um limite da execução foi atingido. O contexto lembra do erro: a execução termina com falha por esse motivo mesmo que o código capture a exceção.
| Membro | Tipo | Descrição |
|---|---|---|
reason |
LimitReason |
Qual limite foi atingido. |
LimitReason
Seção intitulada “LimitReason”Os limites que geram ConnectLimitError: chamadas, tamanho de resposta, tamanho do log, registros em quarentena.
type LimitReason = 'calls' | 'response_size' | 'log_size' | 'quarantine';