UNPKG

@vepler/http-client

Version:

A flexible and extensible API service library for making HTTP requests with built-in authentication support for bearer tokens and API keys.

318 lines 14.5 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createErrorFromResponse = exports.ValidationError = exports.RateLimitError = exports.TimeoutError = exports.AuthError = exports.NetworkError = exports.ServerError = exports.ClientError = exports.HttpError = void 0; /** * Base HTTP error class for all API errors */ var HttpError = /** @class */ (function (_super) { __extends(HttpError, _super); function HttpError(message, status, statusText, endpoint, method, url, data) { if (status === void 0) { status = 500; } if (statusText === void 0) { statusText = 'Internal Server Error'; } if (endpoint === void 0) { endpoint = ''; } if (method === void 0) { method = ''; } if (url === void 0) { url = ''; } if (data === void 0) { data = null; } var _this = _super.call(this, message) || this; _this.isHttpError = true; _this.name = 'HttpError'; _this.status = status; _this.statusText = statusText; _this.endpoint = endpoint; _this.method = method; _this.url = url; _this.data = data; // This is needed due to extending a built-in class in TypeScript Object.setPrototypeOf(_this, HttpError.prototype); return _this; } /** * Formats the error for developer debugging */ HttpError.prototype.toJSON = function () { return { name: this.name, message: this.message, status: this.status, statusText: this.statusText, endpoint: this.endpoint, method: this.method, url: this.url, data: this.data, }; }; /** * Creates an HttpError from an AxiosError */ HttpError.fromAxiosError = function (error) { var _a; if (error.response) { var _b = error.response, status_1 = _b.status, statusText = _b.statusText, config = _b.config, data = _b.data; var method = ((_a = config === null || config === void 0 ? void 0 : config.method) === null || _a === void 0 ? void 0 : _a.toUpperCase()) || 'UNKNOWN'; var endpoint = (config === null || config === void 0 ? void 0 : config.url) || ''; var baseUrl = (config === null || config === void 0 ? void 0 : config.baseURL) || ''; var url = baseUrl ? "".concat(baseUrl).concat(endpoint) : endpoint; return new HttpError("".concat(status_1, " ").concat(statusText, " - ").concat(method, " ").concat(endpoint), status_1, statusText, endpoint, method, url, data); } else if (error.request) { // The request was made but no response was received return new NetworkError('No response received from server', error.request); } else { // Something happened in setting up the request return new ClientError(error.message || 'Request setup error'); } }; return HttpError; }(Error)); exports.HttpError = HttpError; /** * 400-499 level HTTP errors */ var ClientError = /** @class */ (function (_super) { __extends(ClientError, _super); function ClientError(message, status, statusText, endpoint, method, url, data) { if (status === void 0) { status = 400; } if (statusText === void 0) { statusText = 'Bad Request'; } if (endpoint === void 0) { endpoint = ''; } if (method === void 0) { method = ''; } if (url === void 0) { url = ''; } if (data === void 0) { data = null; } var _this = _super.call(this, message, status, statusText, endpoint, method, url, data) || this; _this.name = 'ClientError'; Object.setPrototypeOf(_this, ClientError.prototype); return _this; } return ClientError; }(HttpError)); exports.ClientError = ClientError; /** * 500-599 level HTTP errors */ var ServerError = /** @class */ (function (_super) { __extends(ServerError, _super); function ServerError(message, status, statusText, endpoint, method, url, data) { if (status === void 0) { status = 500; } if (statusText === void 0) { statusText = 'Internal Server Error'; } if (endpoint === void 0) { endpoint = ''; } if (method === void 0) { method = ''; } if (url === void 0) { url = ''; } if (data === void 0) { data = null; } var _this = _super.call(this, message, status, statusText, endpoint, method, url, data) || this; _this.name = 'ServerError'; Object.setPrototypeOf(_this, ServerError.prototype); return _this; } return ServerError; }(HttpError)); exports.ServerError = ServerError; /** * Network or connectivity errors */ var NetworkError = /** @class */ (function (_super) { __extends(NetworkError, _super); function NetworkError(message, request, endpoint, method, url) { if (request === void 0) { request = null; } if (endpoint === void 0) { endpoint = ''; } if (method === void 0) { method = ''; } if (url === void 0) { url = ''; } var _this = _super.call(this, message, 0, 'Network Error', endpoint, method, url) || this; _this.name = 'NetworkError'; _this.request = request; Object.setPrototypeOf(_this, NetworkError.prototype); return _this; } NetworkError.prototype.toJSON = function () { return __assign(__assign({}, _super.prototype.toJSON.call(this)), { request: this.request ? '[Request Object]' : null }); }; return NetworkError; }(HttpError)); exports.NetworkError = NetworkError; /** * Authentication errors (401, 403) */ var AuthError = /** @class */ (function (_super) { __extends(AuthError, _super); function AuthError(message, status, statusText, endpoint, method, url, data, credentials) { if (status === void 0) { status = 401; } if (statusText === void 0) { statusText = 'Unauthorized'; } if (endpoint === void 0) { endpoint = ''; } if (method === void 0) { method = ''; } if (url === void 0) { url = ''; } if (data === void 0) { data = null; } if (credentials === void 0) { credentials = {}; } var _this = _super.call(this, message, status, statusText, endpoint, method, url, data) || this; _this.name = 'AuthError'; _this.credentials = AuthError.sanitizeCredentials(credentials); Object.setPrototypeOf(_this, AuthError.prototype); return _this; } AuthError.sanitizeCredentials = function (credentials) { var sanitized = {}; Object.entries(credentials).forEach(function (_a) { var key = _a[0], value = _a[1]; if (key.toLowerCase().includes('key') || key.toLowerCase().includes('token')) { // Mask sensitive credentials but show the first and last 4 chars if (value && value.length > 8) { sanitized[key] = "".concat(value.substring(0, 4), "...").concat(value.substring(value.length - 4)); } else if (value) { sanitized[key] = '********'; } } else { sanitized[key] = value; } }); return sanitized; }; AuthError.prototype.toJSON = function () { return __assign(__assign({}, _super.prototype.toJSON.call(this)), { credentials: this.credentials }); }; return AuthError; }(ClientError)); exports.AuthError = AuthError; /** * Request timeout errors */ var TimeoutError = /** @class */ (function (_super) { __extends(TimeoutError, _super); function TimeoutError(message, request, endpoint, method, url) { if (message === void 0) { message = 'Request timed out'; } if (request === void 0) { request = null; } if (endpoint === void 0) { endpoint = ''; } if (method === void 0) { method = ''; } if (url === void 0) { url = ''; } var _this = _super.call(this, message, request, endpoint, method, url) || this; _this.name = 'TimeoutError'; Object.setPrototypeOf(_this, TimeoutError.prototype); return _this; } return TimeoutError; }(NetworkError)); exports.TimeoutError = TimeoutError; /** * Rate limiting errors */ var RateLimitError = /** @class */ (function (_super) { __extends(RateLimitError, _super); function RateLimitError(message, retryAfter, status, statusText, endpoint, method, url, data) { if (status === void 0) { status = 429; } if (statusText === void 0) { statusText = 'Too Many Requests'; } if (endpoint === void 0) { endpoint = ''; } if (method === void 0) { method = ''; } if (url === void 0) { url = ''; } if (data === void 0) { data = null; } var _this = _super.call(this, message, status, statusText, endpoint, method, url, data) || this; _this.name = 'RateLimitError'; _this.retryAfter = retryAfter; Object.setPrototypeOf(_this, RateLimitError.prototype); return _this; } RateLimitError.prototype.toJSON = function () { return __assign(__assign({}, _super.prototype.toJSON.call(this)), { retryAfter: this.retryAfter }); }; return RateLimitError; }(ClientError)); exports.RateLimitError = RateLimitError; /** * Validation errors (400 with specific validation failures) */ var ValidationError = /** @class */ (function (_super) { __extends(ValidationError, _super); function ValidationError(message, validationErrors, status, statusText, endpoint, method, url, data) { if (validationErrors === void 0) { validationErrors = {}; } if (status === void 0) { status = 400; } if (statusText === void 0) { statusText = 'Bad Request'; } if (endpoint === void 0) { endpoint = ''; } if (method === void 0) { method = ''; } if (url === void 0) { url = ''; } if (data === void 0) { data = null; } var _this = _super.call(this, message, status, statusText, endpoint, method, url, data) || this; _this.name = 'ValidationError'; _this.validationErrors = validationErrors; Object.setPrototypeOf(_this, ValidationError.prototype); return _this; } ValidationError.prototype.toJSON = function () { return __assign(__assign({}, _super.prototype.toJSON.call(this)), { validationErrors: this.validationErrors }); }; return ValidationError; }(ClientError)); exports.ValidationError = ValidationError; /** * Creates the appropriate error type based on HTTP status code */ function createErrorFromResponse(response) { var _a, _b, _c; var status = response.status, statusText = response.statusText, config = response.config, data = response.data; var method = ((_a = config === null || config === void 0 ? void 0 : config.method) === null || _a === void 0 ? void 0 : _a.toUpperCase()) || 'UNKNOWN'; var endpoint = (config === null || config === void 0 ? void 0 : config.url) || ''; var baseUrl = (config === null || config === void 0 ? void 0 : config.baseURL) || ''; var url = baseUrl ? "".concat(baseUrl).concat(endpoint) : endpoint; var message = "".concat(status, " ").concat(statusText, " - ").concat(method, " ").concat(endpoint); // Extract credentials for auth errors var credentials = {}; if ((_b = config === null || config === void 0 ? void 0 : config.headers) === null || _b === void 0 ? void 0 : _b['Authorization']) { credentials['Authorization'] = config.headers['Authorization']; } if ((_c = config === null || config === void 0 ? void 0 : config.headers) === null || _c === void 0 ? void 0 : _c['x-api-key']) { credentials['x-api-key'] = config.headers['x-api-key']; } // Extract validation errors if present var validationErrors = {}; if (status === 400 && (data === null || data === void 0 ? void 0 : data.errors) && typeof data.errors === 'object') { Object.entries(data.errors).forEach(function (_a) { var key = _a[0], values = _a[1]; validationErrors[key] = Array.isArray(values) ? values : [String(values)]; }); } // Handle specific error types based on status code if (status === 401 || status === 403) { return new AuthError(message, status, statusText, endpoint, method, url, data, credentials); } else if (status === 429) { var retryAfter = response.headers['retry-after'] ? parseInt(response.headers['retry-after'], 10) : undefined; return new RateLimitError(message, retryAfter, status, statusText, endpoint, method, url, data); } else if (status === 400 && Object.keys(validationErrors).length > 0) { return new ValidationError(message, validationErrors, status, statusText, endpoint, method, url, data); } else if (status >= 400 && status < 500) { return new ClientError(message, status, statusText, endpoint, method, url, data); } else if (status >= 500) { return new ServerError(message, status, statusText, endpoint, method, url, data); } return new HttpError(message, status, statusText, endpoint, method, url, data); } exports.createErrorFromResponse = createErrorFromResponse; //# sourceMappingURL=http-error.js.map