Pular para o conteúdo principal

Services

O template separa serviços server-side (.server.ts) e client-side (.client.ts).

api.server.ts — ApiClient SSR

Cria um ApiClient sem token, usado pelo loader para carregar brand config.

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

export function createClient(env: Record<string, string>) {
return createApiClient({
baseUrl: env.API_BASE_URL,
tenant: env.ORIGIN_DOMAIN,
language: env.BRAND_LANGUAGE,
});
}

brand.server.ts — Brand Loading

Carrega a configuração de marca no server:

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

export async function loadBrandConfig(env: Record<string, string>) {
const client = createClient(env);
const country = env.BRAND_COUNTRY;
const language = env.BRAND_LANGUAGE;
return createBrandFromClient(client, { country, language });
}

auth.client.ts — AuthService Singleton

Singleton que inicializa o AuthService com um ApiClient client-side:

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

let service: AuthService | null = null;

export function initAuthService(env: Record<string, string>) {
const client = createApiClient({
baseUrl: env.API_BASE_URL,
tenant: env.ORIGIN_DOMAIN,
language: env.BRAND_LANGUAGE,
});

service = createAuthFromClient(client);
}

export function getAuthService(): AuthService {
if (!service) throw new Error('AuthService not initialized');
return service;
}

user.client.ts — UserService Singleton

Singleton que inicializa o UserService com um ApiClient client-side. Deve ser inicializado após o usuário estar autenticado:

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

let service: UserService | null = null;

export function initUserService(env: ClientEnv): UserService {
const client = createApiClient({
baseUrl: env.API_BASE_URL,
tenant: env.ORIGIN_DOMAIN,
language: env.BRAND_LANGUAGE,
});

service = createUserFromClient(client);
return service;
}

export function getUserService(): UserService {
if (!service) throw new Error('UserService not initialized');
return service;
}

Os componentes da área do usuário fazem import('~/services/user.client') via dynamic import para garantir code-splitting — o bundle do UserService só é carregado quando o usuário está logado e acessa as páginas da conta.

Separação de serviços

ArquivoContextoTokenUso
api.server.tsServer (loader)NãoBrand loading, config
auth.client.tsClient (browser)Sim (via Zustand)Login, profile, refresh
user.client.tsClient (browser)Sim (via ApiClient)Perfil, segurança, limites, IRPF, wallet

Essa separação é intencional: o server não tem acesso ao token do usuário (que está no cookie/store client-side). Os serviços client-side são singletons inicializados sob demanda.