UNPKG

ci-validation

Version:

🇺🇾 Complete TypeScript/JavaScript library for validating Uruguayan CI (Cédula de Identidad) with official algorithm and government service integration

335 lines • 12.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SanRoqueService = void 0; const axios_1 = __importDefault(require("axios")); /** * San Roque Service Class * Handles member validation and points query for Tarjeta San Roque (tarjetasanroque.com.uy) * * This service checks if a user is a member of the San Roque loyalty program * and retrieves their points information. */ class SanRoqueService { constructor() { this.baseUrl = 'https://api.tarjetasanroque.com.uy'; this.endpoint = '/api/public/member-validation'; this.timeout = 10000; // 10 seconds timeout } /** * Default headers for San Roque requests * Based on the original curl request */ getDefaultHeaders() { return { 'accept': 'application/json, text/plain, */*', 'accept-language': 'es-ES,es;q=0.9,bg;q=0.8', 'cache-control': 'no-cache', 'content-type': 'application/json', 'origin': 'https://tarjetasanroque.com.uy', 'pragma': 'no-cache', 'priority': 'u=1, i', 'referer': 'https://tarjetasanroque.com.uy/', 'sec-ch-ua': '"Not;A=Brand";v="99", "Google Chrome";v="139", "Chromium";v="139"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'same-site', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36' }; } /** * Creates request payload for the San Roque API * @param ci - Cédula de identidad (without dots or dashes) * @param documentType - Document type (default: "CI") * @returns Request payload object */ createRequestPayload(ci, documentType = 'CI') { return { documentType: documentType, documentNumber: parseInt(ci, 10) // Convert to number as expected by API }; } /** * Validates CI format before making the request * @param ci - Cédula de identidad * @returns boolean */ validateCI(ci) { // Remove any non-numeric characters const cleanCi = ci.replace(/\D/g, ''); // Check if it's between 7 and 8 digits return cleanCi.length >= 7 && cleanCi.length <= 8; } /** * Normalizes CI by removing any formatting * @param ci - Cédula de identidad * @returns Normalized CI string */ normalizeCI(ci) { return ci.replace(/\D/g, ''); } /** * Converts string numbers to actual numbers, handling empty strings * @param value - String value that might be a number * @returns Number or 0 if invalid */ parsePoints(value) { if (!value || value.trim() === '') { return 0; } const parsed = parseInt(value, 10); return isNaN(parsed) ? 0 : parsed; } /** * Parses the San Roque API response * @param response - Axios response * @param ci - Original CI for context * @returns Parsed SanRoqueResponse */ parseResponse(response, ci) { const executionTime = Date.now(); try { const data = response.data; // Check if there's an error in the response if (data.error) { return { success: true, // API call was successful, but user not found hasUser: false, error: data.error, member: { ci: ci, documentType: 'CI', firstName: '', lastName: '', email: '', status: 'unknown', executionTime: executionTime } }; } // If we have member data, user exists if (data.socio) { const member = data.socio; const points = data.puntos; // Parse points information const availablePoints = points ? this.parsePoints(points.puntosDisponibles) : 0; const expiring30 = points ? this.parsePoints(points.vencimiento30) : 0; const expiring60 = points && points.vencimiento60 ? this.parsePoints(points.vencimiento60) : undefined; const expiring90 = points && points.vencimiento90 ? this.parsePoints(points.vencimiento90) : undefined; return { success: true, hasUser: true, member: { ci: member.cedula, documentType: member.tipoDocumento, firstName: member.nombres || '', lastName: member.apellidos || '', email: member.email || '', status: member.estado?.toLowerCase() === 'activo' ? 'active' : member.estado?.toLowerCase() === 'inactivo' ? 'inactive' : 'unknown', executionTime: executionTime }, points: { available: availablePoints, expiring30Days: expiring30, expiring60Days: expiring60, expiring90Days: expiring90, total: availablePoints + expiring30 + (expiring60 || 0) + (expiring90 || 0) } }; } // No member data and no error - unexpected response return { success: false, hasUser: false, error: 'Respuesta inesperada del servidor', member: { ci: ci, documentType: 'CI', firstName: '', lastName: '', email: '', status: 'unknown', executionTime: executionTime } }; } catch (error) { return { success: false, hasUser: false, error: `Error parsing response: ${error instanceof Error ? error.message : 'Unknown error'}`, member: { ci: ci, documentType: 'CI', firstName: '', lastName: '', email: '', status: 'unknown', executionTime: executionTime } }; } } /** * Checks if a user is a member of San Roque and retrieves their information * @param request - San Roque request parameters * @returns Promise<SanRoqueResponse> */ async checkMember(request) { const startTime = Date.now(); try { // Validate input if (!request.ci) { throw new Error('CI (Cédula de Identidad) is required'); } const normalizedCI = this.normalizeCI(request.ci); if (!this.validateCI(normalizedCI)) { throw new Error('CI must be between 7 and 8 digits'); } // Prepare request const payload = this.createRequestPayload(normalizedCI, request.documentType); const headers = this.getDefaultHeaders(); // Make the request const response = await axios_1.default.post(`${this.baseUrl}${this.endpoint}`, payload, { headers, timeout: this.timeout, validateStatus: (status) => status < 500 // Accept 4xx as valid responses }); const result = this.parseResponse(response, normalizedCI); // Update execution time if (result.member) { result.member.executionTime = Date.now() - startTime; } return result; } catch (error) { const executionTime = Date.now() - startTime; if (axios_1.default.isAxiosError(error)) { // Handle specific HTTP errors if (error.response?.status === 404) { return { success: true, hasUser: false, error: 'Member not found in San Roque system', member: { ci: this.normalizeCI(request.ci), documentType: request.documentType || 'CI', firstName: '', lastName: '', email: '', status: 'unknown', executionTime: executionTime } }; } if (error.response?.status === 403 || error.response?.status === 401) { return { success: false, hasUser: false, error: 'Access denied or authentication required', member: { ci: this.normalizeCI(request.ci), documentType: request.documentType || 'CI', firstName: '', lastName: '', email: '', status: 'unknown', executionTime: executionTime } }; } return { success: false, hasUser: false, error: `HTTP Error: ${error.response?.status} - ${error.message}`, member: { ci: this.normalizeCI(request.ci), documentType: request.documentType || 'CI', firstName: '', lastName: '', email: '', status: 'unknown', executionTime: executionTime } }; } return { success: false, hasUser: false, error: `Network or system error: ${error instanceof Error ? error.message : 'Unknown error'}`, member: { ci: this.normalizeCI(request.ci), documentType: request.documentType || 'CI', firstName: '', lastName: '', email: '', status: 'unknown', executionTime: executionTime } }; } } /** * Convenience method to check if a user is a member by CI only * @param ci - Cédula de identidad * @returns Promise<boolean> */ async isMember(ci) { try { const result = await this.checkMember({ ci }); return result.hasUser || false; } catch (error) { console.error('Error checking member in San Roque:', error); return false; } } /** * Get member points from San Roque system * @param ci - Cédula de identidad * @returns Promise<number> */ async getMemberPoints(ci) { try { const result = await this.checkMember({ ci }); return result.points?.available || 0; } catch (error) { console.error('Error getting member points from San Roque:', error); return 0; } } /** * Get total member points (available + expiring) from San Roque system * @param ci - Cédula de identidad * @returns Promise<number> */ async getTotalMemberPoints(ci) { try { const result = await this.checkMember({ ci }); return result.points?.total || 0; } catch (error) { console.error('Error getting total member points from San Roque:', error); return 0; } } /** * Get comprehensive member information from San Roque system * @param ci - Cédula de identidad * @param documentType - Document type (optional) * @returns Promise<SanRoqueResponse> */ async getMemberInfo(ci, documentType) { return this.checkMember({ ci, documentType }); } } exports.SanRoqueService = SanRoqueService; // Export a default instance exports.default = new SanRoqueService(); //# sourceMappingURL=SanRoque.js.map