UNPKG

revit-cli

Version:

A scalable CLI tool for Revit communication and data manipulation

472 lines 17.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.RevitConnector = void 0; const axios_1 = __importDefault(require("axios")); const logger_1 = require("../utils/logger"); /** * Handles communication with Revit API */ class RevitConnector { constructor() { this.isConnected = false; this.logger = new logger_1.Logger(); // Initialize axios client with default config this.client = axios_1.default.create({ timeout: 30000, headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' } }); this.setupInterceptors(); } /** * Setup request/response interceptors for logging and error handling */ setupInterceptors() { // Request interceptor this.client.interceptors.request.use((config) => { this.logger.debug('=== HTTP REQUEST START ==='); this.logger.debug(`Making request to: ${config.method?.toUpperCase()} ${config.url}`); this.logger.debug('Request config:', { method: config.method, url: config.url, baseURL: config.baseURL, timeout: config.timeout, headers: config.headers, data: config.data }); this.logger.debug('Full request URL:', `${config.baseURL || ''}${config.url}`); return config; }, (error) => { this.logger.error('=== HTTP REQUEST ERROR ==='); this.logger.error('Request setup error:', { message: error.message, code: error.code, config: error.config }); return Promise.reject(error); }); // Response interceptor this.client.interceptors.response.use((response) => { this.logger.debug('=== HTTP RESPONSE SUCCESS ==='); this.logger.debug(`Response received: ${response.status} ${response.statusText}`); this.logger.debug('Response details:', { status: response.status, statusText: response.statusText, headers: response.headers, dataType: typeof response.data, dataLength: response.data ? JSON.stringify(response.data).length : 0 }); if (response.data && typeof response.data === 'object') { this.logger.debug('Response data sample:', JSON.stringify(response.data).substring(0, 500)); } return response; }, (error) => { this.logger.error('=== HTTP RESPONSE ERROR ==='); this.logger.error('Response error details:', { message: error.message, code: error.code, status: error.response?.status, statusText: error.response?.statusText, responseData: error.response?.data, requestURL: error.config?.url, requestMethod: error.config?.method }); if (error.response) { this.logger.error('Error response body:', error.response.data); } return Promise.reject(error); }); } /** * Initialize the connector with configuration */ async initialize(configManager) { const config = configManager.getConfig(); // Update client configuration if (config.revit?.apiUrl) { this.client.defaults.baseURL = config.revit.apiUrl; } if (config.revit?.timeout) { this.client.defaults.timeout = config.revit.timeout; } this.logger.debug('Revit Connector initialized'); } /** * Test connection to Revit API */ async testConnection() { try { this.logger.debug('=== CONNECTION TEST START ==='); this.logger.debug('Testing connection to:', this.client.defaults.baseURL); const response = await this.client.get('/health'); this.logger.debug('Health check response:', { status: response.status, statusText: response.statusText, data: response.data }); this.isConnected = response.status === 200; if (this.isConnected) { this.logger.info('Successfully connected to Revit API'); } else { this.logger.warn('Revit API health check returned non-200 status'); } this.logger.debug('Connection test result:', this.isConnected); this.logger.debug('=== CONNECTION TEST END ==='); return this.isConnected; } catch (error) { this.logger.error('=== CONNECTION TEST ERROR ==='); this.isConnected = false; this.logger.error('Failed to connect to Revit API:', { message: error instanceof Error ? error.message : String(error), code: error?.code, status: error?.response?.status }); return false; } } /** * Get Revit project information */ async getProjectInfo() { try { const response = await this.client.get('/project/info'); return { success: true, data: response.data, timestamp: new Date().toISOString() }; } catch (error) { return this.handleError('Failed to get project info', error); } } /** * Extract elements from Revit based on options */ async extractElements(options) { try { this.logger.debug('=== EXTRACT ELEMENTS START ==='); this.logger.debug('Extract options:', options); this.logger.debug('Client base URL:', this.client.defaults.baseURL); this.logger.debug('Client timeout:', this.client.defaults.timeout); this.logger.debug('Making POST request to /elements/extract'); const response = await this.client.post('/elements/extract', options); this.logger.debug('Extract response received:', { status: response.status, dataType: typeof response.data, dataLength: response.data ? JSON.stringify(response.data).length : 0 }); this.logger.debug('=== EXTRACT ELEMENTS END ==='); return { success: true, data: response.data, timestamp: new Date().toISOString() }; } catch (error) { this.logger.error('=== EXTRACT ELEMENTS ERROR ==='); return this.handleError('Failed to extract elements', error); } } /** * Get elements by category */ async getElementsByCategory(category) { try { const response = await this.client.get(`/elements/category/${encodeURIComponent(category)}`); return { success: true, data: response.data, timestamp: new Date().toISOString() }; } catch (error) { return this.handleError(`Failed to get elements for category: ${category}`, error); } } /** * Get element by ID */ async getElementById(elementId) { try { const response = await this.client.get(`/elements/${encodeURIComponent(elementId)}`); return { success: true, data: response.data, timestamp: new Date().toISOString() }; } catch (error) { return this.handleError(`Failed to get element: ${elementId}`, error); } } /** * Get all available categories */ async getCategories() { try { this.logger.debug('=== GET CATEGORIES START ==='); this.logger.debug('Fetching all available categories from Revit API'); this.logger.debug('Client base URL:', this.client.defaults.baseURL); this.logger.debug('Client timeout:', this.client.defaults.timeout); this.logger.debug('Current headers:', this.client.defaults.headers); const startTime = Date.now(); this.logger.debug('Making GET request to /categories endpoint'); const response = await this.client.get('/categories'); const duration = Date.now() - startTime; this.logger.debug(`Categories request completed in ${duration}ms`); this.logger.debug('Categories response received:', { status: response.status, statusText: response.statusText, dataType: typeof response.data, isArray: Array.isArray(response.data), dataLength: response.data ? JSON.stringify(response.data).length : 0, headers: response.headers }); // Validate response data structure if (!response.data) { this.logger.warn('Response data is null or undefined'); return { success: true, data: [], timestamp: new Date().toISOString() }; } let categories = []; // Handle different response structures if (Array.isArray(response.data)) { // Direct array response categories = response.data; this.logger.debug('Response is direct array format'); } else if (typeof response.data === 'object') { // Check for nested structure with 'data' property if ('data' in response.data && Array.isArray(response.data.data)) { categories = response.data.data; this.logger.debug('Found categories in response.data.data structure'); } // Check for nested structure with 'categories' property else if ('categories' in response.data && Array.isArray(response.data.categories)) { categories = response.data.categories; this.logger.debug('Found categories in response.data.categories structure'); } // If response.data is an object but not nested, treat it as a single category else if (response.data.id && response.data.name) { categories = [response.data]; this.logger.debug('Response is single category object'); } else { this.logger.warn('Unknown response structure:', response.data); } } if (categories.length > 0) { this.logger.debug(`Successfully retrieved ${categories.length} categories`); this.logger.debug('Sample category:', categories[0]); if (categories.length <= 5) { this.logger.debug('All categories:', categories); } else { this.logger.debug('First 3 categories:', categories.slice(0, 3)); } } else { this.logger.warn('No categories found in response'); } this.logger.debug('=== GET CATEGORIES SUCCESS ==='); return { success: true, data: categories, timestamp: new Date().toISOString() }; } catch (error) { this.logger.error('=== GET CATEGORIES ERROR ==='); this.logger.error('Failed to get categories:', { message: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, url: `${this.client.defaults.baseURL}/categories` }); // Check if it's a connection error if (error instanceof Error && (error.message.includes('ECONNREFUSED') || error.message.includes('Network Error'))) { this.logger.error('Connection refused - is Revit API Server running?'); this.logger.error('Please ensure:'); this.logger.error('1. Revit is running'); this.logger.error('2. The Revit API Server add-in is loaded'); this.logger.error('3. The server is listening on the configured port'); } return this.handleError('Failed to get categories', error); } } /** * Get parameters for a specific category */ async getCategoryParameters(category) { try { const response = await this.client.get(`/categories/${encodeURIComponent(category)}/parameters`); return { success: true, data: response.data, timestamp: new Date().toISOString() }; } catch (error) { return this.handleError(`Failed to get parameters for category: ${category}`, error); } } /** * Execute a custom Revit API command */ async executeCommand(command, parameters) { try { const response = await this.client.post('/commands/execute', { command, parameters: parameters || {} }); return { success: true, data: response.data, timestamp: new Date().toISOString() }; } catch (error) { return this.handleError(`Failed to execute command: ${command}`, error); } } /** * Export data in specified format */ async exportData(data, format = 'json') { try { const response = await this.client.post('/export', { data, format }); return { success: true, data: response.data, timestamp: new Date().toISOString() }; } catch (error) { return this.handleError(`Failed to export data as ${format}`, error); } } /** * Import data from file */ async importData(filePath, format = 'json') { try { const response = await this.client.post('/import', { filePath, format }); return { success: true, data: response.data, timestamp: new Date().toISOString() }; } catch (error) { return this.handleError(`Failed to import data from ${filePath}`, error); } } /** * Get Revit application status */ async getStatus() { try { const response = await this.client.get('/status'); return { success: true, data: response.data, timestamp: new Date().toISOString() }; } catch (error) { return this.handleError('Failed to get Revit status', error); } } /** * Handle API errors consistently */ handleError(message, error) { const errorMessage = error.response?.data?.message || error.message || 'Unknown error'; this.logger.error(`${message}: ${errorMessage}`); return { success: false, error: errorMessage, timestamp: new Date().toISOString() }; } /** * Make a custom API request */ async request(config) { try { const response = await this.client.request(config); return { success: true, data: response.data, timestamp: new Date().toISOString() }; } catch (error) { return this.handleError('Custom API request failed', error); } } /** * Check if connector is connected */ async getConnectionStatus() { this.logger.debug('=== GET CONNECTION STATUS ==='); this.logger.debug('Testing actual connection to Revit API...'); this.logger.debug('Client config:', { baseURL: this.client.defaults.baseURL, timeout: this.client.defaults.timeout }); try { // Actually test the connection by calling the health endpoint const isConnected = await this.testConnection(); if (isConnected) { this.logger.debug('Connection status check: SUCCESS'); return { connected: true }; } else { this.logger.debug('Connection status check: FAILED - Health check returned false'); return { connected: false, error: 'Health check failed' }; } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); this.logger.debug('Connection status check: ERROR -', errorMessage); return { connected: false, error: errorMessage }; } } /** * Set custom headers for API requests */ setHeaders(headers) { Object.assign(this.client.defaults.headers, headers); } /** * Set authentication token */ setAuthToken(token) { this.client.defaults.headers['Authorization'] = `Bearer ${token}`; } /** * Clear authentication */ clearAuth() { delete this.client.defaults.headers['Authorization']; } } exports.RevitConnector = RevitConnector; //# sourceMappingURL=revit-connector.js.map