Skip to main content
Glama
open-composition-editor-v1.1.0.js15.2 kB
#!/usr/bin/env node /** * Composition Editor Opener Tool v1.1.0 - FAIL-FAST RELIABILITY * Navigate to saved composition with strict validation and comprehensive error reporting * @version 1.1.0 (January 20, 2025) * @status ENHANCED - Fail-fast validation with comprehensive error reporting * @reference JIT workflow step 7 of 7 * @enhancement Strict validation, no fallbacks, detailed troubleshooting */ export class CompositionEditorOpenerV110 { constructor() { this.processingStartTime = null; this.navigationLog = []; this.validationErrors = []; this.browserTimeout = 30000; // 30 seconds this.composerBaseUrl = 'https://composer.euconquisto.com/'; } /** * Main navigation entry point with FAIL-FAST validation * @param {Object} input - Contains compositionUid from save operation * @returns {Object} Navigation result OR detailed error information */ async openCompositionEditor(input) { this.processingStartTime = Date.now(); this.navigationLog = []; this.validationErrors = []; try { console.error('[OPEN_COMPOSITION_EDITOR_V110] Starting fail-fast navigation'); // FAIL-FAST VALIDATION PHASE const validationResult = this.validateCompositionUidComprehensively(input); if (!validationResult.valid) { throw new Error(`Composition Editor navigation validation failed:\n\n${validationResult.errors.join('\n\n')}\n\nReceived input: ${JSON.stringify(input, null, 2)}`); } const { compositionUid } = validationResult; console.error(`[OPEN_COMPOSITION_EDITOR_V110] Validation passed - Opening composition: ${compositionUid}`); // BROWSER LAUNCH PHASE const browserResult = await this.launchBrowserStrict(); if (!browserResult.success) { throw new Error(`Browser launch failed: ${browserResult.error}`); } const { browser, page } = browserResult; try { // NAVIGATION PHASE const navigationResult = await this.navigateToCompositionStrict(page, compositionUid); if (!navigationResult.success) { throw new Error(`Navigation failed: ${navigationResult.error}`); } // VERIFICATION PHASE const verificationResult = await this.verifyCompositionLoadedStrict(page, compositionUid); if (!verificationResult.success) { throw new Error(`Composition verification failed: ${verificationResult.error}`); } const processingTime = Date.now() - this.processingStartTime; console.error(`[OPEN_COMPOSITION_EDITOR_V110] Success - Composition opened in ${processingTime}ms`); return { success: true, data: { compositionUid: compositionUid, editorUrl: navigationResult.finalUrl, browserStatus: 'opened', verificationStatus: verificationResult.status, navigationSummary: { totalSteps: this.navigationLog.length, processingTime: processingTime, browserPersistence: true, editingReady: true }, userInstructions: { status: "Composition editor is now open and ready for editing", browserWindow: "Keep the browser window open to continue editing", note: "Browser will remain open until manually closed" } }, metadata: { version: "1.1.0", timestamp: new Date().toISOString(), processingTime: processingTime, failFastValidation: "passed", navigationSteps: this.navigationLog.length } }; } catch (error) { // Close browser on error try { await browser.close(); } catch (closeError) { console.error('[OPEN_COMPOSITION_EDITOR_V110] Browser close error:', closeError.message); } throw error; } } catch (error) { console.error('[OPEN_COMPOSITION_EDITOR_V110] FAIL-FAST ERROR:', error.message); return { success: false, error: { code: 'COMPOSITION_EDITOR_NAVIGATION_FAILED', message: error.message, timestamp: new Date().toISOString(), processingTime: Date.now() - this.processingStartTime, failFast: true, developmentMode: true, troubleshooting: { requiredInputStructure: { compositionUid: "string - unique composition identifier from save operation" }, navigationPhases: [ "1. Input validation and composition UID extraction", "2. Browser launch with Playwright", "3. Navigation to Composer base URL", "4. Composition-specific URL navigation", "5. Composer interface verification", "6. Composition load verification" ], commonIssues: [ "Missing or invalid composition UID", "Playwright browser not installed", "Network connectivity issues", "Composer website accessibility problems", "Composition not found or access denied", "Browser automation restrictions" ], debugSteps: [ "1. Check if compositionUid exists and is valid", "2. Verify Playwright installation: 'npx playwright install'", "3. Test network connectivity to composer.euconquisto.com", "4. Verify composition was saved successfully", "5. Check browser automation permissions", "6. Test manual access to composition URL" ], playwrightRequirements: { installation: "Run 'npx playwright install chromium' if browser launch fails", permissions: "Ensure browser automation is allowed", network: "Verify access to https://composer.euconquisto.com/" } } } }; } } /** * COMPREHENSIVE FAIL-FAST VALIDATION for composition UID */ validateCompositionUidComprehensively(input) { const errors = []; // Basic input validation if (!input || typeof input !== 'object') { errors.push("❌ INPUT STRUCTURE ERROR:\nInput must be an object containing compositionUid.\nThis should come from the save_composition_direct_api tool output.\nRequired format: { compositionUid: 'string' }"); return { valid: false, errors }; } // Extract composition UID from various possible structures let compositionUid = null; // Direct compositionUid property if (input.compositionUid) { compositionUid = input.compositionUid; } // From save operation response structure else if (input.data && input.data.compositionUid) { compositionUid = input.data.compositionUid; } // From nested save response else if (input.data && input.data.uploadDetails && input.data.uploadDetails.compositionUid) { compositionUid = input.data.uploadDetails.compositionUid; } // From alternative response structure else if (input.uploadDetails && input.uploadDetails.compositionUid) { compositionUid = input.uploadDetails.compositionUid; } if (!compositionUid) { errors.push("❌ MISSING COMPOSITION UID ERROR:\ncompositionUid is required for navigation.\nThis should be provided by the save_composition_direct_api tool.\nCheck if the save operation completed successfully.\nExpected structure: { compositionUid: 'string' }"); return { valid: false, errors }; } // Validate composition UID format if (typeof compositionUid !== 'string') { errors.push(`❌ COMPOSITION UID TYPE ERROR:\ncompositionUid must be a string, received: ${typeof compositionUid}\nValue: ${JSON.stringify(compositionUid)}`); return { valid: false, errors }; } if (compositionUid.trim().length === 0) { errors.push("❌ EMPTY COMPOSITION UID ERROR:\ncompositionUid cannot be empty.\nEnsure the save operation returned a valid composition identifier."); return { valid: false, errors }; } // Basic UID format validation (adjust based on actual UID format) if (compositionUid.length < 10) { errors.push(`❌ INVALID COMPOSITION UID FORMAT ERROR:\ncompositionUid appears too short: "${compositionUid}"\nExpected: Valid composition identifier from save operation\nLength: ${compositionUid.length} characters (minimum: 10)`); return { valid: false, errors }; } console.error(`[OPEN_COMPOSITION_EDITOR_V110] Composition UID validation passed: ${compositionUid}`); return { valid: true, compositionUid: compositionUid.trim(), errors: [] }; } /** * STRICT browser launch with comprehensive error handling */ async launchBrowserStrict() { try { console.error('[OPEN_COMPOSITION_EDITOR_V110] Launching browser with Playwright'); // Import Playwright const { chromium } = await import('playwright'); // Launch browser with optimal settings const browser = await chromium.launch({ headless: false, // Keep visible for user interaction args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-web-security', '--disable-blink-features=AutomationControlled' ], timeout: this.browserTimeout }); // Create new page const page = await browser.newPage(); // Set user agent and viewport await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'); await page.setViewportSize({ width: 1366, height: 768 }); console.error('[OPEN_COMPOSITION_EDITOR_V110] Browser launched successfully'); return { success: true, browser, page }; } catch (error) { console.error('[OPEN_COMPOSITION_EDITOR_V110] Browser launch error:', error.message); return { success: false, error: `Browser launch failed: ${error.message}. Ensure Playwright is installed: 'npx playwright install chromium'` }; } } /** * STRICT navigation to composition with comprehensive verification */ async navigateToCompositionStrict(page, compositionUid) { try { console.error(`[OPEN_COMPOSITION_EDITOR_V110] Navigating to composition: ${compositionUid}`); // Step 1: Navigate to base URL first console.error('[OPEN_COMPOSITION_EDITOR_V110] Step 1: Navigating to Composer base URL'); await page.goto(this.composerBaseUrl, { waitUntil: 'networkidle', timeout: this.browserTimeout }); // Wait for initial load await page.waitForTimeout(2000); // Step 2: Navigate to specific composition const compositionUrl = `${this.composerBaseUrl}#/composer/${compositionUid}`; console.error(`[OPEN_COMPOSITION_EDITOR_V110] Step 2: Navigating to composition URL: ${compositionUrl}`); await page.goto(compositionUrl, { waitUntil: 'networkidle', timeout: this.browserTimeout }); // Step 3: Wait for Composer interface console.error('[OPEN_COMPOSITION_EDITOR_V110] Step 3: Waiting for Composer interface'); await page.waitForFunction(() => { const composerSelectors = [ '[data-testid="composer-app"]', '.composer-editor', '#composer-root', '.rdp-composer', '[data-composer]', '.composer-container', '.composer-interface' ]; return composerSelectors.some(selector => document.querySelector(selector) !== null ); }, { timeout: 15000 }); // Additional wait for composition to load await page.waitForTimeout(3000); const finalUrl = page.url(); console.error(`[OPEN_COMPOSITION_EDITOR_V110] Navigation successful - Final URL: ${finalUrl}`); return { success: true, finalUrl: finalUrl }; } catch (error) { console.error('[OPEN_COMPOSITION_EDITOR_V110] Navigation error:', error.message); return { success: false, error: `Navigation failed: ${error.message}. Check network connectivity and Composer website accessibility.` }; } } /** * STRICT composition load verification */ async verifyCompositionLoadedStrict(page, compositionUid) { try { console.error(`[OPEN_COMPOSITION_EDITOR_V110] Verifying composition loaded: ${compositionUid}`); // Check URL contains composition UID const currentUrl = page.url(); if (!currentUrl.includes(compositionUid)) { throw new Error(`Composition UID not found in current URL: ${currentUrl}`); } // Check for error messages const errorElements = await page.$$('.error, .alert-danger, [data-error], .composition-error'); if (errorElements.length > 0) { const errorText = await Promise.all( errorElements.map(el => el.textContent().catch(() => 'Unknown error')) ); throw new Error(`Composition load errors detected: ${errorText.join(', ')}`); } // Check for loading indicators completion await page.waitForFunction(() => { const loadingSelectors = [ '.loading', '.spinner', '[data-loading]', '.composition-loading' ]; return !loadingSelectors.some(selector => document.querySelector(selector) !== null ); }, { timeout: 10000 }).catch(() => { console.error('[OPEN_COMPOSITION_EDITOR_V110] Loading indicators still present - continuing anyway'); }); console.error('[OPEN_COMPOSITION_EDITOR_V110] Composition verification successful'); return { success: true, status: 'loaded and ready for editing' }; } catch (error) { console.error('[OPEN_COMPOSITION_EDITOR_V110] Verification error:', error.message); return { success: false, error: `Composition verification failed: ${error.message}. Composition may not exist or access may be denied.` }; } } /** * Log navigation step */ logNavigation(step, description, success, details = null) { this.navigationLog.push({ step, description, success, details, timestamp: new Date().toISOString() }); } } /** * Create and export the tool instance for JIT server integration */ export function createCompositionEditorOpenerV110() { const opener = new CompositionEditorOpenerV110(); return { name: 'open_composition_editor_v110', description: 'STEP 7 v1.1.0: Navigate to saved composition editor with fail-fast validation. Opens browser to composition with comprehensive error reporting for development.', inputSchema: { type: 'object', properties: { compositionUid: { type: 'string', description: 'Composition UID from save_composition_direct_api tool output' } }, required: ['compositionUid'] }, handler: async (input) => { return await opener.openCompositionEditor(input); } }; }

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