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.

226 lines (222 loc) 6.5 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. */ import { TTLCache } from '@catbee/utils/cache'; import { getLogger } from '@catbee/utils/logger'; var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); function timeSync(fn, options = {}) { const { label = fn.name || "anonymous function", log = false, logLevel = "debug" } = options; const startTime = performance.now(); const result = fn(); const endTime = performance.now(); const durationMs = endTime - startTime; const durationSec = durationMs / 1e3; const timing = { durationMs, durationSec, startTime, endTime, label }; if (log) { const logger = getLogger(); const message = `${label} completed in ${durationMs.toFixed(2)}ms`; switch (logLevel) { case "trace": logger.trace({ timing }, message); break; case "debug": logger.debug({ timing }, message); break; case "info": logger.info({ timing }, message); break; case "warn": logger.warn({ timing }, message); break; case "error": logger.error({ timing }, message); break; default: logger.debug({ timing }, message); break; } } return { result, timing }; } __name(timeSync, "timeSync"); async function timeAsync(fn, options = {}) { const { label = fn.name || "anonymous async function", log = false, logLevel = "debug" } = options; const startTime = performance.now(); const result = await fn(); const endTime = performance.now(); const durationMs = endTime - startTime; const durationSec = durationMs / 1e3; const timing = { durationMs, durationSec, startTime, endTime, label }; if (log) { const logger = getLogger(); const message = `${label} completed in ${durationMs.toFixed(2)}ms`; switch (logLevel) { case "trace": logger.trace({ timing }, message); break; case "debug": logger.debug({ timing }, message); break; case "info": logger.info({ timing }, message); break; case "warn": logger.warn({ timing }, message); break; case "error": logger.error({ timing }, message); break; default: logger.debug({ timing }, message); break; } } return { result, timing }; } __name(timeAsync, "timeAsync"); function timed(options = {}) { return function(target, propertyKeyOrContext, descriptor) { let propertyKey; let actualDescriptor; if (typeof propertyKeyOrContext === "object" && propertyKeyOrContext !== null && "name" in propertyKeyOrContext) { propertyKey = propertyKeyOrContext.name; actualDescriptor = descriptor ?? Object.getOwnPropertyDescriptor(target, propertyKey); } else { propertyKey = propertyKeyOrContext; actualDescriptor = descriptor ?? Object.getOwnPropertyDescriptor(target, propertyKey); } const originalMethod = actualDescriptor.value; actualDescriptor.value = function(...args) { const methodOptions = { ...options, label: options.label || `${target.constructor.name}.${String(propertyKey)}` }; if (originalMethod.constructor.name === "AsyncFunction") { return timeAsync(() => originalMethod.apply(this, args), methodOptions).then(({ result }) => result); } else { return timeSync(() => originalMethod.apply(this, args), methodOptions).result; } }; if (descriptor) { descriptor.value = actualDescriptor.value; } else { Object.defineProperty(target, propertyKey, actualDescriptor); } }; } __name(timed, "timed"); function memoize(fn, options = {}) { const { ttl, maxSize, autoCleanupMs, cacheKey = /* @__PURE__ */ __name((...args) => JSON.stringify(args), "cacheKey") } = options; const cache = new TTLCache({ ttlMs: ttl, maxSize, autoCleanupMs }); return function(...args) { const key = cacheKey(...args); const cachedValue = cache.get(key); if (cachedValue !== void 0) { return cachedValue; } const value = fn(...args); cache.set(key, value); return value; }; } __name(memoize, "memoize"); function trackMemoryUsage(fn, options = {}) { const { log = false, label = fn.name || "anonymous function" } = options; if (globalThis.gc) { globalThis.gc(); } const beforeMemory = process.memoryUsage(); const result = fn(); const afterMemory = process.memoryUsage(); const diff = {}; for (const key in afterMemory) { if (Object.hasOwn(afterMemory, key)) { diff[key] = afterMemory[key] - beforeMemory[key]; } } if (log) { getLogger().info({ label, memoryBefore: beforeMemory, memoryAfter: afterMemory, memoryDiff: diff }, `Memory usage for ${label}`); } return { result, memoryUsage: { before: beforeMemory, after: afterMemory, diff } }; } __name(trackMemoryUsage, "trackMemoryUsage"); export { memoize, timeAsync, timeSync, timed, trackMemoryUsage };