UNPKG

mcp-quickbase

Version:

Work with Quickbase via Model Context Protocol

146 lines 4.54 kB
"use strict"; /** * Logger utility for the Quickbase connector */ Object.defineProperty(exports, "__esModule", { value: true }); exports.LogLevel = void 0; exports.setLogLevel = setLogLevel; exports.getLogLevel = getLogLevel; exports.createLogger = createLogger; /** * Log levels */ var LogLevel; (function (LogLevel) { LogLevel[LogLevel["ERROR"] = 0] = "ERROR"; LogLevel[LogLevel["WARN"] = 1] = "WARN"; LogLevel[LogLevel["INFO"] = 2] = "INFO"; LogLevel[LogLevel["DEBUG"] = 3] = "DEBUG"; })(LogLevel || (exports.LogLevel = LogLevel = {})); // Global log level (can be set via environment variable) let globalLogLevel = process.env.LOG_LEVEL ? LogLevel[process.env.LOG_LEVEL.toUpperCase()] || LogLevel.INFO : LogLevel.INFO; /** * Set the global log level * @param level New log level */ function setLogLevel(level) { if (typeof level === "string") { globalLogLevel = LogLevel[level.toUpperCase()] || LogLevel.INFO; } else { globalLogLevel = level; } } /** * Get the current global log level * @returns Current log level */ function getLogLevel() { return LogLevel[globalLogLevel] || "INFO"; } /** * Creates a logger with the specified name * @param name Logger name * @returns Logger instance */ function createLogger(name) { const formatData = (data) => { if (data === undefined) return ""; try { return JSON.stringify(redactSensitiveData(data)); } catch (error) { // Safe error message formatting to prevent nested serialization issues const errorMessage = error instanceof Error ? error.message : String(error); return `[Unserializable data: ${errorMessage}]`; } }; return { error(message, data) { if (globalLogLevel >= LogLevel.ERROR) { // Use stderr to avoid interfering with JSON responses on stdout process.stderr.write(`[ERROR] ${name}: ${message} ${data ? formatData(data) : ""}\n`); } }, warn(message, data) { if (globalLogLevel >= LogLevel.WARN) { // Use stderr to avoid interfering with JSON responses on stdout process.stderr.write(`[WARN] ${name}: ${message} ${data ? formatData(data) : ""}\n`); } }, info(message, data) { if (globalLogLevel >= LogLevel.INFO) { // Use stderr to avoid interfering with JSON responses on stdout process.stderr.write(`[INFO] ${name}: ${message} ${data ? formatData(data) : ""}\n`); } }, debug(message, data) { if (globalLogLevel >= LogLevel.DEBUG) { // Use stderr to avoid interfering with JSON responses on stdout process.stderr.write(`[DEBUG] ${name}: ${message} ${data ? formatData(data) : ""}\n`); } }, }; } /** * Sensitive keys that should be redacted */ const SENSITIVE_KEYS = [ "token", "password", "secret", "auth", "key", "credential", "Authorization", "QB-USER-TOKEN", "userToken", "QUICKBASE_USER_TOKEN", ]; /** * Redacts sensitive data in objects with circular reference protection * @param data Object to redact * @returns Redacted object */ function redactSensitiveData(data) { const visited = new WeakSet(); function redactRecursive(obj) { if (!obj || typeof obj !== "object") { return obj; } // Circular reference protection if (visited.has(obj)) { return "[Circular Reference]"; } visited.add(obj); if (Array.isArray(obj)) { return obj.map((item) => redactRecursive(item)); } const result = {}; try { for (const [key, value] of Object.entries(obj)) { if (typeof value === "object" && value !== null) { result[key] = redactRecursive(value); } else if (typeof value === "string" && SENSITIVE_KEYS.some((k) => key.toLowerCase().includes(k.toLowerCase()))) { result[key] = "***REDACTED***"; } else { result[key] = value; } } } catch (error) { return "[Unserializable Object]"; } return result; } return redactRecursive(data); } //# sourceMappingURL=logger.js.map