fastcheck/server/src/services/dequienesService.ts
2026-04-08 13:58:46 -04:00

275 lines
7.5 KiB
TypeScript

import axios, { AxiosError, AxiosInstance } from 'axios';
import ELKService from './elkService';
interface RelationshipsRequest {
rut: string;
tenantId: string;
distance?: number;
relationshipDirection?: 'BOTH' | 'OUTGOING' | 'INCOMING';
onePathPerNode?: boolean;
apiKey?: string;
}
interface RelationshipsResponse {
success: boolean;
data?: any;
error?: string;
statusCode?: number;
responseTime?: number;
}
interface LegalEvent {
cve?: string;
publication_date?: string;
published_at?: string;
actuation_type: string;
company_name?: string;
source: string;
url?: string;
}
interface LegalEventsQueryResponse {
success: boolean;
data?: {
rut: string;
count: number;
cached: boolean;
timestamp: string;
events: LegalEvent[];
constitution_date?: string;
};
error?: string;
statusCode?: number;
responseTime?: number;
}
export class DequienesService {
private static instance: DequienesService;
private readonly axiosInstance: AxiosInstance;
private readonly baseUrl: string;
private constructor() {
this.baseUrl = process.env.DEQUIENES_BASE_URL || 'http://127.0.0.1:8023';
this.axiosInstance = axios.create({
baseURL: this.baseUrl,
timeout: 30000,
headers: {
'Accept': 'application/json'
}
});
this.axiosInstance.interceptors.request.use(
(config) => {
return config;
},
(error) => {
return Promise.reject(error);
}
);
this.axiosInstance.interceptors.response.use(
(response) => {
return response;
},
(error) => {
return Promise.reject(error);
}
);
}
public static getInstance(): DequienesService {
if (!DequienesService.instance) {
DequienesService.instance = new DequienesService();
}
return DequienesService.instance;
}
private sanitizeRut(rut: string): string {
const rutNoDots = rut.replace(/\./g, '').trim();
const parts = rutNoDots.split('-');
const numeric = parts[0].replace(/^0+/, '') || '0';
return numeric;
}
public async queryRelationships(req: RelationshipsRequest): Promise<RelationshipsResponse> {
const startTime = Date.now();
let statusCode: number | undefined;
let errorMessage: string | undefined;
const distance = req.distance ?? 2;
const relationshipDirection = req.relationshipDirection ?? 'BOTH';
const onePathPerNode = req.onePathPerNode ?? false;
const apiKey = (req.apiKey || process.env.DEQUIENES_API_KEY || '').trim();
const rutSanitized = this.sanitizeRut(req.rut);
try {
const url = `/relationships/${rutSanitized}`;
const headers: Record<string, string> = { 'accept': 'application/json' };
if (apiKey) headers['x-api-key'] = apiKey;
const response = await this.axiosInstance.get(url, {
params: {
distance,
relationship_direction: relationshipDirection,
one_path_per_node: onePathPerNode ? 'true' : 'false'
},
headers
});
statusCode = response.status;
const responseTime = Date.now() - startTime;
let augmentedData: any = response.data;
try {
const legalRes = await this.queryLegalEvents({ rut: req.rut, tenantId: req.tenantId, apiKey });
if (legalRes.success && legalRes.data) {
augmentedData = {
...augmentedData,
legalentity: legalRes.data
};
}
} catch (e) {
// Swallow errors from secondary call but keep primary response
}
await ELKService.logSheriffApiCall({
callName: 'dequienes_relationships',
method: 'GET',
url: `${this.baseUrl}${url}`,
statusCode,
responseTime,
rut: req.rut,
logId: `dequienes_${rutSanitized}_${Date.now()}`,
tenantId: req.tenantId,
success: true,
requestPayload: {
params: { distance, relationshipDirection, onePathPerNode },
headers: apiKey ? { 'x-api-key': '***' } : undefined
},
responseData: augmentedData
});
return {
success: true,
data: augmentedData,
statusCode,
responseTime
};
} catch (error) {
const err = error as AxiosError;
statusCode = err.response?.status;
errorMessage = err.message;
const responseTime = Date.now() - startTime;
await ELKService.logSheriffApiCall({
callName: 'dequienes_relationships',
method: 'GET',
url: `${this.baseUrl}/relationships/${rutSanitized}`,
statusCode,
responseTime,
rut: req.rut,
logId: `dequienes_${rutSanitized}_${Date.now()}`,
tenantId: req.tenantId,
success: false,
errorMessage,
requestPayload: {
params: { distance, relationshipDirection, onePathPerNode },
headers: apiKey ? { 'x-api-key': '***' } : undefined
},
responseData: err.response?.data
});
return {
success: false,
error: errorMessage,
statusCode,
responseTime
};
}
}
public async queryLegalEvents(req: { rut: string; tenantId: string; apiKey?: string }): Promise<LegalEventsQueryResponse> {
const startTime = Date.now();
let statusCode: number | undefined;
let errorMessage: string | undefined;
const apiKey = (req.apiKey || process.env.DEQUIENES_API_KEY || '').trim();
const rutSanitized = this.sanitizeRut(req.rut);
try {
const url = `/api/legal-events/${rutSanitized}`;
const headers: Record<string, string> = { 'accept': 'application/json' };
if (apiKey) headers['x-api-key'] = apiKey;
const response = await this.axiosInstance.get(url, { headers });
statusCode = response.status;
const responseTime = Date.now() - startTime;
await ELKService.logSheriffApiCall({
callName: 'dequienes_legal_events',
method: 'GET',
url: `${this.baseUrl}${url}`,
statusCode,
responseTime,
rut: req.rut,
logId: `dequienes_legal_events_${rutSanitized}_${Date.now()}`,
tenantId: req.tenantId,
success: true,
requestPayload: {
headers: apiKey ? { 'x-api-key': '***' } : undefined
},
responseData: response.data
});
return {
success: true,
data: response.data,
statusCode,
responseTime
};
} catch (error) {
const err = error as AxiosError;
statusCode = err.response?.status;
errorMessage = err.message;
const responseTime = Date.now() - startTime;
await ELKService.logSheriffApiCall({
callName: 'dequienes_legal_events',
method: 'GET',
url: `${this.baseUrl}/api/legal-events/${rutSanitized}`,
statusCode,
responseTime,
rut: req.rut,
logId: `dequienes_legal_events_${rutSanitized}_${Date.now()}`,
tenantId: req.tenantId,
success: false,
errorMessage,
requestPayload: {
headers: apiKey ? { 'x-api-key': '***' } : undefined
},
responseData: err.response?.data
});
return {
success: false,
error: errorMessage,
statusCode,
responseTime
};
}
}
public async getHealthStatus(): Promise<{ status: string; baseUrl: string }> {
try {
const res = await this.axiosInstance.get('/health');
const status = res.data?.status || 'unknown';
return { status, baseUrl: this.baseUrl };
} catch {
return { status: 'unreachable', baseUrl: this.baseUrl };
}
}
}
export default DequienesService;