UNPKG

@0xobelisk/graphql-server

Version:

Tookit for interacting with dubhe graphql server

262 lines 11.1 kB
"use strict"; // Express server manager - using Express framework and PostgreSQL subscriptions var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.EnhancedServerManager = void 0; const express_1 = __importDefault(require("express")); const http_1 = require("http"); const cors_1 = __importDefault(require("cors")); const postgraphile_1 = require("postgraphile"); const subscription_config_1 = require("../config/subscription-config"); const logger_1 = require("../utils/logger"); const welcome_page_1 = require("./welcome-page"); const postgraphile_config_1 = require("./postgraphile-config"); class EnhancedServerManager { config; app = null; httpServer = null; pgPool = null; constructor() { this.config = subscription_config_1.subscriptionConfig.getConfig(); } // Create Express application createExpressApp(serverConfig) { const { postgraphileMiddleware, allTables, welcomeConfig, postgraphileConfigOptions } = serverConfig; const app = (0, express_1.default)(); // Middleware configuration app.use((0, cors_1.default)({ origin: '*', methods: ['GET', 'POST', 'OPTIONS'], allowedHeaders: ['Content-Type', 'Authorization'] })); // Request logging middleware app.use((req, res, next) => { const startTime = Date.now(); res.on('finish', () => { (0, logger_1.logExpress)(req.method, req.path, res.statusCode, startTime, { userAgent: req.get('user-agent')?.substring(0, 50) }); }); next(); }); // Route configuration // Root path - welcome page app.get('/', (req, res) => { res.set('Content-Type', 'text/html; charset=utf-8'); res.send((0, welcome_page_1.createWelcomePage)(allTables, welcomeConfig)); }); // GraphQL Playground app.get('/playground', (req, res) => { res.set('Content-Type', 'text/html; charset=utf-8'); res.send((0, postgraphile_config_1.createPlaygroundHtml)(postgraphileConfigOptions)); }); // Redirect old GraphiQL paths app.get('/graphiql*', (req, res) => { logger_1.serverLogger.info('Redirecting old GraphiQL path', { from: req.path, to: '/playground' }); res.redirect(301, '/playground'); }); // Health check endpoint app.get('/health', (req, res) => { res.json({ status: 'healthy', subscriptions: this.getSubscriptionStatus(), timestamp: new Date().toISOString() }); }); // Subscription configuration endpoint app.get('/subscription-config', (req, res) => { res.json(subscription_config_1.subscriptionConfig.generateClientConfig()); }); // Configuration documentation endpoint app.get('/subscription-docs', (req, res) => { res.set('Content-Type', 'text/plain'); res.send(subscription_config_1.subscriptionConfig.generateDocumentation()); }); // Add connection pool status endpoint app.get('/pool-status', (req, res) => { if (this.pgPool) { const poolStatus = { totalCount: this.pgPool.totalCount, idleCount: this.pgPool.idleCount, waitingCount: this.pgPool.waitingCount, maxConnections: this.pgPool.options.max || 'Not set', minConnections: this.pgPool.options.min || 'Not set' }; res.json({ status: 'ok', connectionPool: poolStatus, strategy: 'single-pool-unified', operations: ['query', 'mutation', 'subscription'], timestamp: new Date().toISOString(), uptime: process.uptime(), memory: process.memoryUsage() }); } else { res.status(503).json({ status: 'error', message: 'Connection pool not available' }); } }); // PostGraphile middleware - mount at root path, let PostGraphile handle routing itself app.use((req, res, next) => { // Check if PostGraphile middleware exists if (!postgraphileMiddleware) { console.error('❌ PostGraphile middleware is null!'); if (req.path.startsWith('/graphql')) { res.status(500).json({ error: 'PostGraphile middleware not properly initialized' }); return; } next(); return; } try { postgraphileMiddleware(req, res, next); } catch (error) { console.error('❌ PostGraphile middleware execution error:', error); if (req.path.startsWith('/graphql')) { res.status(500).json({ error: 'PostGraphile execution error', details: error instanceof Error ? error.message : String(error) }); return; } next(); } }); // Error handling middleware app.use((err, req, res, _next) => { logger_1.serverLogger.error('Express error handling', err, { url: req.originalUrl, method: req.method, userAgent: req.get('user-agent')?.substring(0, 50) }); res.status(500).send('Internal Server Error'); }); return app; } // Create and configure HTTP server async createEnhancedServer(serverConfig) { const { postgraphileMiddleware, pgPool } = serverConfig; // Store pool references for monitoring this.pgPool = pgPool; // Create Express application this.app = this.createExpressApp(serverConfig); // Create HTTP server this.httpServer = (0, http_1.createServer)(this.app); // Enable PostgreSQL subscriptions and WebSocket support if (this.config.capabilities.pgSubscriptions) { (0, postgraphile_1.enhanceHttpServerWithSubscriptions)(this.httpServer, postgraphileMiddleware, { // Enable WebSocket transport graphqlRoute: '/graphql' }); logger_1.systemLogger.info('✅ PostgreSQL subscriptions and WebSocket enabled', { pgSubscriptions: this.config.capabilities.pgSubscriptions, webSocket: true }); } logger_1.serverLogger.info('🚀 Express server creation completed', { framework: 'Express', graphqlPort: this.config.graphqlPort, capabilities: { pgSubscriptions: this.config.capabilities.pgSubscriptions }, recommendedMethod: 'pg-subscriptions' }); return this.httpServer; } // Start server async startServer() { if (!this.httpServer) { throw new Error('Server not created, please call createEnhancedServer() first'); } return new Promise((resolve, reject) => { this.httpServer.listen(this.config.graphqlPort, (err) => { if (err) { reject(err); return; } this.logServerStatus(); resolve(); }); }); } // Log server status logServerStatus() { const clientConfig = subscription_config_1.subscriptionConfig.generateClientConfig(); logger_1.serverLogger.info('🎉 Express GraphQL server started successfully!', { port: this.config.graphqlPort, framework: 'Express', endpoints: { home: `http://localhost:${this.config.graphqlPort}/`, playground: `http://localhost:${this.config.graphqlPort}/playground`, graphql: clientConfig.graphqlEndpoint, subscription: clientConfig.subscriptionEndpoint, health: `http://localhost:${this.config.graphqlPort}/health`, config: `http://localhost:${this.config.graphqlPort}/subscription-config`, docs: `http://localhost:${this.config.graphqlPort}/subscription-docs` } }); // Display main access links console.log('\n' + '🌟'.repeat(30)); console.log('🏠 Homepage: ' + `http://localhost:${this.config.graphqlPort}/`); console.log('🎮 Playground: ' + `http://localhost:${this.config.graphqlPort}/playground`); console.log('🔗 GraphQL: ' + clientConfig.graphqlEndpoint); console.log('📡 WebSocket: ' + clientConfig.subscriptionEndpoint); console.log('🌟'.repeat(30) + '\n'); } // Get subscription status getSubscriptionStatus() { return { enabled: this.config.capabilities.pgSubscriptions, method: 'pg-subscriptions', config: subscription_config_1.subscriptionConfig.generateClientConfig() }; } // Quick shutdown async quickShutdown() { logger_1.systemLogger.info('🛑 Starting quick shutdown of Express server...'); if (this.httpServer) { this.httpServer.close(); logger_1.systemLogger.info('✅ HTTP server closed'); } logger_1.systemLogger.info('🎯 Express server quick shutdown completed'); } // Graceful shutdown async gracefulShutdown(pgPool) { logger_1.systemLogger.info('🛑 Starting graceful shutdown of Express server...'); const shutdownPromises = []; // Close HTTP server if (this.httpServer) { shutdownPromises.push(new Promise((resolve) => { this.httpServer.close(() => { logger_1.systemLogger.info('✅ HTTP server closed'); resolve(); }); })); } // Close database connection pool shutdownPromises.push(pgPool.end().then(() => { logger_1.systemLogger.info('✅ Database connection pool closed'); })); try { await Promise.all(shutdownPromises); logger_1.systemLogger.info('🎯 Express server graceful shutdown completed'); } catch (error) { logger_1.systemLogger.error('❌ Error occurred during shutdown process', error); throw error; } } } exports.EnhancedServerManager = EnhancedServerManager; //# sourceMappingURL=enhanced-server-manager.js.map