Skip to main content
Glama
composer-interface-mapper.js10.1 kB
/** * @document Composer Interface Discovery and Mapping * @version 1.0.0 * @status active * @author Claude Code * @created 2025-06-30 * @description Automated discovery of Composer interface URLs and access patterns */ import { chromium } from 'playwright'; import fs from 'fs/promises'; class ComposerInterfaceMapper { constructor() { this.browser = null; this.page = null; this.baseUrl = 'https://composer.euconquisto.com'; this.jwtToken = null; } async initialize() { this.browser = await chromium.launch({ headless: false, slowMo: 500 }); const context = await this.browser.newContext({ viewport: { width: 1920, height: 1080 } }); this.page = await context.newPage(); // Load JWT token try { this.jwtToken = await fs.readFile('archive/authentication/correct-jwt-new.txt', 'utf-8'); this.jwtToken = this.jwtToken.trim(); console.log('✅ JWT token loaded for authenticated discovery'); } catch (error) { console.log('⚠️ No JWT token found, using unauthenticated discovery'); } } async authenticateAndExplore() { console.log('🔐 Starting authenticated exploration...'); const result = { accessPattern: 'direct', authenticationRequired: true, workingPaths: [], failedPaths: [] }; // Step 1: Authenticate if JWT available if (this.jwtToken) { console.log('🎫 Authenticating with JWT token...'); const loginUrl = `${this.baseUrl}/auth/login?token=${this.jwtToken}`; result.loginUrl = loginUrl; await this.page.goto(loginUrl, { waitUntil: 'networkidle' }); await this.page.waitForTimeout(3000); // Take screenshot of authenticated state await this.page.screenshot({ path: 'logs/screenshots/discovery/01-authenticated-state.png', fullPage: true }); } else { // Try direct access await this.page.goto(this.baseUrl, { waitUntil: 'networkidle' }); } // Step 2: Discover dashboard/main interface console.log('🏠 Discovering main interface...'); const currentUrl = this.page.url(); console.log(`📍 Current URL after auth: ${currentUrl}`); if (!currentUrl.includes('404') && !currentUrl.includes('not exist')) { result.dashboardUrl = currentUrl; result.workingPaths.push(currentUrl.replace(this.baseUrl, '')); } // Step 3: Test common composer paths const pathsToTest = [ '/', '/dashboard', '/home', '/workspace', '/composer', '/editor', '/create', '/new', '/compositions', '/app', '/portal', '/studio' ]; for (const path of pathsToTest) { try { console.log(`🧭 Testing path: ${path}`); await this.page.goto(`${this.baseUrl}${path}`, { waitUntil: 'networkidle', timeout: 10000 }); const content = await this.page.textContent('body'); const isValid = content && !content.includes('404') && !content.includes('not exist') && !content.includes('WebContentNotFound'); if (isValid) { result.workingPaths.push(path); console.log(` ✅ Working: ${path}`); // Take screenshot of working interfaces await this.page.screenshot({ path: `logs/screenshots/discovery/working-${path.replace('/', 'root')}.png`, fullPage: true }); // Check for composer-specific indicators const indicators = await this.page.evaluate(() => { const bodyText = document.body.innerText.toLowerCase(); return { hasComposer: bodyText.includes('composer') || bodyText.includes('composition'), hasEditor: bodyText.includes('editor') || bodyText.includes('edit'), hasCreate: bodyText.includes('create') || bodyText.includes('new'), hasWidgets: document.querySelectorAll('[class*="widget"], [class*="element"]').length > 0, hasNavigation: document.querySelectorAll('nav, [class*="nav"], [class*="menu"]').length > 0, textSnippet: bodyText.substring(0, 200) }; }); console.log(` 📊 Indicators:`, indicators); // Identify specific interface types if (indicators.hasEditor || indicators.hasWidgets) { result.editorUrl = `${this.baseUrl}${path}`; } if (indicators.hasCreate) { result.createUrl = `${this.baseUrl}${path}`; } } else { result.failedPaths.push(path); console.log(` ❌ Failed: ${path}`); } } catch (error) { result.failedPaths.push(path); console.log(` ❌ Error on ${path}: ${error.message}`); } } // Step 4: Look for navigation links and buttons console.log('🔗 Searching for navigation elements...'); if (result.dashboardUrl) { await this.page.goto(result.dashboardUrl, { waitUntil: 'networkidle' }); const navigationLinks = await this.page.evaluate(() => { const links = Array.from(document.querySelectorAll('a, button')); return links .map(el => ({ text: el.textContent?.trim() || '', href: el.getAttribute('href') || '', onclick: el.getAttribute('onclick') || '' })) .filter(link => link.text.toLowerCase().includes('composer') || link.text.toLowerCase().includes('editor') || link.text.toLowerCase().includes('create') || link.text.toLowerCase().includes('new') || link.href.includes('composer') || link.href.includes('editor') ); }); console.log('🔗 Found navigation elements:', navigationLinks); } return result; } async testCompositionLoading(interfaceUrl) { try { console.log('🧪 Testing composition loading at:', interfaceUrl); await this.page.goto(interfaceUrl, { waitUntil: 'networkidle' }); // Inject our test composition first const injectionResult = await this.page.evaluate(() => { // Clear existing data localStorage.removeItem('rdp-composer-data'); // Inject test data const testComposition = { composition: { id: 'test-fotossintese', title: 'Fotossíntese Test', elements: [ { id: '1', type: 'head-1', content_title: 'Test Header' }, { id: '2', type: 'text-1', content: 'Test content about fotossíntese' } ] } }; localStorage.setItem('rdp-composer-data', JSON.stringify(testComposition)); return !!localStorage.getItem('rdp-composer-data'); }); console.log('💉 Composition injection result:', injectionResult); // Wait for potential auto-loading await this.page.waitForTimeout(5000); // Check if composition appears const compositionVisible = await this.page.evaluate(() => { const bodyText = document.body.innerText.toLowerCase(); return { hasData: !!localStorage.getItem('rdp-composer-data'), hasPhotosynthesis: bodyText.includes('fotossíntese'), hasTest: bodyText.includes('test'), textSnippet: bodyText.substring(0, 300) }; }); await this.page.screenshot({ path: 'logs/screenshots/discovery/composition-test.png', fullPage: true }); console.log('🧪 Composition visibility test:', compositionVisible); return compositionVisible.hasPhotosynthesis || compositionVisible.hasTest; } catch (error) { console.log('❌ Composition loading test failed:', error.message); return false; } } async generateReport() { const result = await this.authenticateAndExplore(); // Test composition loading on working interfaces if (result.editorUrl) { const compositionWorks = await this.testCompositionLoading(result.editorUrl); console.log(`🎨 Composition loading test: ${compositionWorks ? 'SUCCESS' : 'FAILED'}`); result.compositionLoadingWorks = compositionWorks; } // Determine access pattern if (result.editorUrl || result.createUrl) { result.accessPattern = 'direct'; } else if (result.dashboardUrl && result.workingPaths.length > 0) { result.accessPattern = 'dashboard'; } else { result.accessPattern = 'redirect'; } console.log('\n📊 Discovery Report:'); console.log('=================='); console.log(`🔐 Authentication: ${this.jwtToken ? 'JWT Used' : 'Unauthenticated'}`); console.log(`🏠 Dashboard URL: ${result.dashboardUrl || 'Not found'}`); console.log(`🎨 Editor URL: ${result.editorUrl || 'Not found'}`); console.log(`➕ Create URL: ${result.createUrl || 'Not found'}`); console.log(`✅ Working paths: ${result.workingPaths.length}`); console.log(`❌ Failed paths: ${result.failedPaths.length}`); console.log(`🔄 Access pattern: ${result.accessPattern}`); console.log(`🧪 Composition loading: ${result.compositionLoadingWorks ? 'WORKS' : 'NEEDS INVESTIGATION'}`); return result; } async cleanup() { if (this.browser) { console.log('\n⏸️ Keeping browser open for 10 seconds...'); await new Promise(resolve => setTimeout(resolve, 10000)); await this.browser.close(); } } } // Run the discovery const mapper = new ComposerInterfaceMapper(); mapper.initialize() .then(() => mapper.generateReport()) .then(result => { console.log('\n✅ Interface discovery completed!'); console.log('📸 Screenshots saved in logs/screenshots/discovery/'); return mapper.cleanup(); }) .catch(error => { console.error('❌ Discovery failed:', error); return mapper.cleanup(); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rkm097git/euconquisto-composer-mcp-poc'

If you have feedback or need assistance with the MCP directory API, please join our Discord server