Pular para o conteúdo principal

@cactus-agents/api-client

HTTP client framework-agnostic baseado em fetch. Gerencia headers de tenant, idioma, autorização e callbacks de erro.

Instalação

pnpm add @cactus-agents/api-client

Uso básico

import { createApiClient } from '@cactus-agents/api-client';

const client = createApiClient({
baseUrl: 'https://api.example.com/v2',
tenant: 'my-tenant',
language: 'pt-br',
});

const response = await client.get<MyData>('/endpoint');
// response.data, response.status, response.headers

ApiClientConfig

interface ApiClientConfig {
baseUrl: string; // URL base da API
tenant: string; // Header tenant
language: string; // Idioma fallback

// Opcionais
buildId?: string; // ID do build
debug?: boolean; // Habilita header DEBUG

// Callbacks de dados
getAccessToken?: () => string | null;
getLocale?: () => string;
getOriginAccess?: () => OriginAccess;
getReferrerInfo?: () => ReferrerInfo | null;
getExtraHeaders?: () => Record<string, string>;

// Hooks de erro
onUnauthorized?: (url: string) => void; // 401
onChallenge?: () => void; // 429
onTimeoutLimit?: (url: string) => void; // 202
}

Métodos

MétodoDescrição
get<T>(path)GET com headers internos
post<T>(path, payload?)POST com headers internos
put<T>(path, payload?)PUT com headers internos
patch<T>(path, payload?)PATCH com headers internos
delete<T>(path, payload?)DELETE com headers internos
getExternal<T>(url)GET para URLs externas (sem headers internos)

Headers automáticos

Em toda request interna (external !== true), o client adiciona:

HeaderConteúdo
tenant, origin-domainconfig.tenant
lang / languagegetLocale() ou config.language
versionvz3b-{buildId} (ou vm se sem buildId)
X-LOG-INFO1-{Date.now()}-{buildId} — formato textual estável usado por tracing server-side
Authorization: Bearer {token}se getAccessToken() retorna token
X-ORIGIN-ACCESSse getOriginAccess() retorna valor ≠ Unknown
X-ORIGIN-REFERRERgetReferrerInfo()?.referrer (URL do referrer first-touch)
X-ORIGIN-HOSTNAMEgetReferrerInfo()?.hostname
X-ORIGIN-CINFO-IDgetReferrerInfo()?.cinfoId (vindo de X-INFOS-ID que o BFF retorna em login/register)
X-ORIGIN-CINFO-ID-REFgetReferrerInfo()?.cinfoIdRef (vindo de X-INFOS-REF)

O bloco X-ORIGIN-* faz parte do tracking de marketing/atribuição — ver Marketing Tracking pra fluxo end-to-end de captura, política de atribuição e payloads associados.

Tratamento de status

StatusComportamento
200-299Resolve com ApiResponse<T>
202Resolve (não throw) + chama onTimeoutLimit
401Chama onUnauthorized + throw
429Chama onChallenge + throw
Outros non-okThrow

ApiResponse

interface ApiResponse<T> {
data: T;
status: number;
statusText: string;
headers: Headers;
url?: string;
rawBody?: string;
}

OriginAccess

enum OriginAccess {
Unknown = 0,
App = 1,
Desktop = 2,
DesktopApp = 3,
Mobile = 4,
MobileApp = 5,
}

Helpers

O pacote exporta helpers de conveniência para quem consome o ApiClient junto com outros pacotes do SDK.

createFetcherFromClient(client)

Converte um ApiClient (ou qualquer objeto com get/post que retorna { data }) no formato de fetcher plano esperado por @cactus-agents/auth e @cactus-agents/brand:

import { createApiClient, createFetcherFromClient } from '@cactus-agents/api-client';
import { createAuthService } from '@cactus-agents/auth';

const client = createApiClient({ baseUrl, tenant, language });
const fetcher = createFetcherFromClient(client);
const auth = createAuthService(fetcher);

Na maioria dos casos, prefira usar createAuthFromClient ou createBrandFromClient diretamente — eles fazem essa conversão internamente.

createFullFetcherFromClient(client)

Versão estendida do createFetcherFromClient que expõe todos os 5 métodos HTTP (get, post, put, patch, delete). Usado por pacotes que precisam de mais do que get/post, como @cactus-agents/user:

import { createApiClient, createFullFetcherFromClient } from '@cactus-agents/api-client';
import { createUserService } from '@cactus-agents/user';

const client = createApiClient({ baseUrl, tenant, language });
const fetcher = createFullFetcherFromClient(client);
const user = createUserService(fetcher);

Na maioria dos casos, prefira usar createUserFromClient diretamente — ele faz essa conversão internamente.

extractApiError(err)

Normaliza erros do ApiClient (que não são instâncias de Error) em uma estrutura consistente para logging e respostas HTTP:

import { extractApiError } from '@cactus-agents/api-client';

try {
await client.post('/endpoint', body);
} catch (err) {
const { status, data, message, isApiError } = extractApiError(err);
// status: number | undefined
// data: response body (se API error)
// message: string (para logging)
// isApiError: boolean
}

Tipos

interface ClientLike {
get<T>(path: string): Promise<{ data: T }>;
post<T>(path: string, body?: unknown): Promise<{ data: T }>;
}

interface FullClientLike extends ClientLike {
put<T>(path: string, payload?: unknown): Promise<{ data: T }>;
patch<T>(path: string, payload?: unknown): Promise<{ data: T }>;
delete<T>(path: string, payload?: unknown): Promise<{ data: T }>;
}

interface ExtractedApiError {
status: number | undefined;
data: unknown;
message: string;
isApiError: boolean;
url?: string;
statusText?: string;
}

interface ReferrerInfo {
/** URL completa do `document.referrer` external (cross-host) capturado no first-touch. */
referrer: string;
/** Hostname extraído do `referrer`. */
hostname: string;
/** Eco do response header `X-INFOS-ID` recebido em login/register, persistido em cookie pelo template. */
cinfoId?: string;
/** Eco do response header `X-INFOS-REF` recebido em login/register. */
cinfoIdRef?: string;
}

ReferrerInfo carrega referrer + IDs de tracking do BFF, não UTMs. UTMs viajam apenas como campos de body em signup/deposit (ver Marketing Tracking).

createCactusServerClient

Factory de alto nível para uso em Cloudflare Workers e SSR. Encapsula toda a lógica de headers da plataforma Cactus (IP real do cliente, geo CF, cookies, auth, origin-access) para que os loaders precisem apenas passar o env e o Request de entrada.

import { createCactusServerClient } from "@cactus-agents/api-client";

// Em um loader / action:
const client = createCactusServerClient({
env: context.cloudflare.env, // ou process.env em dev local
request,
getAccessToken: () => token,
});

// Agora use normalmente com os wrappers do SDK:
const games = createGamesFromClient(client);
const brand = await createBrandFromClient(client, opts);

CactusServerClientOptions

interface CactusServerClientOptions {
env: Partial<CactusServerEnv>; // vars de ambiente
request?: Request; // Request do Worker (extrai IP, geo, cookies, UA)
cookies?: string; // override de cookies (substitui request.cookies)
getAccessToken?: () => string | null | undefined;
buildId?: string;
debug?: boolean;
getOriginAccess?: () => OriginAccess; // default: OriginAccess.Desktop
getReferrerInfo?: () => ReferrerInfo | null;

// Hooks de erro (mesmos do ApiClientConfig)
onUnauthorized?: (url: string) => void;
onChallenge?: () => void;
onTimeoutLimit?: (url: string) => void;
}

CactusServerEnv

interface CactusServerEnv {
API_BASE_URL: string;
ORIGIN_DOMAIN: string;
BRAND_LANGUAGE: string;
BRAND_COUNTRY: string; // alpha-3 (ex: "BRA")
BRAND_CURRENCY: string;
BRAND_TIMEZONE: string;
CF_WORKER_KEY?: string; // header de autenticação Worker → API (server-only, nunca expor ao browser)
}

Headers injetados automaticamente

O createCactusServerClient injeta os seguintes headers em cada requisição, além dos headers padrão do ApiClient:

HeaderOrigem
User-Agentrequest.headers["user-agent"]
S-Client-Addr, x-cac-real-ip, X-Forwarded-For, X-Real-IPCF-Connecting-IP do request
x-countryrequest.cf.country (ISO alpha-2)
x-user-info-timezonerequest.cf.timezone
x-user-info-long, x-user-info-latrequest.cf.longitude / request.cf.latitude
x-user-info-region, x-user-info-cityrequest.cf.regionCode / request.cf.city
country, country_alpha3, currency, jurisdictionDerivados das env vars da marca
Cookierequest.headers["Cookie"] (ou options.cookies)
cf-worker-keyenv.CF_WORKER_KEY (quando presente)
cuidado

CF_WORKER_KEY é um segredo server-side. Configure via wrangler secret put CF_WORKER_KEY e nunca inclua no bundle client.

RequestDebugInfo

Tipo da metadata da request capturada apenas quando debug: true no ApiClientConfig (anexada ao ApiResponse.requestInfo). Pra inspeção em DevApiDebug / DevApiExplorer. Não está relacionado ao header X-LOG-INFO, que é um string estável (1-{ts}-{buildId}).

interface RequestDebugInfo {
/** URL completa que foi chamada. */
url: string;
/** Método HTTP. */
method: string;
/** Headers enviados (Authorization e Cookie ficam mascarados como `[REDACTED]`). */
headers: Record<string, string>;
/** Body parseado, `undefined` para GET/bodyless. */
body?: unknown;
}

Exports

O pacote exporta os seguintes itens:

ExportTipoDescrição
ApiClientclassClasse do client HTTP
createApiClientfunctionFactory básica para ApiClient (client-side / testes)
createCactusServerClientfunctionFactory para Workers/SSR com headers automáticos de plataforma
createFetcherFromClientfunctionConverte ApiClient para fetcher simples (get/post)
createFullFetcherFromClientfunctionConverte ApiClient para fetcher completo (5 métodos)
extractApiErrorfunctionNormaliza erros do ApiClient
ApiClientConfigtypeConfiguração base do client
CactusServerClientOptionstypeOpções do createCactusServerClient
CactusServerEnvtypeShape das env vars esperadas pelo server client
ApiResponsetypeResposta padronizada
ExtractedApiErrortypeErro normalizado
RequestDebugInfotypeInformações de debug do request
OriginAccessenumOrigem do acesso
ReferrerInfotypeInformações de referrer/UTM
ClientLiketypeInterface mínima de client (get/post)
FullClientLiketypeInterface completa de client (5 métodos)