UNPKG

solver-sdk

Version:

SDK для интеграции с Code Solver Backend API (совместимо с браузером и Node.js), с поддержкой функциональности мышления (Thinking Mode)

319 lines 13.2 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.HttpClient = void 0; const axios_1 = __importDefault(require("axios")); /** * Определение типа среды выполнения * @returns 'browser' | 'node' */ function getEnvironment() { return (typeof window !== 'undefined' && typeof window.document !== 'undefined') ? 'browser' : 'node'; } /** * HTTP клиент для выполнения запросов к API * * Предоставляет методы для работы с REST API, включая обработку ошибок, * повторные попытки и таймауты. */ class HttpClient { /** * Создает новый HTTP клиент * @param {string} baseURL Базовый URL для запросов * @param {HttpClientOptions} [options] Опции для HTTP клиента */ constructor(baseURL, options = {}) { this.baseURL = baseURL; this.options = { headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', ...(options.headers || {}) }, timeout: options.timeout || 30000, retry: options.retry || { maxRetries: 3, retryDelay: 1000, maxRetryDelay: 10000, retryStatusCodes: [408, 429, 500, 502, 503, 504] }, httpsAgent: options.httpsAgent }; this.environment = getEnvironment(); // Создаем Axios инстанс с базовыми настройками this.axiosInstance = axios_1.default.create({ baseURL: this.baseURL, timeout: this.options.timeout, headers: this.options.headers, ...(this.environment === 'node' && this.options.httpsAgent ? { httpsAgent: this.options.httpsAgent } : {}) }); // Добавляем интерцептор для обработки ошибок и повторных попыток this.setupInterceptors(); } /** * Настраивает интерцепторы Axios */ setupInterceptors() { // Интерцептор для ответов this.axiosInstance.interceptors.response.use((response) => response.data, async (error) => { const { config, response } = error; // Если нет конфига запроса или это уже повторный запрос, или skipRetry установлен, возвращаем ошибку if (!config || config._retryCount || config.skipRetry) { return Promise.reject(error); } config._retryCount = config._retryCount || 0; const retryConfig = this.options.retry; // Проверяем, нужно ли делать повторную попытку для данного статуса const shouldRetry = response && retryConfig.retryStatusCodes?.includes(response.status) && config._retryCount < (retryConfig.maxRetries || 3); if (shouldRetry) { config._retryCount += 1; // Вычисляем время задержки перед повторной попыткой const delay = Math.min((retryConfig.retryDelay || 1000) * Math.pow(2, config._retryCount - 1), retryConfig.maxRetryDelay || 10000); // Ждем перед повторной попыткой await new Promise(resolve => setTimeout(resolve, delay)); // Делаем повторную попытку return this.axiosInstance(config); } // Если не нужно делать повторную попытку, возвращаем ошибку return Promise.reject(error); }); } /** * Выполняет HTTP запрос * @param {RequestOptions} options Опции запроса * @returns {Promise<T>} Ответ от API */ async request(options) { const axiosConfig = { url: options.url, method: options.method, data: options.data, params: options.params, headers: { ...this.options.headers, ...(options.headers || {}) }, timeout: options.timeout || this.options.timeout }; // Если указано не делать повторные попытки, добавляем специальный флаг if (options.noRetry) { axiosConfig.skipRetry = true; } try { return await this.axiosInstance.request(axiosConfig); } catch (error) { throw this.handleError(error); } } /** * Выполняет GET запрос * @param {string} url URL для запроса * @param {Record<string, any>} [params] Query параметры * @param {Record<string, string>} [headers] HTTP заголовки * @returns {Promise<T>} Ответ от API */ async get(url, params, headers) { return this.request({ url, method: 'GET', params, headers }); } /** * Выполняет POST запрос * @param {string} url URL для запроса * @param {any} [data] Данные для отправки * @param {Record<string, string>} [headers] HTTP заголовки * @returns {Promise<T>} Ответ от API */ async post(url, data, headers) { return this.request({ url, method: 'POST', data, headers }); } /** * Выполняет PUT запрос * @param {string} url URL для запроса * @param {any} [data] Данные для отправки * @param {Record<string, string>} [headers] HTTP заголовки * @returns {Promise<T>} Ответ от API */ async put(url, data, headers) { return this.request({ url, method: 'PUT', data, headers }); } /** * Выполняет DELETE запрос * @param {string} url URL для запроса * @param {Record<string, any>} [params] Query параметры * @param {Record<string, string>} [headers] HTTP заголовки * @returns {Promise<T>} Ответ от API */ async delete(url, params, headers) { return this.request({ url, method: 'DELETE', params, headers }); } /** * Выполняет PATCH запрос * @param {string} url URL для запроса * @param {any} [data] Данные для отправки * @param {Record<string, string>} [headers] HTTP заголовки * @returns {Promise<T>} Ответ от API */ async patch(url, data, headers) { return this.request({ url, method: 'PATCH', data, headers }); } /** * Выполняет POST запрос с потоковым ответом * @param {string} url URL для запроса * @param {any} [data] Данные для отправки * @param {Record<string, string>} [headers] HTTP заголовки * @returns {Promise<Response>} Объект Response с потоком данных */ async postStream(url, data, headers) { // Для Node.js среды используем node-fetch или другую библиотеку if (this.environment === 'node') { try { // Используем динамический импорт для совместимости с браузером const { default: nodeFetch } = await Promise.resolve().then(() => __importStar(require('node-fetch'))); return nodeFetch(`${this.baseURL}${url}`, { method: 'POST', headers: { 'Content-Type': 'application/json', ...this.options.headers, ...(headers || {}) }, body: JSON.stringify(data) }); } catch (error) { console.error('Ошибка при загрузке node-fetch:', error); throw new Error('Для использования потоковой передачи в Node.js необходимо установить node-fetch'); } } // Для браузера используем нативный fetch return fetch(`${this.baseURL}${url}`, { method: 'POST', headers: { 'Content-Type': 'application/json', ...this.options.headers, ...(headers || {}) }, body: JSON.stringify(data) }); } /** * Обрабатывает ошибки от Axios * @param {any} error Ошибка от Axios * @returns {Error} Обработанная ошибка */ handleError(error) { let enhancedError; if (error.response) { // Ошибка от сервера с кодом ответа const { status, data } = error.response; const message = data?.message || data?.error || `HTTP ошибка ${status}`; enhancedError = new Error(message); enhancedError.status = status; enhancedError.data = data; enhancedError.isApiError = true; } else if (error.request) { // Запрос был сделан, но ответ не получен enhancedError = new Error('Нет ответа от сервера. Проверьте подключение к интернету.'); enhancedError.request = error.request; enhancedError.isNetworkError = true; } else { // Произошла ошибка при настройке запроса enhancedError = new Error(error.message || 'Произошла неизвестная ошибка'); enhancedError.isUnknownError = true; } // Сохраняем оригинальную ошибку для отладки enhancedError.originalError = error; // Пытаемся обработать ошибку через глобальный обработчик try { // eslint-disable-next-line @typescript-eslint/no-var-requires const { CodeSolverSDK } = require('../code-solver-sdk.js'); if (typeof CodeSolverSDK.handleError === 'function') { CodeSolverSDK.handleError(enhancedError); } } catch (e) { // Игнорируем ошибки при импорте или вызове обработчика } return enhancedError; } /** * Получает экземпляр Axios для тестирования */ get axiosConfig() { return this.axiosInstance; } /** * Получает базовый URL API * @returns {string} Базовый URL */ getBaseURL() { return this.baseURL; } } exports.HttpClient = HttpClient; //# sourceMappingURL=http-client.js.map