@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.
233 lines • 9.21 kB
JavaScript
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 __());
};
})();
import { randomUUID } from "crypto";
import { getRequestId } from "./context-store.utils";
/**
* Standard HTTP response wrapper for successful responses.
* Implements the `ApiResponse<T>` interface and sets default values.
*
* @typeParam T - The shape of the data returned in the response.
*/
var SuccessResponse = /** @class */ (function () {
/**
* Constructs a new success response.
*
* @param {string} message - Optional message to override the default.
* @param {T} [data] - Optional data payload.
*/
function SuccessResponse(message, data) {
var _a;
/** Message describing the result of the operation. */
this.message = "Success";
/** Whether the response is an error. Always false in success responses. */
this.error = false;
/** The payload returned from the API. */
this.data = null;
/** Timestamp when the response was generated, in ISO format. */
this.timestamp = new Date().toISOString();
/** Unique identifier for this response, useful for request tracing. */
this.requestId = (_a = getRequestId()) !== null && _a !== void 0 ? _a : randomUUID();
if (message)
this.message = message;
this.data = data !== null && data !== void 0 ? data : null;
}
return SuccessResponse;
}());
export { SuccessResponse };
/**
* Wrapper for error responses that extends the native `Error` object.
* Implements `ApiResponse` but omits the `data` field (which should not be present in errors).
*/
var ErrorResponse = /** @class */ (function (_super) {
__extends(ErrorResponse, _super);
/**
* Constructs a new error response.
*
* @param {string} message - The error message to display or log.
* @param {number} [status=500] - Optional HTTP status code (defaults to 500).
*/
function ErrorResponse(message, status) {
if (status === void 0) { status = 500; }
var _a;
var _this = _super.call(this, message) || this;
/** Indicates that this is an error. Always true. */
_this.error = true;
/** Timestamp when the error occurred, in ISO format. */
_this.timestamp = new Date().toISOString();
/** Unique identifier for this error instance. */
_this.requestId = (_a = getRequestId()) !== null && _a !== void 0 ? _a : randomUUID();
_this.status = status;
_this.name = _this.constructor.name;
Error.captureStackTrace(_this, _this.constructor);
return _this;
}
return ErrorResponse;
}(Error));
export { ErrorResponse };
/**
* Response with paginated data extending the standard success response.
* Useful for APIs that return large collections of data.
*
* @typeParam T - The shape of each item in the paginated collection.
*/
var PaginatedResponse = /** @class */ (function (_super) {
__extends(PaginatedResponse, _super);
/**
* Constructs a new paginated response.
*
* @param {T[]} items - The current page of items.
* @param {Object} pagination - Pagination information.
* @param {number} pagination.total - Total number of items across all pages.
* @param {number} pagination.page - Current page number (1-based).
* @param {number} pagination.pageSize - Number of items per page.
* @param {string} [message="Success"] - Optional custom message.
*/
function PaginatedResponse(items, pagination, message) {
if (message === void 0) { message = "Success"; }
var _this = _super.call(this, message, items) || this;
_this.total = pagination.total;
_this.page = pagination.page;
_this.pageSize = pagination.pageSize;
_this.totalPages = Math.ceil(_this.total / _this.pageSize);
_this.hasNext = _this.page < _this.totalPages;
_this.hasPrevious = _this.page > 1;
return _this;
}
return PaginatedResponse;
}(SuccessResponse));
export { PaginatedResponse };
/**
* Specialized response for operations that don't return data (HTTP 204).
*/
var NoContentResponse = /** @class */ (function (_super) {
__extends(NoContentResponse, _super);
/**
* Constructs a new no-content response.
*
* @param {string} [message="Operation completed successfully"] - Optional custom message.
*/
function NoContentResponse(message) {
if (message === void 0) { message = "Operation completed successfully"; }
return _super.call(this, message, null) || this;
}
return NoContentResponse;
}(SuccessResponse));
export { NoContentResponse };
/**
* Specialized response for redirects.
*/
var RedirectResponse = /** @class */ (function () {
/**
* Constructs a new redirect response.
*
* @param {string} url - The URL to redirect to.
* @param {number} [statusCode=302] - HTTP status code for the redirect.
*/
function RedirectResponse(url, statusCode) {
if (statusCode === void 0) { statusCode = 302; }
var _a;
/** Whether the response is a redirect */
this.isRedirect = true;
/** Unique identifier for this response */
this.requestId = (_a = getRequestId()) !== null && _a !== void 0 ? _a : randomUUID();
this.redirectUrl = url;
this.statusCode = statusCode;
}
return RedirectResponse;
}());
export { RedirectResponse };
/**
* Creates a standard success response.
*
* @typeParam T - The shape of the data returned in the response.
* @param {T} data - The data to include in the response.
* @param {string} [message="Success"] - Optional custom message.
* @returns {SuccessResponse<T>} A properly formatted success response.
*/
export function createSuccessResponse(data, message) {
if (message === void 0) { message = "Success"; }
return new SuccessResponse(message, data);
}
/**
* Creates a standard error response.
*
* @param {string} message - The error message.
* @param {number} [statusCode=500] - HTTP status code for the error.
* @returns {ErrorResponse} A properly formatted error response.
*/
export function createErrorResponse(message, statusCode) {
if (statusCode === void 0) { statusCode = 500; }
return new ErrorResponse(message, statusCode);
}
/**
* Creates a paginated response from array data.
*
* @typeParam T - The shape of each item in the collection.
* @param {T[]} allItems - The complete array of items to paginate.
* @param {number} page - The requested page (1-based).
* @param {number} pageSize - The number of items per page.
* @param {string} [message="Success"] - Optional custom message.
* @returns {PaginatedResponse<T>} A properly formatted paginated response.
*/
export function createPaginatedResponse(allItems, page, pageSize, message) {
if (message === void 0) { message = "Success"; }
// Ensure valid pagination parameters
var validPage = Math.max(1, page);
var validPageSize = Math.max(1, pageSize);
// Calculate slice indices
var startIndex = (validPage - 1) * validPageSize;
var endIndex = startIndex + validPageSize;
// Get current page items
var pageItems = allItems.slice(startIndex, endIndex);
return new PaginatedResponse(pageItems, {
total: allItems.length,
page: validPage,
pageSize: validPageSize,
}, message);
}
/**
* Adapter to convert API responses to Express.js response format.
*
* @param {any} res - Express response object.
* @param {SuccessResponse<any> | ErrorResponse | RedirectResponse} apiResponse - API response instance.
*/
export function sendResponse(res, apiResponse) {
// Handle redirects
if ("redirectUrl" in apiResponse) {
res.redirect(apiResponse.statusCode, apiResponse.redirectUrl);
return;
}
// Handle errors
if ("error" in apiResponse && apiResponse.error) {
var errorResponse = apiResponse;
res.status(errorResponse.status).json({
error: true,
message: errorResponse.message,
timestamp: errorResponse.timestamp,
requestId: errorResponse.requestId,
});
return;
}
// Handle success responses
var successResponse = apiResponse;
// No content (204) shouldn't return a body
if (successResponse instanceof NoContentResponse) {
res.status(204).end();
return;
}
res.status(200).json(successResponse);
}
//# sourceMappingURL=response.utils.js.map