Pular para o conteúdo principal

@cactus-agents/brand

Transforma as respostas raw da API em BrandConfig limpo e tipado. Faz 3 requests em paralelo e aplica transformações.

Instalação

pnpm add @cactus-agents/brand

Uso básico

A forma recomendada é usar createBrandFromClient, que aceita um ApiClient diretamente:

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

const client = createApiClient({ baseUrl, tenant, language });
const brand = await createBrandFromClient(client, { country: 'BRA', language: 'pt-br' });

// brand.appearance.logo
// brand.features.maintenanceMode
// brand.settings.name

Uso de baixo nível (fetcher manual)

Se precisar de controle total sobre o adapter HTTP, use createBrandConfig:

import { createBrandConfig } from '@cactus-agents/brand';

const brand = await createBrandConfig({
fetcher: {
get: (path) => myHttpClient.get(path),
post: (path, body) => myHttpClient.post(path, body),
},
country: 'BRA',
language: 'pt-br',
});

API

createBrandConfig(options)

function createBrandConfig(options: CreateBrandConfigOptions): Promise<BrandConfig>;

interface CreateBrandConfigOptions {
fetcher: BrandFetcher;
country: string;
language: string;
}

interface BrandFetcher {
get(path: string): Promise<unknown>;
post(path: string, body: unknown): Promise<unknown>; // body é OBRIGATÓRIO
}

:::caution post exige body No BrandFetcher, o segundo parâmetro de post não é opcional. Um adapter escrito como post: (path) => ... não satisfaz a interface. Passe {} quando não há corpo. :::

Faz 3 requests em paralelo:

  • GET /appearance
  • GET /bff/features
  • POST /bookmaker-settings

selectByCountry(items, country)

Seleciona item de um array multi-país:

selectByCountry(items, 'BRA')
// 1. Exact match: item.country.code === 'BRA'
// 2. Default: item.is_default === 1
// 3. Fallback: items[0]

safeParseJson(raw, fallback)

Parse seguro de JSON strings (muitos campos da API vêm como JSON string):

safeParseJson('{"key": "value"}', {}) // { key: "value" }
safeParseJson('invalid', {}) // {}
safeParseJson(null, []) // []

bool(v)

Coerce 0 | 1 | nullboolean:

bool(1) // true
bool(0) // false
bool(null) // false

Transformações aplicadas

RawTransformado
Banners {"1":{...}} ou []Banner[] sorted by order
Links duplicados (LINK_TO_X)Último entry vence
JSON strings (auth_configs, contacts, etc.)Objetos parseados
Flags 0 | 1boolean
Arrays multi-paísFiltrado por selectByCountry
26 campos sem consumidorPodados — não aparecem no BrandConfig

Campos podados (slim 2026-07-15)

O commit 116c234 removeu 26 campos dos três transforms (transform/appearance.ts, transform/features.ts, transform/settings.ts) porque não tinham consumidor e viajavam no turbo-stream de toda página + em todos os tiers de cache.

O raw do BFF continua enviando esses campos — a poda é só do lado transformado. Reativar exige descomentar em packages/types/src/brand.ts e no transform correspondente. Lista completa dos 26 e detalhes em types.

Isso é a assimetria mais fácil de tropeçar neste pacote: ver o campo no payload da API não significa que ele existe no BrandConfig.

Raw Types

O pacote exporta raw types para referência (RawAppearance, RawFeatures, RawFeaturesResponse, RawSettings). Representam as shapes verbatim da API e nunca devem ser usados na UI — use apenas BrandConfig e seus sub-tipos.