UNPKG

@dima_aryze/reforge

Version:

TypeScript/JavaScript SDK for Reforge - Cross-chain token operations

258 lines 8.34 kB
"use strict"; /** * Base HTTP client implementation for the Reforge SDK */ Object.defineProperty(exports, "__esModule", { value: true }); exports.BaseHttpClient = void 0; const tslib_1 = require("tslib"); const axios_1 = tslib_1.__importDefault(require("axios")); const errors_1 = require("../errors"); const utils_1 = require("../utils"); const errors_2 = require("./errors"); const interceptors_1 = require("./interceptors"); const retry_1 = require("./retry"); /** * Default configuration for HTTP requests */ const DEFAULT_CONFIG = { timeout: 30000, headers: {}, debug: false, retry: { attempts: 3, delay: 1000, maxDelay: 30000, backoffMultiplier: 2, }, }; /** * Base HTTP client with comprehensive error handling and retry logic */ class BaseHttpClient { constructor(options) { Object.defineProperty(this, "httpClient", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "config", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "logger", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "eventListeners", { enumerable: true, configurable: true, writable: true, value: new Map() }); Object.defineProperty(this, "errorTransformer", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "retryHandler", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "apiKey", { enumerable: true, configurable: true, writable: true, value: void 0 }); this.validateOptions(options); // Merge configuration with defaults this.config = (0, utils_1.deepMerge)({}, DEFAULT_CONFIG, { baseUrl: options.baseUrl, timeout: options.timeout, headers: options.headers, debug: options.debug, retry: options.retry, }); this.apiKey = options.apiKey; this.logger = (0, utils_1.createLogger)(this.config.debug ? 'debug' : 'warn'); this.errorTransformer = new errors_2.ErrorTransformer(); this.retryHandler = new retry_1.RetryHandler(this.config.retry, this.logger); // Initialize HTTP client this.httpClient = options.httpClient || this.createHttpClient(); this.logger.info('HTTP client initialized', { baseUrl: this.config.baseUrl, hasApiKey: !!this.apiKey, debug: this.config.debug, }); } /** * Validate constructor options */ validateOptions(options) { if (!options.apiKey || typeof options.apiKey !== 'string') { throw new errors_1.ReforgeValidationError('API key is required and must be a string'); } if (!options.baseUrl || typeof options.baseUrl !== 'string') { throw new errors_1.ReforgeValidationError('Base URL is required and must be a string'); } try { new URL(options.baseUrl); } catch { throw new errors_1.ReforgeValidationError('Base URL must be a valid URL'); } } /** * Create and configure the Axios instance */ createHttpClient() { const client = axios_1.default.create({ baseURL: (0, utils_1.sanitizeUrl)(this.config.baseUrl), timeout: this.config.timeout, headers: { 'Content-Type': 'application/json', 'User-Agent': 'reforge-sdk/1.0.0', ...this.config.headers, }, }); // Setup interceptors const requestInterceptor = new interceptors_1.RequestInterceptor(this.apiKey, this.logger); requestInterceptor.setup(client); // Response interceptor client.interceptors.response.use(response => { this.logger.debug('Response received', { status: response.status, url: response.config.url, }); return response; }, error => { const transformedError = this.errorTransformer.transform(error); this.logger.error('Response error', transformedError.message); return Promise.reject(transformedError); }); return client; } /** * Emit an event to all registered listeners */ emitEvent(type, data) { const listeners = this.eventListeners.get(type) || []; const eventData = { type, timestamp: new Date(), data, }; listeners.forEach(callback => { try { callback(eventData); } catch (error) { this.logger.error('Event listener error', error); } }); } /** * Make HTTP request with comprehensive error handling and retry logic */ async makeRequest(method, path, data, options = {}) { return this.retryHandler.execute(async (attempt) => { this.emitEvent('request:start', { method, path, attempt }); try { const axiosConfig = { method, url: path, timeout: options.timeout || this.config.timeout, headers: { ...options.headers, ...(options.skipAuth ? { 'skip-auth': 'true' } : {}), 'X-Request-ID': (0, utils_1.generateRequestId)(), }, }; if (data) { if (method === 'GET') { axiosConfig.params = data; } else { axiosConfig.data = data; } } const response = await this.httpClient.request(axiosConfig); this.emitEvent('request:success', { method, path, attempt, status: response.status, }); return response.data; } catch (error) { const transformedError = error instanceof errors_1.ReforgeError ? error : this.errorTransformer.transform(error); this.emitEvent('request:error', { method, path, attempt, error: transformedError, }); throw transformedError; } }, options.retry); } /** * Update the API key */ setApiKey(apiKey) { if (typeof apiKey !== 'string' || !apiKey.trim()) { throw new errors_1.ReforgeValidationError('API key must be a non-empty string'); } this.apiKey = apiKey.trim(); this.logger.info('API key updated'); } /** * Get the current API key */ getApiKey() { return this.apiKey; } /** * Add event listener */ on(event, callback) { if (!this.eventListeners.has(event)) { this.eventListeners.set(event, []); } this.eventListeners.get(event).push(callback); } /** * Remove event listener */ off(event, callback) { const listeners = this.eventListeners.get(event); if (listeners) { const index = listeners.indexOf(callback); if (index > -1) { listeners.splice(index, 1); } } } /** * Remove all event listeners */ removeAllListeners(event) { if (event) { this.eventListeners.delete(event); } else { this.eventListeners.clear(); } } } exports.BaseHttpClient = BaseHttpClient; //# sourceMappingURL=base.js.map