UNPKG

@settlemint/sdk-utils

Version:

Shared utilities and helper functions for SettleMint SDK modules

221 lines (217 loc) • 6.8 kB
//#region src/logging/mask-tokens.ts /** * Masks sensitive SettleMint tokens in output text by replacing them with asterisks. * Handles personal access tokens (PAT), application access tokens (AAT), and service account tokens (SAT). * * @param output - The text string that may contain sensitive tokens * @returns The text with any sensitive tokens masked with asterisks * @example * import { maskTokens } from "@settlemint/sdk-utils/terminal"; * * // Masks a token in text * const masked = maskTokens("Token: sm_pat_****"); // "Token: ***" */ const maskTokens = (output) => { return output.replace(/sm_(pat|aat|sat)_[0-9a-zA-Z]+/g, "***"); }; //#endregion //#region src/logging/logger.ts /** * Creates a simple logger with configurable log level * * @param options - Configuration options for the logger * @param options.level - The minimum log level to output (default: warn) * @param options.prefix - The prefix to add to the log message (default: "") * @returns A logger instance with debug, info, warn, and error methods * * @example * import { createLogger } from "@/utils/logging/logger"; * * const logger = createLogger({ level: 'info' }); * * logger.info('User logged in', { userId: '123' }); * logger.error('Operation failed', new Error('Connection timeout')); */ function createLogger(options = {}) { const { level = "warn", prefix = "" } = options; const logLevels = { debug: 0, info: 1, warn: 2, error: 3, none: 4 }; const currentLevelValue = logLevels[level]; const formatArgs = (args) => { if (args.length === 0 || args.every((arg) => arg === undefined || arg === null)) { return ""; } const formatted = args.map((arg) => { if (arg instanceof Error) { return `\n${arg.stack || arg.message}`; } if (typeof arg === "object" && arg !== null) { return `\n${JSON.stringify(arg, null, 2)}`; } return ` ${String(arg)}`; }).join(""); return `, args:${formatted}`; }; const shouldLog = (level$1) => { return logLevels[level$1] >= currentLevelValue; }; return { debug: (message, ...args) => { if (shouldLog("debug")) { console.debug(`\x1b[32m${prefix}[DEBUG] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1b[0m`); } }, info: (message, ...args) => { if (shouldLog("info")) { console.info(`\x1b[34m${prefix}[INFO] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1b[0m`); } }, warn: (message, ...args) => { if (shouldLog("warn")) { console.warn(`\x1b[33m${prefix}[WARN] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1b[0m`); } }, error: (message, ...args) => { if (shouldLog("error")) { console.error(`\x1b[31m${prefix}[ERROR] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1b[0m`); } } }; } /** * Default logger instance with standard configuration */ const logger = createLogger(); //#endregion //#region src/string.ts /** * Capitalizes the first letter of a string. * * @param val - The string to capitalize * @returns The input string with its first letter capitalized * * @example * import { capitalizeFirstLetter } from "@settlemint/sdk-utils"; * * const capitalized = capitalizeFirstLetter("hello"); * // Returns: "Hello" */ function capitalizeFirstLetter(val) { return String(val).charAt(0).toUpperCase() + String(val).slice(1); } /** * Converts a camelCase string to a human-readable string. * * @param s - The camelCase string to convert * @returns The human-readable string * * @example * import { camelCaseToWords } from "@settlemint/sdk-utils"; * * const words = camelCaseToWords("camelCaseString"); * // Returns: "Camel Case String" */ function camelCaseToWords(s) { const result = s.replace(/([a-z])([A-Z])/g, "$1 $2"); const withSpaces = result.replace(/([A-Z])([a-z])/g, " $1$2"); const capitalized = capitalizeFirstLetter(withSpaces); return capitalized.replace(/\s+/g, " ").trim(); } /** * Replaces underscores and hyphens with spaces. * * @param s - The string to replace underscores and hyphens with spaces * @returns The input string with underscores and hyphens replaced with spaces * * @example * import { replaceUnderscoresAndHyphensWithSpaces } from "@settlemint/sdk-utils"; * * const result = replaceUnderscoresAndHyphensWithSpaces("Already_Spaced-Second"); * // Returns: "Already Spaced Second" */ function replaceUnderscoresAndHyphensWithSpaces(s) { return s.replace(/[-_]/g, " "); } /** * Truncates a string to a maximum length and appends "..." if it is longer. * * @param value - The string to truncate * @param maxLength - The maximum length of the string * @returns The truncated string or the original string if it is shorter than the maximum length * * @example * import { truncate } from "@settlemint/sdk-utils"; * * const truncated = truncate("Hello, world!", 10); * // Returns: "Hello, wor..." */ function truncate(value, maxLength) { if (value.length <= maxLength) { return value; } return `${value.slice(0, maxLength)}...`; } //#endregion //#region src/logging/request-logger.ts const WARNING_THRESHOLD = 500; const TRUNCATE_LENGTH = 50; /** * Logs the request and duration of a fetch call (> 500ms is logged as warn, otherwise info) * @param logger - The logger to use * @param name - The name of the request * @param fn - The fetch function to use * @returns The fetch function */ function requestLogger(logger$1, name, fn) { return async (...args) => { const start = Date.now(); try { return await fn(...args); } finally { const end = Date.now(); const duration = end - start; const body = extractInfoFromBody(args[1]?.body ?? "{}"); const message = `${name} path: ${args[0]}, took ${formatDuration(duration)}`; if (duration > WARNING_THRESHOLD) { logger$1.warn(message, body); } else { logger$1.info(message, body); } } }; } function formatDuration(duration) { return duration < 1e3 ? `${duration}ms` : `${(duration / 1e3).toFixed(3)}s`; } function extractInfoFromBody(body) { try { const parsedBody = typeof body === "string" ? JSON.parse(body) : body; if (parsedBody === null || parsedBody === undefined || Object.keys(parsedBody).length === 0) { return null; } const dataToKeep = {}; if ("query" in parsedBody) { dataToKeep.query = truncate(parsedBody.query, TRUNCATE_LENGTH); } if ("variables" in parsedBody) { dataToKeep.variables = truncate(JSON.stringify(parsedBody.variables), TRUNCATE_LENGTH); } if ("operationName" in parsedBody) { dataToKeep.operationName = truncate(parsedBody.operationName, TRUNCATE_LENGTH); } if (Object.keys(dataToKeep).length > 0) { return JSON.stringify(dataToKeep); } return truncate(JSON.stringify(parsedBody || "{}"), TRUNCATE_LENGTH); } catch { return "{}"; } } //#endregion export { createLogger, maskTokens, requestLogger }; //# sourceMappingURL=logging.js.map