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.

235 lines (229 loc) 8.24 kB
/* * The MIT License * * Copyright (c) 2026 Catbee Technologies. https://catbee.in/license * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ 'use strict'; var contextStore = require('@catbee/utils/context-store'); var env = require('@catbee/utils/env'); var id = require('@catbee/utils/id'); var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var SuccessResponse = class { static { __name(this, "SuccessResponse"); } /** Message describing the result of the operation. */ message = "Success"; /** Whether the response is an error. Always false in success responses. */ error = false; /** The payload returned from the API. */ data = null; /** Timestamp when the response was generated, in ISO format. */ timestamp = (/* @__PURE__ */ new Date()).toISOString(); /** Unique identifier for this response, useful for request tracing. */ requestId = contextStore.getRequestId() ?? id.uuid(); /** * Constructs a new success response. * * @param {string} message - Optional message to override the default. * @param {T} [data] - Optional data payload. */ constructor(message, data) { if (message) this.message = message; this.data = data ?? null; } }; var ErrorResponse = class extends Error { static { __name(this, "ErrorResponse"); } /** HTTP status code associated with the error (e.g., 404, 500). */ status; /** Indicates that this is an error. Always true. */ error = true; /** Timestamp when the error occurred, in ISO format. */ timestamp = (/* @__PURE__ */ new Date()).toISOString(); /** Unique identifier for this error instance. */ requestId = contextStore.getRequestId() ?? id.uuid(); /** * 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) { super(message); this.status = status; this.name = this.constructor.name; Error.captureStackTrace(this, this.constructor); } }; var PaginatedResponse = class extends SuccessResponse { static { __name(this, "PaginatedResponse"); } /** Total number of items across all pages */ total; /** Current page number (1-based) */ page; /** Number of items per page */ pageSize; /** Total number of pages */ totalPages; /** Whether there's a next page available */ hasNext; /** Whether there's a previous page available */ hasPrevious; /** * 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; } }; var NoContentResponse = class extends SuccessResponse { static { __name(this, "NoContentResponse"); } /** * Constructs a new no-content response. * * @param {string} [message="Operation completed successfully"] - Optional custom message. */ constructor(message = "Operation completed successfully") { super(message, null); } }; var RedirectResponse = class { static { __name(this, "RedirectResponse"); } /** The URL to redirect to */ redirectUrl; /** HTTP status code for the redirect (301, 302, 303, 307, 308) */ statusCode; /** Whether the response is a redirect */ isRedirect = true; /** Unique identifier for this response */ requestId = contextStore.getRequestId() ?? id.uuid(); /** * 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) { this.redirectUrl = url; this.statusCode = statusCode; } }; function createSuccessResponse(data, message = "Success") { return new SuccessResponse(message, data); } __name(createSuccessResponse, "createSuccessResponse"); function createErrorResponse(message, statusCode = 500) { return new ErrorResponse(message, statusCode); } __name(createErrorResponse, "createErrorResponse"); function createFinalErrorResponse(req, status, message, error, options) { const isDev = env.Env.isDev(); const includeDetails = options?.includeDetails && isDev; const response = { error: true, message, timestamp: (/* @__PURE__ */ new Date()).toISOString(), requestId: error?.requestId || req?.id || id.uuid(), status, path: req.originalUrl || req.url }; if (includeDetails && error?.stack) { response.stack = error.stack.split("\n").map((line) => line.trim()); } return response; } __name(createFinalErrorResponse, "createFinalErrorResponse"); function createPaginatedResponse(allItems, page, pageSize, message = "Success") { const validPage = Math.max(1, page); const validPageSize = Math.max(1, pageSize); const startIndex = (validPage - 1) * validPageSize; const endIndex = startIndex + validPageSize; const pageItems = allItems.slice(startIndex, endIndex); return new PaginatedResponse(pageItems, { total: allItems.length, page: validPage, pageSize: validPageSize }, message); } __name(createPaginatedResponse, "createPaginatedResponse"); function sendResponse(res, apiResponse) { if ("redirectUrl" in apiResponse) { res.redirect(apiResponse.statusCode, apiResponse.redirectUrl); return; } 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; } const successResponse = apiResponse; if (successResponse instanceof NoContentResponse) { res.status(204).end(); return; } res.status(200).json(successResponse); } __name(sendResponse, "sendResponse"); // src/types/api-response.ts var SortDirection = /* @__PURE__ */ (function(SortDirection2) { SortDirection2["ASC"] = "asc"; SortDirection2["DESC"] = "desc"; return SortDirection2; })({}); exports.ErrorResponse = ErrorResponse; exports.NoContentResponse = NoContentResponse; exports.PaginatedResponse = PaginatedResponse; exports.RedirectResponse = RedirectResponse; exports.SortDirection = SortDirection; exports.SuccessResponse = SuccessResponse; exports.createErrorResponse = createErrorResponse; exports.createFinalErrorResponse = createFinalErrorResponse; exports.createPaginatedResponse = createPaginatedResponse; exports.createSuccessResponse = createSuccessResponse; exports.sendResponse = sendResponse;