UNPKG

@zxkane/quip-mcp-server

Version:

MCP server for interacting with Quip spreadsheets

342 lines 12.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.logger = exports.Logger = exports.LogLevel = void 0; exports.configureLogger = configureLogger; /** * Structured logging for the Quip MCP Server * Using Winston logging library */ const winston_1 = __importDefault(require("winston")); const path = __importStar(require("path")); const fs = __importStar(require("fs")); /** * Log levels */ var LogLevel; (function (LogLevel) { LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG"; LogLevel[LogLevel["INFO"] = 1] = "INFO"; LogLevel[LogLevel["WARN"] = 2] = "WARN"; LogLevel[LogLevel["ERROR"] = 3] = "ERROR"; })(LogLevel || (exports.LogLevel = LogLevel = {})); // Map our LogLevel enum to Winston's levels const levelMap = { [LogLevel.DEBUG]: 'debug', [LogLevel.INFO]: 'info', [LogLevel.WARN]: 'warn', [LogLevel.ERROR]: 'error' }; // Map Winston's levels back to our LogLevel enum const reverseLevelMap = { 'debug': LogLevel.DEBUG, 'info': LogLevel.INFO, 'warn': LogLevel.WARN, 'error': LogLevel.ERROR }; /** * Logger class for structured logging using Winston */ class Logger { /** * Create a new logger * * @param config Logger configuration * @param context Additional context to include in all log entries */ constructor(config = {}, context = {}) { // Store original console methods this.originalConsole = { debug: console.debug, info: console.info, warn: console.warn, error: console.error }; const level = config.level ?? LogLevel.WARN; const shouldUseTimestamps = config.timestamps ?? true; const shouldUseJSON = config.json ?? false; const logFile = config.logFile; const maxFileSize = config.maxFileSize ?? 10 * 1024 * 1024; // 10MB default const maxFiles = config.maxFiles ?? 5; // Create format based on configuration let format; if (shouldUseJSON) { format = winston_1.default.format.combine(shouldUseTimestamps ? winston_1.default.format.timestamp() : winston_1.default.format.simple(), winston_1.default.format.json()); } else { const customFormat = winston_1.default.format.printf(({ level, message, timestamp, ...rest }) => { const prefix = shouldUseTimestamps && timestamp ? `[${timestamp}] ${level.toUpperCase()}: ` : `${level.toUpperCase()}: `; let output = `${prefix}${message}`; // Add any additional data as JSON const additionalData = { ...rest }; delete additionalData.level; delete additionalData.message; delete additionalData.timestamp; if (Object.keys(additionalData).length > 0) { output += ` ${JSON.stringify(additionalData)}`; } return output; }); format = winston_1.default.format.combine(shouldUseTimestamps ? winston_1.default.format.timestamp() : winston_1.default.format.simple(), customFormat); } // Create transports array const transports = [ new winston_1.default.transports.Console() ]; // Add file transport if logFile is specified if (logFile) { // Ensure directory exists const logDir = path.dirname(logFile); if (!fs.existsSync(logDir)) { fs.mkdirSync(logDir, { recursive: true }); } transports.push(new winston_1.default.transports.File({ filename: logFile, maxsize: maxFileSize, maxFiles: maxFiles, tailable: true })); } // Create winston logger this.logger = winston_1.default.createLogger({ level: levelMap[level], format: format, transports: transports }); this.context = context; } /** * Create a child logger with additional context * * @param context Additional context to include in all log entries * @returns New logger instance with combined context */ child(context) { // Create new logger with the same configuration const childLogger = new Logger({ level: reverseLevelMap[this.logger.level], timestamps: true, json: false }, { ...this.context, ...context }); return childLogger; } /** * Log a message at DEBUG level * * @param message Log message * @param data Additional data to include in the log entry */ debug(message, data = {}) { this.log(LogLevel.DEBUG, message, data); } /** * Log a message at INFO level * * @param message Log message * @param data Additional data to include in the log entry */ info(message, data = {}) { this.log(LogLevel.INFO, message, data); } /** * Log a message at WARN level * * @param message Log message * @param data Additional data to include in the log entry */ warn(message, data = {}) { this.log(LogLevel.WARN, message, data); } /** * Log a message at ERROR level * * @param message Log message * @param data Additional data to include in the log entry */ error(message, data = {}) { this.log(LogLevel.ERROR, message, data); } /** * Log a message at the specified level * * @param level Log level * @param message Log message * @param data Additional data to include in the log entry */ log(level, message, data = {}) { // Skip if level is below configured minimum if (level < reverseLevelMap[this.logger.level]) { return; } // Build log entry const logData = { message }; // Add context and data if (Object.keys(this.context).length > 0) { logData.context = this.context; } if (Object.keys(data).length > 0) { logData.data = data; } // Log using winston - avoid passing message twice this.logger.log(levelMap[level], message, { context: logData.context, data: logData.data }); } /** * Configure global console methods to use this logger */ installAsGlobal() { // Override console methods console.debug = (message, ...args) => { if (typeof message === 'string') { this.debug(message, args.length > 0 ? { args } : {}); } else { this.originalConsole.debug(message, ...args); } }; console.info = (message, ...args) => { if (typeof message === 'string') { this.info(message, args.length > 0 ? { args } : {}); } else { this.originalConsole.info(message, ...args); } }; console.warn = (message, ...args) => { if (typeof message === 'string') { this.warn(message, args.length > 0 ? { args } : {}); } else { this.originalConsole.warn(message, ...args); } }; console.error = (message, ...args) => { if (typeof message === 'string') { this.error(message, args.length > 0 ? { args } : {}); } else { this.originalConsole.error(message, ...args); } }; } /** * Reconfigure an existing logger with new settings * * @param config Logger configuration */ reconfigure(config = {}) { const level = config.level ?? LogLevel.WARN; const shouldUseTimestamps = config.timestamps ?? true; const shouldUseJSON = config.json ?? false; const logFile = config.logFile; const maxFileSize = config.maxFileSize ?? 10 * 1024 * 1024; // 10MB default const maxFiles = config.maxFiles ?? 5; // Create format based on configuration let format; if (shouldUseJSON) { format = winston_1.default.format.combine(shouldUseTimestamps ? winston_1.default.format.timestamp() : winston_1.default.format.simple(), winston_1.default.format.json()); } else { const customFormat = winston_1.default.format.printf(({ level, message, timestamp, ...rest }) => { const prefix = shouldUseTimestamps && timestamp ? `[${timestamp}] ${level.toUpperCase()}: ` : `${level.toUpperCase()}: `; let output = `${prefix}${message}`; // Add any additional data as JSON const additionalData = { ...rest }; delete additionalData.level; delete additionalData.message; delete additionalData.timestamp; if (Object.keys(additionalData).length > 0) { output += ` ${JSON.stringify(additionalData)}`; } return output; }); format = winston_1.default.format.combine(shouldUseTimestamps ? winston_1.default.format.timestamp() : winston_1.default.format.simple(), customFormat); } // Create transports array const transports = [ new winston_1.default.transports.Console() ]; // Add file transport if logFile is specified if (logFile) { // Ensure directory exists const logDir = path.dirname(logFile); if (!fs.existsSync(logDir)) { fs.mkdirSync(logDir, { recursive: true }); } transports.push(new winston_1.default.transports.File({ filename: logFile, maxsize: maxFileSize, maxFiles: maxFiles, tailable: true })); } // Update winston logger configuration this.logger.configure({ level: levelMap[level], format: format, transports: transports }); } } exports.Logger = Logger; // Create default logger instance exports.logger = new Logger(); /** * Configure logger from command line options * * @param options Command line options * @returns Configured logger instance */ function configureLogger(options = {}) { const config = { level: options.debug ? LogLevel.DEBUG : LogLevel.WARN, json: options.json || false, timestamps: true, logFile: options.logFile }; // Update the existing logger instead of creating a new one exports.logger.reconfigure(config); // Install as global logger exports.logger.installAsGlobal(); return exports.logger; } //# sourceMappingURL=logger.js.map