/** * Verification script for Sovereign Stack marketplace services * Verifies that all services are properly registered in the marketplace */ import 'dotenv/config' import { getDb } from '../src/db/index.js' import { logger } from '../src/lib/logger.js' async function verifySovereignStackServices() { const db = getDb() try { logger.info('Verifying Sovereign Stack marketplace services...') // 1. Verify Phoenix publisher exists const publisherResult = await db.query( `SELECT * FROM publishers WHERE name = 'phoenix-cloud-services'` ) if (publisherResult.rows.length === 0) { throw new Error('Phoenix publisher not found. Please run migration 025 first.') } const publisher = publisherResult.rows[0] logger.info(`✓ Phoenix publisher found: ${publisher.display_name} (${publisher.id})`) logger.info(` Verified: ${publisher.verified}`) logger.info(` Website: ${publisher.website_url || 'N/A'}`) // 2. Verify all 9 services exist const expectedServices = [ 'phoenix-ledger-service', 'phoenix-identity-service', 'phoenix-wallet-registry', 'phoenix-tx-orchestrator', 'phoenix-messaging-orchestrator', 'phoenix-voice-orchestrator', 'phoenix-event-bus', 'phoenix-audit-service', 'phoenix-observability' ] const servicesResult = await db.query( `SELECT p.*, pub.display_name as publisher_name FROM products p JOIN publishers pub ON p.publisher_id = pub.id WHERE pub.name = 'phoenix-cloud-services' ORDER BY p.name` ) const foundServices = servicesResult.rows.map(row => row.slug) logger.info(`\n✓ Found ${servicesResult.rows.length} Phoenix services:`) for (const service of servicesResult.rows) { logger.info(` - ${service.name} (${service.slug})`) logger.info(` Category: ${service.category}`) logger.info(` Status: ${service.status}`) logger.info(` Featured: ${service.featured}`) } // Check for missing services const missingServices = expectedServices.filter(slug => !foundServices.includes(slug)) if (missingServices.length > 0) { logger.warn(`\n⚠ Missing services: ${missingServices.join(', ')}`) logger.warn('Please run: pnpm db:seed:sovereign-stack') } else { logger.info(`\n✓ All ${expectedServices.length} expected services found!`) } // 3. Verify categories are available const categoriesResult = await db.query( `SELECT DISTINCT category FROM products WHERE publisher_id = $1`, [publisher.id] ) const categories = categoriesResult.rows.map(row => row.category) logger.info(`\n✓ Services span ${categories.length} categories:`) categories.forEach(cat => logger.info(` - ${cat}`)) // 4. Verify product versions exist const versionsResult = await db.query( `SELECT COUNT(*) as count FROM product_versions pv JOIN products p ON pv.product_id = p.id JOIN publishers pub ON p.publisher_id = pub.id WHERE pub.name = 'phoenix-cloud-services'` ) const versionCount = parseInt(versionsResult.rows[0].count) logger.info(`\n✓ Found ${versionCount} product versions`) // 5. Verify pricing models exist const pricingResult = await db.query( `SELECT COUNT(*) as count FROM pricing_models pm JOIN products p ON pm.product_id = p.id JOIN publishers pub ON p.publisher_id = pub.id WHERE pub.name = 'phoenix-cloud-services'` ) const pricingCount = parseInt(pricingResult.rows[0].count) logger.info(`✓ Found ${pricingCount} pricing models`) // 6. Summary logger.info('\n' + '='.repeat(60)) logger.info('VERIFICATION SUMMARY') logger.info('='.repeat(60)) logger.info(`Publisher: ${publisher.display_name} (${publisher.verified ? '✓ Verified' : '✗ Not verified'})`) logger.info(`Services: ${foundServices.length}/${expectedServices.length}`) logger.info(`Categories: ${categories.length}`) logger.info(`Versions: ${versionCount}`) logger.info(`Pricing Models: ${pricingCount}`) if (missingServices.length === 0 && versionCount >= expectedServices.length && pricingCount >= expectedServices.length) { logger.info('\n✅ All Sovereign Stack services verified successfully!') return true } else { logger.warn('\n⚠ Some services may need to be seeded. Run: pnpm db:seed:sovereign-stack') return false } } catch (error) { logger.error('Verification error', { error }) throw error } finally { await db.end() } } // Run if called directly if (import.meta.url === `file://${process.argv[1]}`) { verifySovereignStackServices() .then(success => { process.exit(success ? 0 : 1) }) .catch((error) => { logger.error('Failed to verify Sovereign Stack services', { error }) process.exit(1) }) } export { verifySovereignStackServices }