#!/usr/bin/env node /** * Phase 3 Patch Application Script * Applies final modifications to server/index.mjs */ import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const indexFile = path.join(__dirname, 'server', 'index.mjs'); const backupFile = `${indexFile}.backup.${Date.now()}`; console.log('\n🚀 Phase 3 Patch Application'); console.log('================================\n'); try { // Step 1: Create backup console.log('📦 Creating backup...'); fs.copyFileSync(indexFile, backupFile); console.log(`✅ Backup created: ${backupFile}\n`); // Step 2: Read the file console.log('📖 Reading index.mjs...'); let content = fs.readFileSync(indexFile, 'utf-8'); console.log('✅ File read successfully\n'); // Step 3: Add performance endpoint setup console.log('🔧 Adding performance endpoint setup...'); const performanceEndpointSetup = `// Phase 3: Setup performance monitoring endpoint setupPerformanceEndpoint(app, performanceMonitor, metadataCache, meilisearchCircuitBreaker); `; // Insert before "// Créer le répertoire de la voûte" content = content.replace( '// Créer le répertoire de la voûte s\'il n\'existe pas', performanceEndpointSetup + '// Créer le répertoire de la voûte s\'il n\'existe pas' ); console.log('✅ Performance endpoint setup added\n'); // Step 4: Update app.listen() for deferred indexing console.log('🔧 Updating app.listen() for deferred indexing...'); const oldListen = `app.listen(PORT, '0.0.0.0', () => { console.log(\`ObsiViewer server running on http://0.0.0.0:\${PORT}\`); console.log(\`Vault directory: \${vaultDir}\`); });`; const newListen = `// Phase 3: Deferred Meilisearch indexing (non-blocking) let indexingState = { inProgress: false, completed: false }; const scheduleIndexing = async () => { if (indexingState.inProgress) return; indexingState.inProgress = true; setImmediate(async () => { try { console.time('[Meilisearch] Background indexing'); await fullReindex(vaultDir); console.timeEnd('[Meilisearch] Background indexing'); indexingState.completed = true; console.log('[Meilisearch] ✅ Background indexing completed'); } catch (error) { console.error('[Meilisearch] ❌ Background indexing failed:', error.message); indexingState.completed = false; // Retry after 5 minutes setTimeout(() => { indexingState.inProgress = false; scheduleIndexing(); }, 5 * 60 * 1000); } }); }; const server = app.listen(PORT, '0.0.0.0', () => { console.log(\`🚀 ObsiViewer server running on http://0.0.0.0:\${PORT}\`); console.log(\`📁 Vault directory: \${vaultDir}\`); console.log(\`📊 Performance monitoring: http://0.0.0.0:\${PORT}/__perf\`); // Schedule background indexing (non-blocking) scheduleIndexing(); console.log('✅ Server ready - Meilisearch indexing in background'); }); // Graceful shutdown process.on('SIGINT', () => { console.log('\\n🛑 Shutting down server...'); server.close(() => { console.log('✅ Server shutdown complete'); process.exit(0); }); });`; content = content.replace(oldListen, newListen); console.log('✅ app.listen() updated with deferred indexing\n'); // Step 5: Write the modified content console.log('💾 Writing modified index.mjs...'); fs.writeFileSync(indexFile, content, 'utf-8'); console.log('✅ File written successfully\n'); // Step 6: Verify changes console.log('🔍 Verifying changes...'); const verifyContent = fs.readFileSync(indexFile, 'utf-8'); const checks = [ { name: 'Performance endpoint setup', pattern: 'setupPerformanceEndpoint' }, { name: 'Deferred indexing', pattern: 'scheduleIndexing' }, { name: 'Graceful shutdown', pattern: "process.on('SIGINT'" }, { name: 'Performance monitoring URL', pattern: '__perf' } ]; let allPassed = true; for (const check of checks) { if (verifyContent.includes(check.pattern)) { console.log(` ✅ ${check.name}`); } else { console.log(` ❌ ${check.name}`); allPassed = false; } } console.log(''); if (allPassed) { console.log('✅ All verification checks passed!\n'); } else { console.log('⚠️ Some verification checks failed\n'); } console.log('================================'); console.log('✅ Phase 3 patch applied successfully!\n'); console.log('Next steps:'); console.log('1. Test the server: npm run start'); console.log('2. Check performance: curl http://localhost:3000/__perf'); console.log('3. Monitor cache hits in the logs'); console.log('4. Verify Meilisearch indexing in background\n'); } catch (error) { console.error('❌ Error applying patch:', error.message); console.error('\nRolling back...'); if (fs.existsSync(backupFile)) { fs.copyFileSync(backupFile, indexFile); console.log('✅ Rollback complete'); } process.exit(1); }