UNPKG

@future-agi/sdk

Version:

We help GenAI teams maintain high-accuracy for their Models in production.

301 lines 12.3 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 __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()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.APIKeyAuth = exports.HttpClient = exports.ResponseHandler = void 0; exports.createAuthenticatedClient = createAuthenticatedClient; const axios_1 = __importStar(require("axios")); const executor_1 = require("../utils/executor"); const errors_1 = require("../utils/errors"); const constants_1 = require("../utils/constants"); /** * Generic response handler for parsing and validating HTTP responses */ class ResponseHandler { /** * Parse the response into the expected type */ static parse(response, handlerClass) { if (!response || response.status !== 200) { handlerClass._handleError(response); } return handlerClass._parseSuccess(response); } /** * Parse successful response - to be implemented by subclasses */ static _parseSuccess(response) { throw new Error("Method '_parseSuccess' must be implemented by subclass."); } /** * Handle error responses - to be implemented by subclasses */ static _handleError(response) { var _a; const status = (response === null || response === void 0 ? void 0 : response.status) || 500; let message; if (response === null || response === void 0 ? void 0 : response.data) { const d = response.data; message = d.message || d.detail || d.result; // If nothing explicit, stringify the whole payload so callers see something meaningful if (!message) { try { message = JSON.stringify(d); } catch (_b) { /* ignore */ } } } if (!message) { const url = ((_a = response === null || response === void 0 ? void 0 : response.config) === null || _a === void 0 ? void 0 : _a.url) ? ` – ${response.config.url}` : ''; message = ((response === null || response === void 0 ? void 0 : response.statusText) && response.statusText.trim().length > 0) ? response.statusText : `HTTP ${status}${url}`; } switch (status) { case 401: case 403: throw new errors_1.InvalidAuthError(message); case 404: throw new errors_1.DatasetNotFoundError(message); case 429: throw new errors_1.RateLimitError(message); case 503: throw new errors_1.ServiceUnavailableError(message); case 500: case 502: case 504: throw new errors_1.ServerError(message); default: throw new Error(`HTTP ${status}: ${message}`); } } } exports.ResponseHandler = ResponseHandler; /** * Base HTTP client with improved request handling, connection pooling, and async execution */ class HttpClient { constructor(config = {}) { this._baseUrl = (config.baseUrl || (0, constants_1.get_base_url)()).replace(/\/$/, ''); this._defaultTimeout = config.timeout || constants_1.DEFAULT_SETTINGS.TIMEOUT; this._defaultRetryAttempts = config.retryAttempts || 3; this._defaultRetryDelay = config.retryDelay || 1000; // Create axios instance with default configuration this._axiosInstance = axios_1.default.create({ baseURL: this._baseUrl, timeout: this._defaultTimeout, headers: Object.assign({ 'Content-Type': 'application/json', 'User-Agent': '@future-agi/sdk' }, config.defaultHeaders), // Enable connection pooling maxRedirects: 5, validateStatus: () => true, // Handle all status codes manually }); // Create bounded executor for managing concurrent requests this._executor = new executor_1.BoundedExecutor(config.maxQueue || constants_1.DEFAULT_SETTINGS.MAX_QUEUE, config.maxWorkers || constants_1.DEFAULT_SETTINGS.MAX_WORKERS); this._setupInterceptors(); } /** * Setup request and response interceptors */ _setupInterceptors() { // Request interceptor for logging and debugging this._axiosInstance.interceptors.request.use((config) => { // Add request timestamp for performance monitoring config.startTime = Date.now(); return config; }, (error) => Promise.reject(error)); // Response interceptor for logging and performance monitoring this._axiosInstance.interceptors.response.use((response) => { const duration = Date.now() - (response.config.startTime || 0); // Could add logging here for production monitoring return response; }, (error) => Promise.reject(error)); } /** * Make an HTTP request with retries and response handling */ request(config, responseHandler) { return __awaiter(this, void 0, void 0, function* () { const requestConfig = { method: config.method, url: config.url, headers: config.headers, params: config.params, data: config.json || config.data, timeout: config.timeout || this._defaultTimeout, }; // Handle file uploads if (config.files && Object.keys(config.files).length > 0) { const formData = new FormData(); Object.entries(config.files).forEach(([key, file]) => { formData.append(key, file); }); if (config.data) { Object.entries(config.data).forEach(([key, value]) => { formData.append(key, value); }); } requestConfig.data = formData; requestConfig.headers = Object.assign(Object.assign({}, requestConfig.headers), { 'Content-Type': 'multipart/form-data' }); } const retryAttempts = config.retry_attempts || this._defaultRetryAttempts; const retryDelay = config.retry_delay || this._defaultRetryDelay; // Execute request with bounded concurrency return this._executor.submit(() => __awaiter(this, void 0, void 0, function* () { var _a; for (let attempt = 0; attempt < retryAttempts; attempt++) { try { const response = yield this._axiosInstance.request(requestConfig); if (responseHandler) { return ResponseHandler.parse(response, responseHandler); } // Handle errors if no custom handler if (response.status >= 400) { ResponseHandler._handleError(response); } return response; } catch (error) { // Don't retry certain errors if (error instanceof errors_1.DatasetNotFoundError || error instanceof errors_1.InvalidAuthError || (error instanceof axios_1.AxiosError && ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 401)) { throw error; } // Last attempt - throw the error if (attempt === retryAttempts - 1) { if (error instanceof axios_1.AxiosError) { ResponseHandler._handleError(error.response); } throw error; } // Wait before retry yield this._sleep(retryDelay * Math.pow(2, attempt)); // Exponential backoff } } throw new Error('Unexpected end of retry loop'); })); }); } /** * Helper method for sleep/delay */ _sleep(ms) { return __awaiter(this, void 0, void 0, function* () { return new Promise(resolve => setTimeout(resolve, ms)); }); } /** * Close the client and cleanup resources */ close() { return __awaiter(this, void 0, void 0, function* () { yield this._executor.shutdown(true); }); } /** * Get the base URL */ get baseUrl() { return this._baseUrl; } /** * Get the default timeout */ get defaultTimeout() { return this._defaultTimeout; } } exports.HttpClient = HttpClient; /** * HTTP client with API key authentication */ class APIKeyAuth extends HttpClient { constructor(config = {}) { const fiApiKey = config.fiApiKey || process.env[constants_1.AUTH_ENVVAR_NAME.API_KEY]; const fiSecretKey = config.fiSecretKey || process.env[constants_1.AUTH_ENVVAR_NAME.SECRET_KEY]; if (!fiApiKey || !fiSecretKey) { throw new errors_1.MissingAuthError(fiApiKey, fiSecretKey); } super(Object.assign(Object.assign({}, config), { baseUrl: config.fiBaseUrl || config.baseUrl, defaultHeaders: Object.assign({ 'X-Api-Key': fiApiKey, 'X-Secret-Key': fiSecretKey }, config.defaultHeaders) })); // Set class-level credentials this._fiApiKey = fiApiKey; this._fiSecretKey = fiSecretKey; } /** * Get the current API key */ get fiApiKey() { return this._fiApiKey; } /** * Get the current secret key */ get fiSecretKey() { return this._fiSecretKey; } /** * Get authentication headers */ get headers() { return { 'X-Api-Key': this._fiApiKey, 'X-Secret-Key': this._fiSecretKey, }; } } exports.APIKeyAuth = APIKeyAuth; /** * Factory function to create authenticated HTTP client */ function createAuthenticatedClient(config) { return new APIKeyAuth(config); } exports.default = { ResponseHandler, HttpClient, APIKeyAuth, createAuthenticatedClient, }; //# sourceMappingURL=auth.js.map