UNPKG

@truefrontier/puppeteer-laravel-mcp-server

Version:

A Model Context Protocol server for Laravel Herd browser automation using Puppeteer

247 lines (232 loc) 8.3 kB
import { exec } from 'child_process'; import { promisify } from 'util'; const execAsync = promisify(exec); export class LaravelHerdIntegration { page; siteName; constructor(page, siteName) { this.page = page; this.siteName = siteName; } async executeHerdCommand(command, args = []) { const fullCommand = this.siteName ? `${command} --site=${this.siteName} ${args.join(' ')}` : `${command} ${args.join(' ')}`; try { const { stdout, stderr } = await execAsync(fullCommand); if (stderr) { console.warn(`Herd command warning: ${stderr}`); } return stdout.trim(); } catch (error) { throw new Error(`Herd command failed: ${error}`); } } async getPhpVersion() { return await this.executeHerdCommand('herd php', ['-v']); } async runArtisanCommand(command, args = []) { return await this.executeHerdCommand('herd artisan', [command, ...args]); } async runComposerCommand(command, args = []) { return await this.executeHerdCommand('herd composer', [command, ...args]); } async secureSite() { if (!this.siteName) { throw new Error('Site name required for SSL security'); } await this.executeHerdCommand('herd secure', [this.siteName]); } async unsecureSite() { if (!this.siteName) { throw new Error('Site name required for SSL unsecurity'); } await this.executeHerdCommand('herd unsecure', [this.siteName]); } // Laravel-specific authentication helpers async loginAs(email, config = {}) { const loginScript = ` (async () => { // First, try to find CSRF token const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || document.querySelector('input[name="_token"]')?.value; // Inject authentication state if (window.Laravel && window.Laravel.csrfToken) { window.Laravel.csrfToken = csrfToken; } // Set session data via localStorage for SPA compatibility localStorage.setItem('laravel_auth_user', JSON.stringify({ email: '${email}', authenticated: true, guard: '${config.guardName || 'web'}', timestamp: new Date().toISOString() })); // Trigger authentication events if available if (window.dispatchEvent) { window.dispatchEvent(new CustomEvent('laravel:auth:login', { detail: { email: '${email}', guard: '${config.guardName || 'web'}' } })); } return true; })() `; await this.page.evaluate(loginScript); // Reload page to apply authentication state await this.page.reload({ waitUntil: 'networkidle2' }); } async actingAs(userId, config = {}) { const actingAsScript = ` (async () => { // Set acting as user data localStorage.setItem('laravel_acting_as', JSON.stringify({ userId: ${userId}, guard: '${config.guardName || 'web'}', timestamp: new Date().toISOString() })); // Trigger acting as events if (window.dispatchEvent) { window.dispatchEvent(new CustomEvent('laravel:auth:acting-as', { detail: { userId: ${userId}, guard: '${config.guardName || 'web'}' } })); } return true; })() `; await this.page.evaluate(actingAsScript); await this.page.reload({ waitUntil: 'networkidle2' }); } async logout() { const logoutScript = ` (async () => { // Clear authentication data localStorage.removeItem('laravel_auth_user'); localStorage.removeItem('laravel_acting_as'); // Clear session storage sessionStorage.clear(); // Trigger logout events if (window.dispatchEvent) { window.dispatchEvent(new CustomEvent('laravel:auth:logout')); } return true; })() `; await this.page.evaluate(logoutScript); await this.page.reload({ waitUntil: 'networkidle2' }); } // Database management helpers async seedDatabase(seeder, config = {}) { const args = ['--class=' + seeder]; if (config.database) { args.push('--database=' + config.database); } await this.runArtisanCommand('db:seed', args); } async migrateDatabase(fresh = false, config = {}) { const command = fresh ? 'migrate:fresh' : 'migrate'; const args = []; if (config.database) { args.push('--database=' + config.database); } await this.runArtisanCommand(command, args); } async rollbackDatabase(steps = 1, config = {}) { const args = [`--step=${steps}`]; if (config.database) { args.push('--database=' + config.database); } await this.runArtisanCommand('migrate:rollback', args); } // Route helpers async visitRoute(routeName, params = {}) { const routeScript = ` (async () => { // Try to use Laravel's route helper if available if (window.route && typeof window.route === 'function') { return window.route('${routeName}', ${JSON.stringify(params)}); } // Fallback: try to find route in Laravel Mix manifest or generate manually const routes = window.Laravel?.routes || {}; const route = routes['${routeName}']; if (route) { let url = route; // Simple parameter replacement Object.keys(${JSON.stringify(params)}).forEach(key => { url = url.replace('{' + key + '}', ${JSON.stringify(params)}[key]); }); return url; } throw new Error('Route not found: ${routeName}'); })() `; try { const url = await this.page.evaluate(routeScript); await this.page.goto(url, { waitUntil: 'networkidle2' }); } catch (error) { throw new Error(`Failed to visit route ${routeName}: ${error}`); } } // Cache management async clearCache() { await this.runArtisanCommand('cache:clear'); } async clearConfig() { await this.runArtisanCommand('config:clear'); } async clearRoute() { await this.runArtisanCommand('route:clear'); } async clearView() { await this.runArtisanCommand('view:clear'); } async clearAll() { await Promise.all([ this.clearCache(), this.clearConfig(), this.clearRoute(), this.clearView(), ]); } // Queue management async runQueue(queue) { const args = queue ? ['--queue=' + queue] : []; await this.runArtisanCommand('queue:work', [...args, '--stop-when-empty']); } async clearFailedJobs() { await this.runArtisanCommand('queue:flush'); } // Environment helpers async getEnvironment() { const envScript = ` (async () => { // Try to get environment from Laravel global if (window.Laravel && window.Laravel.env) { return window.Laravel.env; } // Try to get from meta tag const envMeta = document.querySelector('meta[name="env"]'); if (envMeta) { return envMeta.getAttribute('content'); } return 'unknown'; })() `; return await this.page.evaluate(envScript); } async isDebugMode() { const debugScript = ` (async () => { // Check Laravel debug mode if (window.Laravel && typeof window.Laravel.debug !== 'undefined') { return window.Laravel.debug; } // Check for debug indicators in page const debugElements = document.querySelectorAll('.sf-toolbar, #debugbar, .phpdebugbar'); return debugElements.length > 0; })() `; return await this.page.evaluate(debugScript); } } //# sourceMappingURL=herd-integration.js.map