UNPKG

@catbee/utils

Version:

A modular, production-grade utility toolkit for Node.js and TypeScript, designed for robust, scalable applications (including Express-based services). All utilities are tree-shakable and can be imported independently.

539 lines 22.1 kB
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 __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()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; import { HttpStatusCodes } from "./http-status-codes"; import { getLogger } from "./logger.utils"; import { ErrorResponse } from "./response.utils"; /** * Generic HTTP error class used for custom exceptions with any status code. * Inherit this when you need to throw errors dynamically at runtime. */ var HttpError = /** @class */ (function (_super) { __extends(HttpError, _super); /** * Creates a new HTTP error instance. * @param status - A valid HTTP status code (e.g., 400, 500). * @param message - The error message to return to the client. */ function HttpError(status, message) { var _this = _super.call(this, message) || this; _this.status = status; return _this; } return HttpError; }(ErrorResponse)); export { HttpError }; /** * Represents a 500 Internal Server Error. * Use this for unexpected backend errors that are not caused by the client. */ var InternalServerErrorException = /** @class */ (function (_super) { __extends(InternalServerErrorException, _super); /** * @param message - Optional custom message. Defaults to "Internal server error". */ function InternalServerErrorException(message) { if (message === void 0) { message = "Internal server error"; } var _this = _super.call(this, message) || this; _this.status = HttpStatusCodes.INTERNAL_SERVER_ERROR; return _this; } return InternalServerErrorException; }(ErrorResponse)); export { InternalServerErrorException }; /** * Represents a 401 Unauthorized Error. * Indicates that authentication is required and has failed or not been provided. */ var UnauthorizedException = /** @class */ (function (_super) { __extends(UnauthorizedException, _super); /** * @param message - Optional custom message. Defaults to "Unauthorized". */ function UnauthorizedException(message) { if (message === void 0) { message = "Unauthorized"; } var _this = _super.call(this, message) || this; _this.status = HttpStatusCodes.UNAUTHORIZED; return _this; } return UnauthorizedException; }(ErrorResponse)); export { UnauthorizedException }; /** * Represents a 400 Bad Request Error. * Indicates that the client has sent invalid data (e.g., malformed request body). */ var BadRequestException = /** @class */ (function (_super) { __extends(BadRequestException, _super); /** * @param message - Optional custom message. Defaults to "Bad request". */ function BadRequestException(message) { if (message === void 0) { message = "Bad request"; } var _this = _super.call(this, message) || this; _this.status = HttpStatusCodes.BAD_REQUEST; return _this; } return BadRequestException; }(ErrorResponse)); export { BadRequestException }; /** * Represents a 404 Not Found Error. * Used when a requested resource (e.g., user, file) could not be located. */ var NotFoundException = /** @class */ (function (_super) { __extends(NotFoundException, _super); /** * @param message - Optional custom message. Defaults to "Resource not found". */ function NotFoundException(message) { if (message === void 0) { message = "Resource not found"; } var _this = _super.call(this, message) || this; _this.status = HttpStatusCodes.NOT_FOUND; return _this; } return NotFoundException; }(ErrorResponse)); export { NotFoundException }; /** * Represents a 403 Forbidden Error. * Indicates that the client is authenticated but not allowed to access the resource. */ var ForbiddenException = /** @class */ (function (_super) { __extends(ForbiddenException, _super); /** * @param message - Optional custom message. Defaults to "Forbidden". */ function ForbiddenException(message) { if (message === void 0) { message = "Forbidden"; } var _this = _super.call(this, message) || this; _this.status = HttpStatusCodes.FORBIDDEN; return _this; } return ForbiddenException; }(ErrorResponse)); export { ForbiddenException }; /** * Represents a 409 Conflict Error. * Commonly used when a resource already exists or a versioning conflict occurs. */ var ConflictException = /** @class */ (function (_super) { __extends(ConflictException, _super); /** * @param message - Optional custom message. Defaults to "Conflict". */ function ConflictException(message) { if (message === void 0) { message = "Conflict"; } var _this = _super.call(this, message) || this; _this.status = HttpStatusCodes.CONFLICT; return _this; } return ConflictException; }(ErrorResponse)); export { ConflictException }; /** * Represents a 502 Bad Gateway Error. * Used when the server receives an invalid response from an upstream server. */ var BadGatewayException = /** @class */ (function (_super) { __extends(BadGatewayException, _super); /** * @param message - Optional custom message. Defaults to "Bad Gateway". */ function BadGatewayException(message) { if (message === void 0) { message = "Bad Gateway"; } var _this = _super.call(this, message) || this; _this.status = HttpStatusCodes.BAD_GATEWAY; return _this; } return BadGatewayException; }(ErrorResponse)); export { BadGatewayException }; /** * Represents a 429 Too Many Requests Error. * Returned when the client has hit a rate limit. */ var TooManyRequestsException = /** @class */ (function (_super) { __extends(TooManyRequestsException, _super); /** * @param message - Optional custom message. Defaults to "Too many requests". */ function TooManyRequestsException(message) { if (message === void 0) { message = "Too many requests"; } var _this = _super.call(this, message) || this; _this.status = HttpStatusCodes.TOO_MANY_REQUESTS; return _this; } return TooManyRequestsException; }(ErrorResponse)); export { TooManyRequestsException }; /** * Represents a 503 Service Unavailable Error. * Indicates that the server is temporarily unavailable (e.g., for maintenance). */ var ServiceUnavailableException = /** @class */ (function (_super) { __extends(ServiceUnavailableException, _super); /** * @param message - Optional custom message. Defaults to "Service Unavailable". */ function ServiceUnavailableException(message) { if (message === void 0) { message = "Service Unavailable"; } var _this = _super.call(this, message) || this; _this.status = HttpStatusCodes.SERVICE_UNAVAILABLE; return _this; } return ServiceUnavailableException; }(ErrorResponse)); export { ServiceUnavailableException }; /** * Represents a 504 Gateway Timeout Error. * Returned when the server acting as a gateway times out waiting for a response. */ var GatewayTimeoutException = /** @class */ (function (_super) { __extends(GatewayTimeoutException, _super); /** * @param message - Optional custom message. Defaults to "Gateway Timeout". */ function GatewayTimeoutException(message) { if (message === void 0) { message = "Gateway Timeout"; } var _this = _super.call(this, message) || this; _this.status = HttpStatusCodes.GATEWAY_TIMEOUT; return _this; } return GatewayTimeoutException; }(ErrorResponse)); export { GatewayTimeoutException }; /** * Represents a 422 Unprocessable Entity Error. * Used when the server understands the content type but cannot process the contained instructions. */ var UnprocessableEntityException = /** @class */ (function (_super) { __extends(UnprocessableEntityException, _super); /** * @param message - Optional custom message. Defaults to "Unprocessable Entity". * @param details - Optional validation details or additional error context. */ function UnprocessableEntityException(message, details) { if (message === void 0) { message = "Unprocessable Entity"; } var _this = _super.call(this, message) || this; _this.details = details; _this.status = HttpStatusCodes.UNPROCESSABLE_ENTITY; return _this; } return UnprocessableEntityException; }(ErrorResponse)); export { UnprocessableEntityException }; /** * Represents a 405 Method Not Allowed Error. * Used when the request method is not supported for the requested resource. */ var MethodNotAllowedException = /** @class */ (function (_super) { __extends(MethodNotAllowedException, _super); /** * @param message - Optional custom message. Defaults to "Method Not Allowed". * @param allowedMethods - Optional array of allowed HTTP methods. */ function MethodNotAllowedException(message, allowedMethods) { if (message === void 0) { message = "Method Not Allowed"; } var _this = _super.call(this, message) || this; _this.allowedMethods = allowedMethods; _this.status = HttpStatusCodes.METHOD_NOT_ALLOWED; return _this; } return MethodNotAllowedException; }(ErrorResponse)); export { MethodNotAllowedException }; /** * Represents a 406 Not Acceptable Error. * Used when the server cannot produce a response matching the client's accepted content types. */ var NotAcceptableException = /** @class */ (function (_super) { __extends(NotAcceptableException, _super); /** * @param message - Optional custom message. Defaults to "Not Acceptable". */ function NotAcceptableException(message) { if (message === void 0) { message = "Not Acceptable"; } var _this = _super.call(this, message) || this; _this.status = HttpStatusCodes.NOT_ACCEPTABLE; return _this; } return NotAcceptableException; }(ErrorResponse)); export { NotAcceptableException }; /** * Represents a 408 Request Timeout Error. * Used when the server times out waiting for the client to send a request. */ var RequestTimeoutException = /** @class */ (function (_super) { __extends(RequestTimeoutException, _super); /** * @param message - Optional custom message. Defaults to "Request Timeout". */ function RequestTimeoutException(message) { if (message === void 0) { message = "Request Timeout"; } var _this = _super.call(this, message) || this; _this.status = HttpStatusCodes.REQUEST_TIMEOUT; return _this; } return RequestTimeoutException; }(ErrorResponse)); export { RequestTimeoutException }; /** * Represents a 415 Unsupported Media Type Error. * Used when the request's Content-Type is not supported. */ var UnsupportedMediaTypeException = /** @class */ (function (_super) { __extends(UnsupportedMediaTypeException, _super); /** * @param message - Optional custom message. Defaults to "Unsupported Media Type". */ function UnsupportedMediaTypeException(message) { if (message === void 0) { message = "Unsupported Media Type"; } var _this = _super.call(this, message) || this; _this.status = HttpStatusCodes.UNSUPPORTED_MEDIA_TYPE; return _this; } return UnsupportedMediaTypeException; }(ErrorResponse)); export { UnsupportedMediaTypeException }; /** * Represents a 413 Payload Too Large Error. * Used when the request body exceeds server limits. */ var PayloadTooLargeException = /** @class */ (function (_super) { __extends(PayloadTooLargeException, _super); /** * @param message - Optional custom message. Defaults to "Payload Too Large". */ function PayloadTooLargeException(message) { if (message === void 0) { message = "Payload Too Large"; } var _this = _super.call(this, message) || this; _this.status = HttpStatusCodes.PAYLOAD_TOO_LARGE; return _this; } return PayloadTooLargeException; }(ErrorResponse)); export { PayloadTooLargeException }; /** * Represents a 507 Insufficient Storage Error. * Used when the server has insufficient storage to complete the request. */ var InsufficientStorageException = /** @class */ (function (_super) { __extends(InsufficientStorageException, _super); /** * @param message - Optional custom message. Defaults to "Insufficient Storage". */ function InsufficientStorageException(message) { if (message === void 0) { message = "Insufficient Storage"; } var _this = _super.call(this, message) || this; _this.status = HttpStatusCodes.INSUFFICIENT_STORAGE; return _this; } return InsufficientStorageException; }(ErrorResponse)); export { InsufficientStorageException }; /** * Checks if an error is an instance of HttpError or its subclasses. * * @param error - The error to check. * @returns True if the error is an HttpError, false otherwise. */ export function isHttpError(error) { return error instanceof ErrorResponse; } /** * Creates an HTTP error with the specified status code and message. * Factory function for creating appropriate HTTP error instances. * * @param status - HTTP status code. * @param message - Optional custom error message. * @returns An instance of the appropriate HTTP error class. */ export function createHttpError(status, message) { switch (status) { case HttpStatusCodes.BAD_REQUEST: return new BadRequestException(message); case HttpStatusCodes.UNAUTHORIZED: return new UnauthorizedException(message); case HttpStatusCodes.FORBIDDEN: return new ForbiddenException(message); case HttpStatusCodes.NOT_FOUND: return new NotFoundException(message); case HttpStatusCodes.METHOD_NOT_ALLOWED: return new MethodNotAllowedException(message); case HttpStatusCodes.NOT_ACCEPTABLE: return new NotAcceptableException(message); case HttpStatusCodes.REQUEST_TIMEOUT: return new RequestTimeoutException(message); case HttpStatusCodes.CONFLICT: return new ConflictException(message); case HttpStatusCodes.GONE: return new HttpError(HttpStatusCodes.GONE, message || "Gone"); case HttpStatusCodes.PAYLOAD_TOO_LARGE: return new PayloadTooLargeException(message); case HttpStatusCodes.UNSUPPORTED_MEDIA_TYPE: return new UnsupportedMediaTypeException(message); case HttpStatusCodes.UNPROCESSABLE_ENTITY: return new UnprocessableEntityException(message); case HttpStatusCodes.TOO_MANY_REQUESTS: return new TooManyRequestsException(message); case HttpStatusCodes.INTERNAL_SERVER_ERROR: return new InternalServerErrorException(message); case HttpStatusCodes.BAD_GATEWAY: return new BadGatewayException(message); case HttpStatusCodes.SERVICE_UNAVAILABLE: return new ServiceUnavailableException(message); case HttpStatusCodes.GATEWAY_TIMEOUT: return new GatewayTimeoutException(message); case HttpStatusCodes.INSUFFICIENT_STORAGE: return new InsufficientStorageException(message); default: return new HttpError(status, message || "HTTP Error ".concat(status)); } } /** * Type guard to check if an object has specific error properties. * * @param error - The object to check. * @returns True if object has error-like structure. */ export function hasErrorShape(error) { return (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string"); } /** * Safely extracts message from any error type. * * @param error - Any error object or value. * @returns A string error message. */ export function getErrorMessage(error) { if (typeof error === "string") { return error; } if (error instanceof Error) { return error.message; } if (hasErrorShape(error)) { return error.message; } return "Unknown error occurred"; } /** * Wraps a function and transforms any errors into HTTP errors. * Useful for API handlers to ensure consistent error responses. * * @param handler - The async function to wrap. * @returns A function that always returns or throws an HTTP error. */ export function withErrorHandling(handler) { var _this = this; return function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return __awaiter(_this, void 0, void 0, function () { var error_1, status_1; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4 /*yield*/, handler.apply(void 0, __spreadArray([], __read(args), false))]; case 1: return [2 /*return*/, _a.sent()]; case 2: error_1 = _a.sent(); if (isHttpError(error_1)) { throw error_1; } // Log the original error (consider using a proper logger) getLogger().error("Caught error in handler:", error_1); status_1 = HttpStatusCodes.INTERNAL_SERVER_ERROR; if (hasErrorShape(error_1) && typeof error_1.status === "number") { status_1 = error_1.status; } // Create appropriate HTTP error throw createHttpError(status_1, getErrorMessage(error_1)); case 3: return [2 /*return*/]; } }); }); }; } //# sourceMappingURL=exception.utils.js.map