UNPKG

coddyger

Version:

Coddyger est une bibliothèque JavaScript/TypeScript qui fournit des fonctions communes et des plugins pour la gestion des données, la communication entre services, et des utilitaires avancés pour le développement d'applications.

276 lines (275 loc) 11.7 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AxiosService = void 0; const axios_1 = __importDefault(require("axios")); const logger_service_1 = require("./logger.service"); class AxiosService { static connect(config) { // Merge default retry config with provided config if (config.retryConfig) { this.retryConfig = Object.assign(Object.assign({}, this.retryConfig), config.retryConfig); } this.instance = axios_1.default.create(Object.assign({ baseURL: config.baseURL, timeout: config.timeout || 30000, headers: Object.assign({ 'Content-Type': 'application/json' }, config.headers), withCredentials: config.withCredentials || false }, config)); this.setupInterceptors(); return this.instance; } static setupInterceptors() { // Request interceptor with logging this.instance.interceptors.request.use((config) => { var _a; const requestId = Math.random().toString(36).substring(7); config.headers['X-Request-ID'] = requestId; logger_service_1.LoggerService.debug('API Request', { requestId, method: (_a = config.method) === null || _a === void 0 ? void 0 : _a.toUpperCase(), url: config.url, headers: this.sanitizeHeaders(config.headers), data: config.data }); return config; }, (error) => { logger_service_1.LoggerService.error('API Request Error', { error }); return Promise.reject(error); }); // Response interceptor with logging this.instance.interceptors.response.use((response) => { const requestId = response.config.headers['X-Request-ID']; logger_service_1.LoggerService.debug('API Response', { requestId, status: response.status, headers: this.sanitizeHeaders(response.headers), data: response.data }); return response; }, (error) => { var _a; const requestId = (_a = error.config) === null || _a === void 0 ? void 0 : _a.headers['X-Request-ID']; const errorResponse = this.handleAxiosError(error); logger_service_1.LoggerService.error('API Response Error', { requestId, error: errorResponse }); return Promise.reject(errorResponse); }); } static sanitizeHeaders(headers) { const sensitiveHeaders = ['authorization', 'cookie', 'x-api-key']; const sanitized = Object.assign({}, headers); for (const header of sensitiveHeaders) { if (sanitized[header]) { sanitized[header] = '[REDACTED]'; } } return sanitized; } static handleAxiosError(error) { var _a, _b, _c, _d, _e; const defaultError = { message: 'Une erreur inattendue s\'est produite', code: 'UNKNOWN_ERROR', status: 500, timestamp: new Date().toISOString() }; if (!error.response) { return { message: 'Erreur réseau - veuillez vérifier votre connexion', code: 'NETWORK_ERROR', status: 0, timestamp: new Date().toISOString() }; } const status = error.response.status; const data = error.response.data; const timestamp = new Date().toISOString(); const path = ((_a = error.config) === null || _a === void 0 ? void 0 : _a.url) || ''; const errorMap = { 400: { message: ((_b = data === null || data === void 0 ? void 0 : data.error) === null || _b === void 0 ? void 0 : _b.message) || 'Requête invalide', code: 'BAD_REQUEST', status: 400, errors: (_c = data === null || data === void 0 ? void 0 : data.error) === null || _c === void 0 ? void 0 : _c.errors }, 401: { message: 'Votre session a expiré. Veuillez vous reconnecter', code: 'UNAUTHORIZED', status: 401 }, 403: { message: 'Vous n\'avez pas les permissions nécessaires', code: 'FORBIDDEN', status: 403 }, 404: { message: 'La ressource demandée n\'a pas été trouvée', code: 'NOT_FOUND', status: 404 }, 422: { message: ((_d = data === null || data === void 0 ? void 0 : data.error) === null || _d === void 0 ? void 0 : _d.message) || 'Erreur de validation', code: 'VALIDATION_ERROR', status: 422, errors: (_e = data === null || data === void 0 ? void 0 : data.error) === null || _e === void 0 ? void 0 : _e.errors }, 429: { message: 'Trop de requêtes. Veuillez réessayer plus tard', code: 'RATE_LIMIT_EXCEEDED', status: 429 }, 500: { message: 'Erreur serveur interne. Veuillez réessayer plus tard', code: 'SERVER_ERROR', status: 500 }, 503: { message: 'Service temporairement indisponible', code: 'SERVICE_UNAVAILABLE', status: 503 } }; const errorResponse = errorMap[status] || defaultError; return Object.assign(Object.assign({}, errorResponse), { timestamp, path }); } static getCacheKey(method, url, data) { return `${method}:${url}:${data ? JSON.stringify(data) : ''}`; } static getFromCache(cacheKey) { const cached = this.cache.get(cacheKey); if (!cached) return null; const now = Date.now(); if (now - cached.timestamp > cached.ttl) { this.cache.delete(cacheKey); return null; } return cached.data; } static setCache(cacheKey, data, ttlMs) { this.cache.set(cacheKey, { data, timestamp: Date.now(), ttl: ttlMs }); } static withRetry(requestFn, customConfig) { return __awaiter(this, void 0, void 0, function* () { const config = Object.assign(Object.assign({}, this.retryConfig), customConfig); let lastError; for (let attempt = 0; attempt < config.maxRetries; attempt++) { try { return yield requestFn(); } catch (error) { lastError = error; if (!config.retryCondition(error)) { break; } if (attempt < config.maxRetries - 1) { const delay = config.delayMs * Math.pow(2, attempt); logger_service_1.LoggerService.warn(`Retry attempt ${attempt + 1}/${config.maxRetries} after ${delay}ms`); yield new Promise(resolve => setTimeout(resolve, delay)); } } } throw lastError; }); } // Utility methods with improved type safety and caching support static get(url, config) { return __awaiter(this, void 0, void 0, function* () { const cacheKey = this.getCacheKey('GET', url); if (config === null || config === void 0 ? void 0 : config.cache) { const cached = this.getFromCache(cacheKey); if (cached) return cached; } const request = () => this.instance.get(url, config); const response = yield ((config === null || config === void 0 ? void 0 : config.retry) ? this.withRetry(request) : request()); if (config === null || config === void 0 ? void 0 : config.cache) { this.setCache(cacheKey, response, config.cacheTTL || 5 * 60 * 1000); // Default 5 minutes } return response; }); } static post(url, data, config) { return __awaiter(this, void 0, void 0, function* () { const request = () => this.instance.post(url, data, config); return (config === null || config === void 0 ? void 0 : config.retry) ? this.withRetry(request) : request(); }); } static put(url, data, config) { return __awaiter(this, void 0, void 0, function* () { const request = () => this.instance.put(url, data, config); return (config === null || config === void 0 ? void 0 : config.retry) ? this.withRetry(request) : request(); }); } static delete(url, config) { return __awaiter(this, void 0, void 0, function* () { const request = () => this.instance.delete(url, config); return (config === null || config === void 0 ? void 0 : config.retry) ? this.withRetry(request) : request(); }); } static patch(url, data, config) { return __awaiter(this, void 0, void 0, function* () { const request = () => this.instance.patch(url, data, config); return (config === null || config === void 0 ? void 0 : config.retry) ? this.withRetry(request) : request(); }); } // Enhanced header management static setHeader(key, value, type = 'common') { if (this.instance) { if (type === 'common') { this.instance.defaults.headers.common[key] = value; } else { this.instance.defaults.headers[type][key] = value; } } } static removeHeader(key, type = 'common') { if (this.instance) { if (type === 'common') { delete this.instance.defaults.headers.common[key]; } else { delete this.instance.defaults.headers[type][key]; } } } static getInstance() { if (!this.instance) { throw new Error('Instance Axios non initialisée. Appelez connect() d\'abord.'); } return this.instance; } // Utility method to clear cache static clearCache() { this.cache.clear(); } // Utility method to get cache size static getCacheSize() { return this.cache.size; } } exports.AxiosService = AxiosService; AxiosService.cache = new Map(); AxiosService.retryConfig = { maxRetries: 3, delayMs: 1000, retryCondition: (error) => { // Retry on network errors and 5xx server errors return !error.response || (error.response.status >= 500 && error.response.status < 600); } };