UNPKG

@akomalabs/kemono

Version:

A production-grade TypeScript API wrapper for the Kemono/Coomer platforms

137 lines 4.59 kB
import axios from 'axios'; import axiosRetry from 'axios-retry'; import { KemonoApiError, AuthenticationError, NotFoundError } from '../errors/api-error'; /** * HTTP client for making API requests with retry, caching, and rate limiting */ export class HttpClient { cache; rateLimiter; logger; axios; constructor(config, cache, rateLimiter, logger) { this.cache = cache; this.rateLimiter = rateLimiter; this.logger = logger; // Initialize axios instance this.axios = axios.create({ baseURL: config.baseUrl || 'https://kemono.su/api/v1', headers: { 'User-Agent': '@akomalabs/kemono', ...(config.sessionKey && { Cookie: `session=${config.sessionKey}` }), }, }); // Configure retry behavior axiosRetry(this.axios, { retries: 3, retryDelay: axiosRetry.exponentialDelay, retryCondition: (error) => { return axiosRetry.isNetworkOrIdempotentRequestError(error) || error.response?.status === 429; }, }); // Add response interceptor for error handling this.axios.interceptors.response.use((response) => response, (error) => { if (!error.response) { throw error; } switch (error.response.status) { case 401: throw new AuthenticationError(); case 404: throw new NotFoundError(); default: throw new KemonoApiError(`API Error: ${error.message}`, error.response.status, 'API_ERROR'); } }); } /** * Make a GET request with caching and rate limiting * @param url Request URL * @param config Axios request config * @returns Response data */ async get(url, config) { const cacheKey = `get:${url}`; // Check cache first const cachedData = await this.cache.get(cacheKey); if (cachedData) { this.logger.debug('Cache hit', { url }); return JSON.parse(cachedData); } await this.rateLimiter.checkLimit(); try { const response = await this.axios.get(url, config); await this.rateLimiter.incrementCount(); // Cache the response await this.cache.set(cacheKey, JSON.stringify(response.data)); return response.data; } catch (error) { this.logger.error('GET request failed', { url, error }); throw error; } } /** * Make a POST request with rate limiting * @param url Request URL * @param data Request body * @param config Axios request config * @returns Response data */ async post(url, data, config) { await this.rateLimiter.checkLimit(); try { const response = await this.axios.post(url, data, config); await this.rateLimiter.incrementCount(); return response.data; } catch (error) { this.logger.error('POST request failed', { url, error }); throw error; } } /** * Make a PUT request with rate limiting * @param url Request URL * @param data Request body * @param config Axios request config * @returns Response data */ async put(url, data, config) { await this.rateLimiter.checkLimit(); try { const response = await this.axios.put(url, data, config); await this.rateLimiter.incrementCount(); return response.data; } catch (error) { this.logger.error('PUT request failed', { url, error }); throw error; } } /** * Make a DELETE request with rate limiting * @param url Request URL * @param config Axios request config * @returns Response data */ async delete(url, config) { await this.rateLimiter.checkLimit(); try { const response = await this.axios.delete(url, config); await this.rateLimiter.incrementCount(); return response.data; } catch (error) { this.logger.error('DELETE request failed', { url, error }); throw error; } } } /** * Create a new HTTP client instance */ export function createHttpClient(config, cache, rateLimiter, logger) { return new HttpClient(config, cache, rateLimiter, logger); } //# sourceMappingURL=http-client.js.map