mcp-quickbase
Version:
Work with Quickbase via Model Context Protocol
146 lines • 4.54 kB
JavaScript
;
/**
* 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