UNPKG

@zxkane/quip-mcp-server

Version:

MCP server for interacting with Quip spreadsheets

247 lines 9.01 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; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.MockQuipClient = void 0; /** * Mock Quip client implementation for testing without a real Quip token */ const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); const logger_1 = require("./logger"); /** * Mock Quip client for testing without a real Quip API token */ class MockQuipClient { /** * Initialize the mock client with sample data */ constructor() { this.mockData = new Map(); logger_1.logger.info('Initializing MockQuipClient'); // Add some sample spreadsheets this.addMockSpreadsheet({ threadId: 'sample1', title: 'Sample Spreadsheet 1', sheets: [ { name: 'Sheet1', csv: 'Name,Age,Email\nJohn Doe,30,john@example.com\nJane Smith,25,jane@example.com\nBob Johnson,40,bob@example.com' }, { name: 'Sheet2', csv: 'Product,Price,Quantity\nWidget A,10.99,100\nWidget B,15.99,50\nWidget C,5.99,200' } ] }); this.addMockSpreadsheet({ threadId: 'sample2', title: 'Sample Spreadsheet 2', sheets: [ { name: 'Data', csv: 'Date,Revenue,Expenses,Profit\n2023-01-01,5000,3000,2000\n2023-02-01,5500,3200,2300\n2023-03-01,6000,3500,2500' } ] }); // Add a large mock spreadsheet const largeSheet = this.generateLargeSheet(100, 10); this.addMockSpreadsheet({ threadId: 'large', title: 'Large Sample Spreadsheet', sheets: [ { name: 'LargeSheet', csv: largeSheet } ] }); } /** * Add a mock spreadsheet to the client * * @param spreadsheet Mock spreadsheet data */ addMockSpreadsheet(spreadsheet) { this.mockData.set(spreadsheet.threadId, spreadsheet); logger_1.logger.debug(`Added mock spreadsheet: ${spreadsheet.threadId}`, { title: spreadsheet.title }); } /** * Get a thread by ID * * @param threadId ID of the thread to retrieve * @returns Promise resolving to thread information * @throws Error if the thread is not found */ async getThread(threadId) { logger_1.logger.info(`Getting mock thread: ${threadId}`); const spreadsheet = this.mockData.get(threadId); if (!spreadsheet) { logger_1.logger.error(`Mock thread not found: ${threadId}`); throw new Error(`Thread not found: ${threadId}`); } // Create a mock thread response return { thread: { id: threadId, title: spreadsheet.title, type: 'spreadsheet' }, html: this.generateMockHtml(spreadsheet) }; } /** * Export a thread to XLSX format and save it locally * * @param threadId ID of the thread to export * @param outputPath Local file path where the XLSX file should be saved * @returns Promise resolving to path to the saved XLSX file * @throws Error if the thread is not found */ async exportThreadToXLSX(threadId, outputPath) { logger_1.logger.info(`Exporting mock thread ${threadId} to XLSX at ${outputPath}`); const spreadsheet = this.mockData.get(threadId); if (!spreadsheet) { logger_1.logger.error(`Mock thread not found: ${threadId}`); throw new Error(`Thread not found: ${threadId}`); } // In a real implementation, we would convert the CSV to XLSX here // For the mock, we'll just write a placeholder file await fs.mkdirp(path.dirname(path.resolve(outputPath))); await fs.writeFile(outputPath, 'Mock XLSX content'); logger_1.logger.info(`Successfully exported mock XLSX to ${outputPath}`); return outputPath; } /** * Export a thread to CSV format using HTML parsing as fallback method * * @param threadId ID of the thread to export * @param sheetName Name of the sheet to extract (optional) * @returns Promise resolving to CSV data as string * @throws Error if the thread is not found or does not contain a spreadsheet */ async exportThreadToCSVFallback(threadId, sheetName) { logger_1.logger.info(`Using fallback method to export mock thread ${threadId} to CSV, sheet: ${sheetName || 'default'}`); const spreadsheet = this.mockData.get(threadId); if (!spreadsheet) { logger_1.logger.error(`Mock thread not found: ${threadId}`); throw new Error(`Thread not found: ${threadId}`); } // Find the requested sheet or use the first one let sheet; if (sheetName) { sheet = spreadsheet.sheets.find(s => s.name === sheetName); if (!sheet) { logger_1.logger.error(`Sheet not found: ${sheetName}`); throw new Error(`Sheet '${sheetName}' not found in thread ${threadId}`); } } else { sheet = spreadsheet.sheets[0]; if (!sheet) { logger_1.logger.error(`No sheets found in thread: ${threadId}`); throw new Error(`No sheets found in thread ${threadId}`); } } return sheet.csv; } /** * Check if a thread is a spreadsheet * * @param threadId ID of the thread to check * @returns Promise resolving to true if the thread is a spreadsheet, false otherwise */ async isSpreadsheet(threadId) { logger_1.logger.info(`Checking if mock thread ${threadId} is a spreadsheet`); return this.mockData.has(threadId); } /** * Generate mock HTML for a spreadsheet * * @param spreadsheet Mock spreadsheet data * @returns HTML string */ generateMockHtml(spreadsheet) { let html = `<html><body><h1>${spreadsheet.title}</h1>`; for (const sheet of spreadsheet.sheets) { html += `<h2>${sheet.name}</h2>`; html += '<table>'; const rows = sheet.csv.split('\n'); for (const row of rows) { html += '<tr>'; const cells = row.split(','); for (const cell of cells) { html += `<td>${cell}</td>`; } html += '</tr>'; } html += '</table>'; } html += '</body></html>'; return html; } /** * Generate a large CSV sheet for testing * * @param rows Number of rows * @param cols Number of columns * @returns CSV string */ generateLargeSheet(rows, cols) { let csv = ''; // Generate header row for (let c = 0; c < cols; c++) { csv += `Column${c + 1}`; if (c < cols - 1) { csv += ','; } } csv += '\n'; // Generate data rows for (let r = 0; r < rows; r++) { for (let c = 0; c < cols; c++) { csv += `Value${r + 1}-${c + 1}`; if (c < cols - 1) { csv += ','; } } if (r < rows - 1) { csv += '\n'; } } return csv; } } exports.MockQuipClient = MockQuipClient; //# sourceMappingURL=mockClient.js.map