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.

208 lines 8.11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RedirectResponse = exports.NoContentResponse = exports.PaginatedResponse = exports.ErrorResponse = exports.SuccessResponse = void 0; exports.createSuccessResponse = createSuccessResponse; exports.createErrorResponse = createErrorResponse; exports.createPaginatedResponse = createPaginatedResponse; exports.sendResponse = sendResponse; const crypto_1 = require("crypto"); const context_store_utils_1 = require("./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. */ class SuccessResponse { /** * Constructs a new success response. * * @param {string} message - Optional message to override the default. * @param {T} [data] - Optional data payload. */ constructor(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 = (0, context_store_utils_1.getRequestId)()) !== null && _a !== void 0 ? _a : (0, crypto_1.randomUUID)(); if (message) this.message = message; this.data = data !== null && data !== void 0 ? data : null; } } exports.SuccessResponse = 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). */ class ErrorResponse extends Error { /** * 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). */ constructor(message, status = 500) { var _a; super(message); /** 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 = (0, context_store_utils_1.getRequestId)()) !== null && _a !== void 0 ? _a : (0, crypto_1.randomUUID)(); this.status = status; this.name = this.constructor.name; Error.captureStackTrace(this, this.constructor); } } exports.ErrorResponse = 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. */ class PaginatedResponse extends SuccessResponse { /** * 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. */ constructor(items, pagination, message = "Success") { super(message, items); 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; } } exports.PaginatedResponse = PaginatedResponse; /** * Specialized response for operations that don't return data (HTTP 204). */ class NoContentResponse extends SuccessResponse { /** * Constructs a new no-content response. * * @param {string} [message="Operation completed successfully"] - Optional custom message. */ constructor(message = "Operation completed successfully") { super(message, null); } } exports.NoContentResponse = NoContentResponse; /** * Specialized response for redirects. */ class RedirectResponse { /** * Constructs a new redirect response. * * @param {string} url - The URL to redirect to. * @param {number} [statusCode=302] - HTTP status code for the redirect. */ constructor(url, statusCode = 302) { var _a; /** Whether the response is a redirect */ this.isRedirect = true; /** Unique identifier for this response */ this.requestId = (_a = (0, context_store_utils_1.getRequestId)()) !== null && _a !== void 0 ? _a : (0, crypto_1.randomUUID)(); this.redirectUrl = url; this.statusCode = statusCode; } } exports.RedirectResponse = 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. */ function createSuccessResponse(data, 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. */ function createErrorResponse(message, 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. */ function createPaginatedResponse(allItems, page, pageSize, message = "Success") { // Ensure valid pagination parameters const validPage = Math.max(1, page); const validPageSize = Math.max(1, pageSize); // Calculate slice indices const startIndex = (validPage - 1) * validPageSize; const endIndex = startIndex + validPageSize; // Get current page items const 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. */ 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) { const errorResponse = apiResponse; res.status(errorResponse.status).json({ error: true, message: errorResponse.message, timestamp: errorResponse.timestamp, requestId: errorResponse.requestId, }); return; } // Handle success responses const 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