import {
AuthAdapter,
AnyAuthConfig,
NoAuthConfig,
BasicAuthConfig,
ApiKeyAuthConfig,
BearerTokenConfig,
BearerEndpointConfig,
OAuth2ClientCredentialsConfig
} from './types.js';
import {
NoAuthAdapter,
BasicAuthAdapter,
ApiKeyAuthAdapter,
BearerTokenAdapter,
BearerEndpointAdapter,
OAuth2ClientCredentialsAdapter
} from './adapters/index.js';
/**
* Factory para crear instancias de adaptadores de autenticación
*/
export class AuthFactory {
/**
* Crea un adaptador de autenticación según la configuración proporcionada
*/
static createAdapter(config: AnyAuthConfig): AuthAdapter {
switch (config.type) {
case 'none':
return new NoAuthAdapter();
case 'basic':
return new BasicAuthAdapter();
case 'api-key':
return new ApiKeyAuthAdapter();
case 'bearer-token':
return new BearerTokenAdapter();
case 'bearer-endpoint':
return new BearerEndpointAdapter();
case 'oauth2-client-credentials':
return new OAuth2ClientCredentialsAdapter();
default:
throw new Error(`Unknown auth type: ${(config as any).type}`);
}
}
/**
* Crea e inicializa un adaptador de autenticación
*/
static async createAndInitialize(config: AnyAuthConfig, baseUrl: string): Promise<AuthAdapter> {
const adapter = this.createAdapter(config);
await adapter.initialize(config, baseUrl);
return adapter;
}
}
/**
* Manager de autenticación
* Gestiona el ciclo de vida del adaptador y el refresco automático
*/
export class AuthManager {
private adapter: AuthAdapter | null = null;
private refreshInterval: NodeJS.Timeout | null = null;
private config: AnyAuthConfig | null = null;
private baseUrl: string = '';
/**
* Inicializa el manager con la configuración de auth
*/
async initialize(config: AnyAuthConfig, baseUrl: string): Promise<void> {
this.config = config;
this.baseUrl = baseUrl;
this.adapter = await AuthFactory.createAndInitialize(config, baseUrl);
// Configurar refresco automático si el adaptador lo soporta
this.setupAutoRefresh();
}
/**
* Configura el refresco automático de tokens
*/
private setupAutoRefresh(): void {
if (!this.adapter) return;
// Verificar cada 30 segundos si necesita refresco
this.refreshInterval = setInterval(async () => {
if (this.adapter && this.adapter.needsRefresh()) {
try {
await this.adapter.refresh();
} catch (error) {
console.error('[AuthManager] Error refreshing auth:', error);
}
}
}, 30000);
}
/**
* Obtiene los headers/params de autenticación para una petición
*/
async getAuthHeaders(): Promise<Record<string, string>> {
if (!this.adapter) {
return {};
}
// Refrescar si es necesario antes de aplicar
if (this.adapter.needsRefresh()) {
await this.adapter.refresh();
}
const result = await this.adapter.applyAuth();
return result.headers || {};
}
/**
* Obtiene los query params de autenticación
*/
async getAuthQueryParams(): Promise<Record<string, string>> {
if (!this.adapter) {
return {};
}
const result = await this.adapter.applyAuth();
return result.queryParams || {};
}
/**
* Obtiene el resultado completo de autenticación
*/
async getAuthResult() {
if (!this.adapter) {
return { headers: {}, queryParams: {}, cookies: {} };
}
if (this.adapter.needsRefresh()) {
await this.adapter.refresh();
}
return this.adapter.applyAuth();
}
/**
* Indica si hay autenticación configurada
*/
hasAuth(): boolean {
return this.adapter !== null && this.config?.type !== 'none';
}
/**
* Limpia recursos y detiene el refresco automático
*/
cleanup(): void {
if (this.refreshInterval) {
clearInterval(this.refreshInterval);
this.refreshInterval = null;
}
if (this.adapter) {
this.adapter.cleanup();
this.adapter = null;
}
}
}