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
| Arquivo | Contexto | Token | Uso |
|---|---|---|---|
api.server.ts | Server (loader) | Não | Brand loading, config |
auth.client.ts | Client (browser) | Sim (via Zustand) | Login, profile, refresh |
user.client.ts | Client (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.