npm package: @infosel-sdk/core
Description: Core SDK for Infosel financial services platform. Provides essential infrastructure for authentication, HTTP/GraphQL communication, storage management, and error handling.
Author: Infosel Team
Latest version: 0.0.6

# @infosel-sdk/core

[![npm version](https://badge.fury.io/js/@infosel-sdk%2Fcore.svg)](https://badge.fury.io/js/@infosel-sdk%2Fcore)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![TypeScript](https://img.shields.io/badge/TypeScript-007ACC?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)

SDK Core para la plataforma de servicios financieros Infosel. Proporciona infraestructura esencial para autenticación, comunicación HTTP/GraphQL, gestión de almacenamiento y manejo de errores.

## 🚀 Características

- **✨ Configuration Builder Pattern**: Nueva API fluida para configuración sin duplicaciones
- **🔐 Gestión de Autenticación**: Proveedores de autenticación KeyCloak y basados en tokens
- **🌐 Cliente HTTP**: Cliente HTTP configurable con interceptores de autenticación
- **📡 Cliente GraphQL**: Cliente GraphQL basado en Apollo con utilidades de consulta
- **💾 Gestión de Almacenamiento**: Soporte para almacenamiento local, en memoria y encriptado
- **🚨 Manejo de Errores**: Sistema completo de tipos de error y gestión centralizada
- **⚙️ Gestor del SDK**: Configuración y gestión centralizada del SDK
- **🔧 Configuración de Realm**: Configuración dinámica de realm para múltiples ambientes

## 📦 Instalación

```bash
npm install @infosel-sdk/core
```

### Compatibilidad de Versiones

- **React**: >=18.0.0
- **React Native**: >=0.70.0 (opcional)
- **Node.js**: >=16.0.0
- **TypeScript**: >=4.5.0

### Dependencias Opcionales

- `react-native-encrypted-storage`: Solo necesario para aplicaciones React Native que requieran almacenamiento encriptado

## 🔧 Configuración

### ✨ Nueva Configuración con Builder Pattern (Recomendado)

La nueva API elimina la duplicación de configuración y proporciona validaciones centralizadas:

#### Autenticación KeyCloak

```typescript
import { InfoselSdkManager, AuthConfigurationBuilder } from '@infosel-sdk/core';

const authConfig = AuthConfigurationBuilder
  .keyCloak()
  .withRealm('my-realm')
  .withEnvironment('qa')
  .withCredentials({
    grant_type: 'client_credentials',
    client_id: 'my-app-client',
    client_secret: 'my-app-secret',
  })
  .build();

const sdk = InfoselSdkManager.initWithConfiguration({
  authConfiguration: authConfig,
});

console.log(sdk.getRealm()); // 'my-realm'
```

#### Autenticación con Token Existente

```typescript
import { InfoselSdkManager, AuthConfigurationBuilder, Token } from '@infosel-sdk/core';

const token: Token = {
  accessToken: 'your-access-token',
  refreshToken: 'your-refresh-token',
};

const authConfig = AuthConfigurationBuilder
  .existingToken()
  .withRealm('production-realm')
  .withEnvironment('prod')
  .withClientId('production-client')
  .withToken(token)
  .build();

const sdk = InfoselSdkManager.initWithConfiguration({
  authConfiguration: authConfig,
});
```

#### Configuración con Valores por Defecto

```typescript
import { InfoselSdkManager, AuthConfigurationBuilder } from '@infosel-sdk/core';

// Usa 'hub' como realm por defecto y 'prod' como environment
const authConfig = AuthConfigurationBuilder
  .keyCloak()
  .withCredentials({
    grant_type: 'client_credentials',
    client_id: 'my-client',
    client_secret: 'my-secret',
  })
  .build();

const sdk = InfoselSdkManager.initWithConfiguration({
  authConfiguration: authConfig,
});
```

### Configuración Legacy (Compatibilidad)

```typescript
import { InfoselSdkManager } from '@infosel-sdk/core';

const sdk = InfoselSdkManager.init({
  mode: 'qa',
  realm: 'my-realm',
  authProviderConfig: {
    type: 'key-cloak',
    credentials: {
      grant_type: 'client_credentials',
      client_id: 'my-client',
      client_secret: 'my-secret',
    },
  },
});
```

## 🔍 Validación de Configuración

El nuevo sistema incluye validaciones robustas:

```typescript
import { AuthConfigurationBuilder } from '@infosel-sdk/core';

const builder = AuthConfigurationBuilder
  .keyCloak()
  .withRealm('invalid@realm') // Caracteres inválidos
  .withCredentials({
    grant_type: 'client_credentials',
    client_id: '', // Client ID vacío
    client_secret: 'secret',
  });

// Validar antes de construir
const validation = builder.validate();
if (!validation.isValid) {
  console.log('Errores:', validation.errors);
  // ['Realm contains invalid characters...', 'Client ID is required...']
}

// O validar automáticamente al construir
try {
  const config = builder.build();
} catch (error) {
  console.error(error.message); // Lista todos los errores de validación
}
```

## 🌍 Configuración por Ambiente

```typescript
import { AuthConfigurationBuilder, Environment } from '@infosel-sdk/core';

function createSdkForEnvironment(env: Environment) {
  const baseBuilder = AuthConfigurationBuilder
    .keyCloak()
    .withEnvironment(env);
    
  if (env === 'qa') {
    return baseBuilder
      .withRealm('qa-realm')
      .withCredentials({
        grant_type: 'client_credentials',
        client_id: 'qa-client',
        client_secret: 'qa-secret',
      })
      .build();
  } else {
    return baseBuilder
      .withRealm('prod-realm')
      .withCredentials({
        grant_type: 'client_credentials',
        client_id: 'prod-client',
        client_secret: 'prod-secret',
      })
      .build();
  }
}

const qaSdk = InfoselSdkManager.initWithConfiguration({
  authConfiguration: createSdkForEnvironment('qa'),
});
```

## 💾 Almacenamiento

El SDK proporciona un sistema de almacenamiento que se adapta automáticamente según la plataforma:

### **Convención de Archivos**

- **`app_local_storage.ts`**: Implementación para Web (localStorage)
- **`app_local_storage.native.ts`**: Implementación para React Native (EncryptedStorage)

### **Uso del Almacenamiento**

```typescript
import { AppLocalStorage } from '@infosel-sdk/core';

const storage = new AppLocalStorage();

// Guardar datos
await storage.saveObject('user-data', { name: 'John', id: 123 });

// Obtener datos
const userData = await storage.getObject('user-data');

// Eliminar datos
await storage.removeObject('user-data');
```

## 🔐 Proveedores de Autenticación

### Token Auth Provider

```typescript
import { TokenAuthProvider } from '@infosel-sdk/core';

// Uso directo (para casos avanzados)
const authProvider = new TokenAuthProvider(
  'qa', // environment
  token, // Token object
  'custom-realm', // realm
  'custom-client' // clientId
);
```

### KeyCloak Auth Provider

```typescript
import { KeyCloakAuthProvider } from '@infosel-sdk/core';

// Uso directo (para casos avanzados)
const authProvider = new KeyCloakAuthProvider('qa', {
  type: 'key-cloak',
  credentials: {
    grant_type: 'client_credentials',
    client_id: 'client',
    client_secret: 'secret',
  },
  realm: 'custom-realm',
});
```

## 🌐 Cliente HTTP

```typescript
import { InfoselHttpClient } from '@infosel-sdk/core';

const httpClient = new InfoselHttpClient({
  baseURL: 'https://api.infosel.com',
  timeout: 30000,
});

// GET request
const data = await httpClient.get('/users');

// POST request
const response = await httpClient.post('/users', { name: 'John' });
```

## 🔍 Cliente GraphQL

```typescript
import { InfoselGraphQlClient, queryfy } from '@infosel-sdk/core';

const graphqlClient = new InfoselGraphQlClient({
  url: 'https://api.infosel.com/graphql',
});

// Query simple
const query = queryfy`
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }
`;

const result = await graphqlClient.query(query, { id: '123' });
```

## 🚨 Manejo de Errores

```typescript
import { SdkError, SdkErrorType } from '@infosel-sdk/core';

try {
  const data = await httpClient.get('/users');
} catch (error) {
  if (error instanceof SdkError) {
    switch (error.type) {
      case SdkErrorType.AXIOS_RESPONSE_ERROR:
        console.error('Error de respuesta HTTP:', error.message);
        break;
      case SdkErrorType.LOCAL_STORAGE_KEY_NOT_FOUND:
        console.error('Clave de almacenamiento no encontrada:', error.message);
        break;
      case SdkErrorType.INVALID_AUTH_PROVIDER_CONFIG:
        console.error('Configuración de autenticación inválida:', error.message);
        break;
      default:
        console.error('Error del SDK:', error.message);
    }
  }
}
```

## 📚 API Reference

### Clases Principales

- `InfoselSdkManager`: Gestor principal del SDK
- `AuthConfigurationBuilder`: Builder para configuraciones de autenticación
- `ConfigurationValidator`: Validador centralizado de configuraciones
- `AppLocalStorage`: Almacenamiento local adaptativo
- `InfoselHttpClient`: Cliente HTTP con interceptores
- `InfoselGraphQlClient`: Cliente GraphQL
- `TokenAuthProvider`: Proveedor de autenticación por token
- `KeyCloakAuthProvider`: Proveedor de autenticación KeyCloak

### Interfaces y Tipos

- `AuthConfiguration`: Configuración de autenticación centralizada
- `ValidationResult`: Resultado de validación con errores detallados
- `SdkConfig`: Configuración legacy del SDK (compatibilidad)
- `ModernSdkConfig`: Nueva configuración del SDK
- `Environment`: Tipo para ambientes ('qa' | 'prod')
- `AuthType`: Tipo de autenticación ('key-cloak' | 'existing-token')

### Tipos de Error

- `SdkErrorType.SDK_MANAGER_NOT_INITIALIZED`: SDK no inicializado
- `SdkErrorType.AXIOS_RESPONSE_ERROR`: Error de respuesta HTTP
- `SdkErrorType.LOCAL_STORAGE_KEY_NOT_FOUND`: Clave de almacenamiento no encontrada
- `SdkErrorType.LOCAL_STORAGE_NOT_AVAILABLE`: Almacenamiento no disponible
- `SdkErrorType.GRAPH_QL_ERROR`: Error de GraphQL
- `SdkErrorType.INVALID_AUTH_PROVIDER_CONFIG`: Configuración de autenticación inválida

## 🆕 Novedades en v0.0.4

### ✨ Configuration Builder Pattern
- **Nueva API fluida** para configuración sin duplicaciones
- **Validaciones centralizadas** con mensajes de error descriptivos
- **Single source of truth** para configuración de realm
- **Compatibilidad hacia atrás** mantenida

### 🔧 Mejoras en Configuración
- **Configuración dinámica de realm** para múltiples ambientes
- **Validación de formatos** de realm, client_id y credenciales
- **Valores por defecto inteligentes** basados en el tipo de autenticación
- **Type safety mejorado** con TypeScript

### 📖 Documentación
- **Ejemplos completos** de uso del Configuration Builder
- **Guías de migración** desde configuración legacy
- **Casos de uso avanzados** para diferentes ambientes

## 🔄 Migración desde v0.0.3

### Antes
```typescript
// ❌ Configuración duplicada
const sdk = InfoselSdkManager.init({
  mode: 'qa',
  realm: 'my-realm', // Primera definición
  authProviderConfig: {
    type: 'key-cloak',
    realm: 'my-realm', // Segunda definición (duplicada)
    credentials: { /* ... */ },
  },
});
```

### Después
```typescript
// ✅ Single source of truth
const authConfig = AuthConfigurationBuilder
  .keyCloak()
  .withRealm('my-realm') // Una sola definición
  .withEnvironment('qa')
  .withCredentials({ /* ... */ })
  .build();

const sdk = InfoselSdkManager.initWithConfiguration({
  authConfiguration: authConfig,
});
```

## 🧪 Testing

```bash
# Ejecutar tests
npm test

# Ejecutar tests con cobertura
npm run test:coverage

# Ejecutar tests específicos
npm test -- --testPathPattern="auth_configuration_builder"
```

## 🔨 Development

```bash
# Instalar dependencias
npm install

# Compilar TypeScript
npm run build

# Crear distribución
npm run build:dist
```

## 🤝 Contribución

1. Fork el proyecto
2. Crea una rama para tu feature (`git checkout -b feature/AmazingFeature`)
3. Commit tus cambios (`git commit -m 'Add some AmazingFeature'`)
4. Push a la rama (`git push origin feature/AmazingFeature`)
5. Abre un Pull Request

## 📄 Licencia

Este proyecto está bajo la Licencia MIT. Ver el archivo `LICENSE` para más detalles.

## 📞 Soporte

- **Documentación**: [Ejemplos de Configuration Builder](./CONFIGURATION_BUILDER_EXAMPLES.md)
- **Issues**: [GitHub Issues](https://github.com/infosel/am-sdks/issues)
- **Equipo**: Infosel Team

---

**Hecho con ❤️ por el equipo de Infosel**