AI Connect/Reference/Referência da API
Referência da API
Referencie o client Vinkius, as APIs fluent e de baixo nível, o contrato de capabilities, erros, retries, hooks e utilitários.
Vinkius é o ponto de entrada com escopo de aplicação. Use seus handles fluentes nos fluxos de usuários, conectores, credenciais e capacidades. Use os clientes de baixo nível quando precisar de operações diretas sobre recursos.
import { Vinkius } from '@vinkius/connect';
const vinkius = new Vinkius({
appId: process.env.VINKIUS_APP_ID!,
apiKey: process.env.VINKIUS_APP_KEY!,
});
const user = vinkius.user('alice_123'); // No request.
const github = user.connector('github'); // No request.
await github.connect();
await github.credentials.set({ GITHUB_TOKEN: process.env.GITHUB_TOKEN! });
const capabilities = await github.capabilities();Exportações do pacote
Pacote raiz
Importe estes valores de @vinkius/connect:
| Categoria | Exportações |
|---|---|
| Cliente e handles fluentes | Vinkius, UserContext, Connector, CredentialsHandle, Capability, CapabilitySet |
| Clientes de baixo nível | CatalogClient, AppUsersClient, ConnectionsClient, CredentialsClient, ExecutionClient |
| Infraestrutura | ResolverCache, VERSION |
| Erros | VinkiusError, ConfigError, AuthError, NotFoundError, ValidationError, RateLimitError, QuotaError, OverageError, ConnectorNotConnectedError, NotImplementedError, ConnectionError |
O pacote raiz também exporta estes tipos:
| Categoria | Exportações |
|---|---|
| Cliente e execução | VinkiusOptions, RequestOptions, ExecuteOptions, Hooks, CapabilityExecutor, CapabilityQuery |
| Entradas de baixo nível | CreateAppUserInput, UpdateAppUserInput, CreateConnectionInput, SetCredentialsInput, ExecuteCapabilityInput |
| Recursos | AppUser, Connection, CatalogConnector, CatalogConnectorDetail, CredentialType, CredentialField, CredentialSchema, CredentialStatus |
| Capacidades | ConnectorStatus, ConnectorSummary, CapabilityResult, CapabilityData, JSONSchema |
| Paginação e primitivos | Paginated, PageMeta, PageLinks, ISODate |
| Erros | VinkiusErrorCode |
HttpClient, os componentes internos de retentativa, os helpers de ocultação de dados e os helpers compartilhados entre adapters não são exportações do pacote raiz. Embora as classes de cliente de baixo nível sejam exportadas, seus construtores exigem o tipo interno HttpClient. Obtenha instâncias por meio de vinkius.catalog, vinkius.users e das fábricas com escopo descritas abaixo.
Subpaths do pacote
| Subpath | Exportações públicas |
|---|---|
@vinkius/connect/openai | toOpenAITools, runOpenAIToolCall, OpenAIFunctionTool, OpenAIToolCall |
@vinkius/connect/anthropic | toAnthropicTools, runAnthropicToolUse, AnthropicTool, AnthropicToolUse |
@vinkius/connect/ai-sdk | toAISDKTools, AISDKTool, ToAISDKOptions |
@vinkius/connect/gemini | toGeminiTools, runGeminiFunctionCall, GeminiFunctionDeclaration, GeminiFunctionCall |
@vinkius/connect/langchain | toLangChainTools, LangChainToolFactory, ToLangChainOptions |
@vinkius/connect/json-schema | toJSONSchemaTools, executeByName, JSONSchemaTool |
@vinkius/connect/openai-agents | toOpenAIAgentsTools, OpenAIAgentsToolFactory, ToOpenAIAgentsOptions |
@vinkius/connect/llamaindex | toLlamaIndexTools, LlamaIndexToolFactory, ToLlamaIndexOptions |
@vinkius/connect/workers-ai | toWorkersAITools, WorkersAITool |
@vinkius/connect/package.json | Metadados do pacote |
O pacote publica pontos de entrada ESM e CommonJS, declara não ter efeitos colaterais e exige Node.js 18 ou posterior.
Crie um cliente
new Vinkius(options: VinkiusOptions)| Opção | Padrão | Comportamento |
|---|---|---|
appId | Obrigatório | Deve ser uma string que comece com vk_app_, mas não com vk_app_sk_. Enviado como x-vinkius-app-id. |
apiKey | Obrigatório | Deve ser uma string que comece com vk_app_sk_. Enviado como token Bearer. Mantenha-o no servidor. |
baseUrl | https://api.vinkius.com | Interpretado como uma URL e normalizado sem barras ao final. Uma URL inválida lança ConfigError. http:// fora de ambiente local emite um aviso no console, mas não é rejeitado. |
timeoutMs | 30000 | Timeout da parte de fetch de cada tentativa. Não é um prazo total para a operação. |
maxRetries | 2 | Número máximo de tentativas adicionais para requisições seguras para retentativa. |
fetch | globalThis.fetch | Implementação de fetch personalizada. A ausência de uma função global ou personalizada lança ConfigError. |
userAgent | nenhum | Acrescentado ao user agent do SDK. |
hooks | nenhum | Callbacks síncronos e com dados ocultados para requisições e respostas. |
namespaceCapability | (connector, name) => \${connector}__\${name}` | Produz o nome de exibição de cada capacidade. |
As requisições incluem Authorization: Bearer <apiKey>, x-vinkius-app-id, Accept: application/json e o user agent do SDK. Requisições com corpo também incluem Content-Type: application/json.
Crie um handle de usuário lazy
const user = vinkius.user('alice_123');user() não faz nenhuma requisição. externalId deve ser o ID estável do usuário na sua aplicação, não um ID interno da Vinkius iniciado por vk_app_user_. Deve conter de 1 a 255 caracteres e não pode conter espaços em branco, / nem barras invertidas. Valores inválidos lançam ConfigError.
Opções de requisição
A maioria dos métodos que realiza requisições aceita RequestOptions. A execução de capacidades aceita ExecuteOptions.
interface RequestOptions {
signal?: AbortSignal;
}
interface ExecuteOptions extends RequestOptions {
idempotencyKey?: string;
}UserContext.ensure(metadata?) é a exceção: ele não aceita RequestOptions. Helpers de dispatch dos adapters e callbacks gerados pelos adapters também não aceitam ExecuteOptions.
Use uma idempotencyKey estável e não vazia para a mesma execução lógica de uma capacidade e reutilize-a somente ao repetir manualmente essa mesma operação.
API fluente
Resolução lazy
const user = vinkius.user('alice_123');
const connector = user.connector('github');
const credentials = connector.credentials;Essas instruções não fazem requisições. Um Connector resolve sua conexão apenas quando uma operação precisa dela, comparando connection.slug ou connection.id com o slug do handle. O ID da conexão resolvida é memoizado somente nesse handle. connect() armazena o ID da conexão retornada; disconnect() o limpa depois da exclusão.
UserContext
class UserContext {
readonly externalId: string;
ensure(metadata?: Record<string, unknown>): Promise<AppUser>;
get(options?: RequestOptions): Promise<AppUser>;
connector(slug: string): Connector;
connectors(options?: RequestOptions): Promise<ConnectorSummary[]>;
capabilities(options?: CapabilityQuery): Promise<CapabilitySet>;
}ensure() realiza o upsert idempotente do usuário; chamar apenas user() não cria um usuário. connectors() retorna apenas conexões existentes ({ slug, status, connectionId? }).
Um array include não vazio em capabilities() é enviado ao servidor como um único valor de consulta connector separado por vírgulas; exclude é aplicado no cliente depois da resposta. As capacidades retornadas são executáveis e carregam o conector e o ID da conexão fornecidos pelo endpoint agregado.
Connector
class Connector {
readonly slug: string;
readonly credentials: CredentialsHandle;
connect(options?: RequestOptions): Promise<Connection>;
disconnect(options?: RequestOptions): Promise<void>;
status(options?: RequestOptions): Promise<ConnectorStatus>;
capabilities(options?: RequestOptions): Promise<CapabilitySet>;
}connect() é explicitamente seguro para retentativas e memoiza o ID da conexão retornada. status() retorna not_connected em vez de lançar quando não existe conexão. disconnect() e capabilities() exigem uma conexão e lançam ConnectorNotConnectedError quando a resolução não encontra nenhuma.
ConnectorStatus é derivado da seguinte forma:
| Valor | Condição |
|---|---|
not_connected | Não existe conexão correspondente. |
ready | connection.status === 'active' e connection.ready === true. |
needs_credentials | connection.status === 'active' e connection.ready !== true. |
disabled | connection.status !== 'active'. |
CredentialsHandle
class CredentialsHandle {
schema(options?: RequestOptions): Promise<CredentialSchema>;
status(options?: RequestOptions): Promise<CredentialStatus>;
set(
values: Record<string, string>,
options?: RequestOptions,
): Promise<CredentialStatus>;
}schema() lê a entrada do catálogo e não exige uma conexão existente. status() e set() nunca conectam implicitamente: eles resolvem primeiro uma conexão existente e lançam ConnectorNotConnectedError quando nenhuma é encontrada.
Os valores das credenciais são somente para escrita. As respostas de credenciais contêm um schema e booleanos indicando as chaves configuradas, nunca os valores das credenciais:
interface CredentialStatus {
schema: CredentialSchema;
configured: Record<string, boolean>;
}O set() fluente aceita um mapa simples e o envolve no envelope de baixo nível { credentials: values }. O cliente não valida os valores em relação ao schema antes de enviá-los.
Capacidades
CapabilitySet
CapabilitySet estende Array<Capability>. Os métodos padrão de arrays estão disponíveis.
class CapabilitySet extends Array<Capability> {
static fromCapabilities(
capabilities: readonly Capability[],
): CapabilitySet;
forConnector(slug: string): CapabilitySet;
findCapability(name: string): Capability | undefined;
}forConnector() usa uma correspondência exata do slug do conector. findCapability() retorna a primeira correspondência exata com o nome de exibição que inclui namespace ou com o nome bruto do conector. Nomes brutos podem colidir entre conectores; prefira nomes de exibição ou primeiro restrinja o escopo:
const issue = capabilities
.forConnector('github')
.findCapability('create_issue');Capability
class Capability {
readonly connector: string;
readonly connectionId: string;
readonly name: string;
readonly rawName: string;
readonly title: string | null;
readonly description: string;
readonly inputSchema: JSONSchema;
execute(
args?: Record<string, unknown>,
options?: ExecuteOptions,
): Promise<CapabilityResult>;
}| Propriedade | Significado |
|---|---|
connector | Slug do conector associado à capacidade. |
connectionId | Conexão usada para rotear a execução. |
name | Nome de exibição produzido por namespaceCapability. |
rawName | Nome exposto pelo conector e enviado para execução. |
title | Título opcional, normalizado como null. |
description | Descrição, normalizada como uma string vazia quando ausente. |
inputSchema | JSON Schema de entrada, normalizado como {} quando ausente. |
A execução sempre é roteada com connectionId e rawName, não com o nome de exibição. Capability é exportada, mas a interface de inicialização do seu construtor não é uma exportação do pacote: trate as capacidades como objetos produzidos pelo SDK em vez de construí-las manualmente.
interface CapabilityResult {
content: Array<{ type: string; text: string }>;
isError: boolean;
}isError: true é um resultado de capacidade retornado, não uma exceção lançada. Falhas de HTTP, transporte, configuração, resolução de conector e dispatch de adapter ainda podem lançar exceções.
Clientes de baixo nível
Use as instâncias e fábricas expostas:
const catalog = vinkius.catalog;
const users = vinkius.users;
const connections = users.connections('alice_123');
const credentials = connections.credentials(connectionId);
const execution = connections.execution(connectionId);As chamadas às fábricas não fazem requisições. Os métodos de baixo nível retornam formatos de recursos ou de capacidades brutas em vez de handles fluentes, salvo indicação em contrário.
CatalogClient
class CatalogClient {
list(
options?: { page?: number } & RequestOptions,
): Promise<Paginated<CatalogConnector>>;
get(
slug: string,
options?: RequestOptions,
): Promise<CatalogConnectorDetail>;
search(
query: string,
options?: RequestOptions,
): Promise<CatalogConnector[]>;
}list() é baseado em páginas. get() aceita um slug de conector ou ID de catálogo e retorna credential_schema. search() envia q e retorna o array de dados normalizado; a filtragem depende do suporte do servidor a q.
AppUsersClient
class AppUsersClient {
create(
input: CreateAppUserInput,
options?: RequestOptions,
): Promise<AppUser>;
get(externalId: string, options?: RequestOptions): Promise<AppUser>;
update(
externalId: string,
patch: UpdateAppUserInput,
options?: RequestOptions,
): Promise<AppUser>;
delete(externalId: string, options?: RequestOptions): Promise<void>;
list(
options?: { status?: string; page?: number } & RequestOptions,
): Promise<Paginated<AppUser>>;
capabilities(
externalId: string,
options?: { connectors?: string[] } & RequestOptions,
): Promise<CapabilityData[]>;
connections(externalId: string): ConnectionsClient;
}create() é um upsert por ID externo explicitamente seguro para retentativas. capabilities() retorna CapabilityData[] brutos, não objetos Capability executáveis; use user.capabilities() para obter a forma fluente e executável.
ConnectionsClient
class ConnectionsClient {
list(options?: RequestOptions): Promise<Connection[]>;
create(
input: CreateConnectionInput,
options?: RequestOptions,
): Promise<Connection>;
get(
connectionId: string,
options?: RequestOptions,
): Promise<Connection>;
delete(
connectionId: string,
options?: RequestOptions,
): Promise<void>;
credentials(connectionId: string): CredentialsClient;
execution(connectionId: string): ExecutionClient;
}create() é uma operação get-or-create explicitamente segura para retentativas. list() retorna um array simples.
CredentialsClient
class CredentialsClient {
status(options?: RequestOptions): Promise<CredentialStatus>;
set(
input: SetCredentialsInput,
options?: RequestOptions,
): Promise<CredentialStatus>;
}
interface SetCredentialsInput {
credentials: Record<string, string>;
}O método de baixo nível exige o envelope que o handle fluente adiciona para você:
await connections.credentials(connection.id).set({
credentials: { GITHUB_TOKEN: process.env.GITHUB_TOKEN! },
});ExecutionClient
class ExecutionClient {
list(options?: RequestOptions): Promise<CapabilityData[]>;
execute(
input: ExecuteCapabilityInput,
options?: ExecuteOptions,
): Promise<CapabilityResult>;
}
interface ExecuteCapabilityInput {
name: string;
arguments?: Record<string, unknown>;
}name é o nome bruto da capacidade do conector. Este é o único método de baixo nível que aceita ExecuteOptions.
Tipos de entrada e de recursos
interface CreateAppUserInput {
external_id: string;
status?: string;
metadata?: Record<string, unknown>;
}
interface UpdateAppUserInput {
status?: string;
metadata?: Record<string, unknown>;
}
interface CreateConnectionInput {
connector: string;
}
interface SetCredentialsInput {
credentials: Record<string, string>;
}
interface ExecuteCapabilityInput {
name: string;
arguments?: Record<string, unknown>;
}
type ISODate = string;
type JSONSchema = Record<string, unknown>;
interface AppUser {
id: string;
external_id: string;
status: string;
metadata: Record<string, unknown> | null;
application_id?: string;
mcp_count?: number;
created_at: ISODate;
updated_at: ISODate;
}
interface Connection {
id: string;
slug: string | null;
name: string;
description: string | null;
status: string;
ready: boolean;
tokens_count?: number;
created_at: ISODate;
}
interface CatalogConnector {
id: string;
slug: string;
title: string;
short_description: string | null;
publisher_type: string;
listing_type: string;
requires_buyer_auth: boolean;
server_type?: string;
tools_count?: number;
}
interface CatalogConnectorDetail extends CatalogConnector {
credential_schema: CredentialSchema;
}
type CredentialType =
| 'api_key'
| 'token'
| 'password'
| 'connection_string'
| 'string'
| 'number'
| 'email'
| 'url'
| 'select'
| 'boolean'
| 'oauth2';
interface CredentialField {
type: CredentialType;
label?: string;
required?: boolean;
group?: string;
docs_url?: string;
placeholder?: string;
allowed?: string[];
}
type CredentialSchema = Record<string, CredentialField>;
interface CapabilityData {
name: string;
title?: string | null;
description?: string | null;
input_schema?: JSONSchema | null;
annotations?: unknown;
connector?: string;
connection_id?: string;
}
interface Paginated<T> {
data: T[];
meta?: PageMeta;
links?: PageLinks;
}
interface PageMeta {
current_page: number;
from: number | null;
last_page: number;
path: string;
per_page: number;
to: number | null;
total: number;
}
interface PageLinks {
first: string | null;
last: string | null;
prev: string | null;
next: string | null;
}Endpoints de listas simples aceitam um array simples ou um objeto com data; formatos inesperados são normalizados como um array vazio. Endpoints paginados esperam { data, meta?, links? }, normalizam um campo data ausente ou que não seja um array como um array vazio e mantêm valores truthy de meta e links.
Hooks e ocultação de dados
interface Hooks {
onRequest?: (info: {
method: string;
url: string;
headers: Record<string, string>;
}) => void;
onResponse?: (info: {
status: number;
url: string;
requestId?: string;
body: unknown;
}) => void;
}Os hooks são executados de forma síncrona e não são aguardados; se um hook lançar uma exceção, ela se propaga e interrompe o fluxo da requisição.
Hook de requisição. onRequest é executado antes de cada tentativa com a URL completa da requisição e uma cópia do mapa de cabeçalhos. Ele não recebe o corpo da requisição, e as URLs não são ocultadas. Os nomes dos cabeçalhos são comparados de forma exata, sem diferenciar maiúsculas de minúsculas; estes valores se tornam [REDACTED]: authorization, idempotency-key, cookie, set-cookie. Nenhum outro cabeçalho é ocultado por heurística.
Hook de resposta. onResponse é executado em cada tentativa que retorna uma resposta HTTP, inclusive uma resposta transitória que será repetida. Ele não é executado em caso de falha de fetch ou timeout sem resposta. Um corpo vazio é undefined; JSON válido é interpretado; texto que não seja JSON permanece como string. As chaves dos objetos da resposta são comparadas de forma exata, sem diferenciar maiúsculas de minúsculas; estes valores se tornam [REDACTED]: authorization, apikey, api_key, token, access_token, refresh_token, mcp_url, credentials, password, secret, client_secret. Não há detecção de segredos por substring nem pelo formato. Objetos na profundidade 6 se tornam [TRUNCATED]; referências repetidas ou circulares se tornam [CIRCULAR]. A ocultação cria uma cópia para os hooks e não reescreve VinkiusError.details.
Timeouts, retentativas e idempotência
Escopo do timeout. Cada tentativa recebe um novo timer de timeoutMs cobrindo a promise de fetch. Ele é limpo antes da leitura do corpo da resposta e não cobre response.text() nem o backoff da retentativa, portanto as retentativas não compartilham um único prazo total. Passe signal para cancelamento controlado pelo chamador: um cancelamento pelo chamador durante o fetch não é repetido e normalmente se torna ConnectionError.
Política de retentativas. Com os valores padrão, uma operação segura para retentativas faz no máximo três tentativas. Uma operação é segura para retentativas quando seu método HTTP é GET, PUT ou DELETE, ou quando o SDK a marca explicitamente como segura para retentativas: criação de usuário, criação de conexão ou execução de capacidade com uma idempotencyKey definida. Operações seguras para retentativas são repetidas após um erro de rede, um timeout por tentativa ou HTTP 429, 502, 503 ou 504. Requisições PATCH e POST comuns não são repetidas.
O backoff usa jitter completo sobre uma janela exponencial: 250 ms inicialmente, com limite de 4.000 ms. Retry-After (segundos de atraso ou uma data HTTP) tem precedência, também com limite de 4.000 ms. maxRetries altera a quantidade de retentativas, não esses valores de atraso.
Erros e IDs de requisição
class VinkiusError extends Error {
readonly status: number;
readonly code: VinkiusErrorCode;
readonly requestId: string | undefined;
readonly details: unknown;
}Erros do cliente e de transporte usam status 0. Falhas HTTP terminais incluem a resposta da API interpretada em details.
| Classe | code | Origem | Campos adicionais |
|---|---|---|---|
ConfigError | config_error | Configuração do cliente ou ID externo inválido | nenhum |
AuthError | auth_error | HTTP 401 ou 403 | nenhum |
NotFoundError | not_found | HTTP 404 | nenhum |
ValidationError | validation_error | HTTP 422 | errors: Record<string, string[]> |
RateLimitError | rate_limit | HTTP 429 sem o formato de quota de capacidades | retryAfterMs?: number |
QuotaError | quota_exceeded | HTTP 429 com isError: true ou um upgrade_url | upgradeUrl?: string |
OverageError | overage_blocked | HTTP 402 | upgradeUrl?: string |
ConnectorNotConnectedError | connector_not_connected | Uma operação fluente exige uma conexão ausente | nenhum |
ConnectionError | connection_error | Falha de rede, timeout ou cancelamento pelo chamador durante o fetch | nenhum |
VinkiusError | api_error | Outro status HTTP sem sucesso | nenhum |
Para respostas HTTP, o cliente lê o primeiro ID de requisição não vazio de x-request-id e, em seguida, x-vinkius-request-id. O valor chega a onResponse e ao erro HTTP final mapeado; valores de recursos bem-sucedidos não o incluem. Erros do cliente e de transporte normalmente não têm ID de requisição. Consulte Error handling para conhecer padrões de fluxo de controle.
ResolverCache
ResolverCache é um cache TTL independente em memória para dados estáveis e não secretos. O cliente não o usa internamente.
class ResolverCache {
constructor(ttlMs?: number); // Default: 5 minutes.
get<V>(key: string): V | undefined;
set<V>(key: string, value: V): void;
delete(key: string): void;
clear(): void;
resolve<V>(key: string, compute: () => Promise<V>): Promise<V>;
}import { ResolverCache } from '@vinkius/connect';
const cache = new ResolverCache(10 * 60 * 1000);
const schema = await cache.resolve('github:schema', () =>
user.connector('github').credentials.schema(),
);Entradas expiradas são excluídas em get(). resolve() calcula e armazena um valor ausente somente depois que a promise é cumprida; rejeições não são armazenadas em cache e ausências simultâneas não são aglutinadas. Um undefined armazenado é indistinguível de uma ausência. Não armazene em cache credenciais, tokens, cabeçalhos de autorização ou outros segredos: o cache é uma otimização, não uma fonte de autorização.
Referência dos adapters
Todos os adapters aceitam readonly Capability[] e usam os nomes de exibição das capacidades nas definições geradas. Um schema de entrada vazio é normalizado para { type: 'object', properties: {} }. Os adapters não validam localmente os argumentos das capacidades; a validação pertence ao serviço chamado.
Os helpers de dispatch e os callbacks de execução gerados chamam capability.execute(args) sem ExecuteOptions: eles não podem receber um signal nem uma chave de idempotência. Chame Capability.execute(args, options) ou ExecutionClient.execute(input, options) diretamente quando precisar de cancelamento ou execução segura para retentativas.
toOpenAITools(capabilities)retornaOpenAIFunctionTool[];runOpenAIToolCall(capabilities, call)corresponde apenas ao nome de exibição. Strings de argumentos JSON vazias, malformadas,nullou primitivas se tornam{}; um nome desconhecido lança umErrorsimples.toAnthropicTools/runAnthropicToolUse: correspondência apenas pelo nome de exibição; nomes desconhecidos lançam umErrorsimples.toAISDKTools(capabilities, { jsonSchema? })retorna um registro indexado pelo nome de exibição; um nome de exibição duplicado sobrescreve a entrada anterior. Sem o wrapper injetado,parametersé o JSON Schema bruto normalizado. Cadaexecute(args)gerado retornaCapabilityResult.toGeminiTools/runGeminiFunctionCall: argumentos ausentes se tornam{}; nomes desconhecidos lançam umErrorsimples.toLangChainTools(capabilities, { tool })etoOpenAIAgentsTools(capabilities, { tool })exigem a fábrica do chamador e são genéricos em relação ao seu tipo de retorno. Os callbacks gerados unem as partes de texto do resultado com uma nova linha e não preservamisErrornem os tipos das partes de conteúdo. O adapter de Agents passa o JSON Schema bruto normalizado comstrict: false.toLlamaIndexTools(capabilities, { tool })aceita JSON Schema bruto, portanto não é necessário Zod.toWorkersAITools(capabilities)retorna objetos simples com funções de execução vinculadas.toJSONSchemaTools(capabilities)emite{ name, description, parameters };executeByName(capabilities, name, args)corresponde ao nome de exibição ou ao nome bruto, com ambiguidade da primeira correspondência para nomes brutos duplicados. Nomes desconhecidos lançam umErrorsimples.
Próximos passos
- Compare os framework adapters.
- Siga os padrões de fluxo de controle de error handling.
- Explore as recipes para padrões de integração focados.
