/** * DeepStudio Pro - Enhanced Production Server * Built with anycoder → https://huggingface.co/spaces/akhaliq/anycoder * * Features: * - Graceful shutdown handling * - Request logging and metrics * - Health check endpoint * - Memory and performance monitoring * - Security headers */ const path = require('path'); const http = require('http'); const { parse } = require('url'); const dir = path.join(__dirname); // Set production environment process.env.NODE_ENV = 'production'; process.chdir(__dirname); // Configuration with sensible defaults const config = { port: parseInt(process.env.PORT, 10) || 7860, hostname: process.env.HOSTNAME || '0.0.0.0', keepAliveTimeout: parseInt(process.env.KEEP_ALIVE_TIMEOUT, 10) || 65000, requestTimeout: parseInt(process.env.REQUEST_TIMEOUT, 10) || 30000, maxRequestsPerSocket: parseInt(process.env.MAX_REQUESTS_PER_SOCKET, 10) || 0, }; // Next.js configuration - optimized for production const nextConfig = { env: {}, webpack: null, eslint: { ignoreDuringBuilds: true }, typescript: { ignoreBuildErrors: false, tsconfigPath: 'tsconfig.json' }, distDir: './.next', cleanDistDir: true, assetPrefix: '', cacheMaxMemorySize: 52428800, configOrigin: 'next.config.ts', useFileSystemPublicRoutes: true, generateEtags: true, pageExtensions: ['tsx', 'ts', 'jsx', 'js'], poweredByHeader: false, // Security: disable X-Powered-By compress: true, images: { deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840], imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], path: '/_next/image', loader: 'default', loaderFile: '', domains: [], disableStaticImages: false, minimumCacheTTL: 60, formats: ['image/webp', 'image/avif'], dangerouslyAllowSVG: false, contentSecurityPolicy: "script-src 'none'; frame-src 'none'; sandbox;", contentDispositionType: 'attachment', remotePatterns: [], unoptimized: false, }, devIndicators: { position: 'bottom-left' }, onDemandEntries: { maxInactiveAge: 60000, pagesBufferLength: 5 }, amp: { canonicalBase: '' }, basePath: '', sassOptions: {}, trailingSlash: false, i18n: null, productionBrowserSourceMaps: false, excludeDefaultMomentLocales: true, serverRuntimeConfig: {}, publicRuntimeConfig: {}, reactProductionProfiling: false, reactStrictMode: true, reactMaxHeadersLength: 6000, httpAgentOptions: { keepAlive: true }, logging: {}, expireTime: 31536000, staticPageGenerationTimeout: 60, output: 'standalone', modularizeImports: { '@mui/icons-material': { transform: '@mui/icons-material/{{member}}' }, 'lodash': { transform: 'lodash/{{member}}' }, }, outputFileTracingRoot: process.cwd(), experimental: { optimizeCss: true, optimizePackageImports: [ 'lucide-react', 'date-fns', 'lodash-es', 'ramda', 'antd', 'react-bootstrap', 'ahooks', '@ant-design/icons', '@headlessui/react', '@headlessui-float/react', '@heroicons/react/20/solid', '@heroicons/react/24/solid', '@heroicons/react/24/outline', '@visx/visx', '@tremor/react', 'rxjs', '@mui/material', '@mui/icons-material', 'recharts', 'react-use', 'framer-motion', '@radix-ui/react-icons', ], }, }; // Serialize config for Next.js process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig); // Metrics tracking const metrics = { startTime: Date.now(), requests: { total: 0, success: 0, error: 0 }, activeConnections: 0, }; // Request logging middleware function logRequest(req, res, startTime) { const duration = Date.now() - startTime; const logEntry = { timestamp: new Date().toISOString(), method: req.method, url: req.url, status: res.statusCode, duration: `${duration}ms`, userAgent: req.headers['user-agent'], ip: req.headers['x-forwarded-for'] || req.socket.remoteAddress, }; // Log errors with more detail if (res.statusCode >= 400) { console.error('[REQUEST ERROR]', JSON.stringify(logEntry)); metrics.requests.error++; } else { console.log('[REQUEST]', JSON.stringify(logEntry)); metrics.requests.success++; } metrics.requests.total++; } // Security headers middleware function setSecurityHeaders(res) { res.setHeader('X-DNS-Prefetch-Control', 'on'); res.setHeader('Strict-Transport-Security', 'max-age=63072000; includeSubDomains; preload'); res.setHeader('X-Frame-Options', 'SAMEORIGIN'); res.setHeader('X-Content-Type-Options', 'nosniff'); res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin'); res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()'); } // Health check handler function healthCheck(req, res) { const uptime = Date.now() - metrics.startTime; const health = { status: 'healthy', timestamp: new Date().toISOString(), uptime: `${Math.floor(uptime / 1000)}s`, version: process.env.npm_package_version || '2.0.0', nodejs: process.version, memory: process.memoryUsage(), metrics: { requests: metrics.requests, activeConnections: metrics.activeConnections, }, }; res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(health, null, 2)); } // Metrics endpoint for monitoring function metricsEndpoint(req, res) { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ ...metrics, memory: process.memoryUsage(), cpu: process.cpuUsage(), uptime: process.uptime(), }, null, 2)); } // Main server startup async function startServer() { const { startServer: startNextServer } = require('next/dist/server/lib/start-server'); // Validate keep-alive timeout let keepAliveTimeout = config.keepAliveTimeout; if ( Number.isNaN(keepAliveTimeout) || !Number.isFinite(keepAliveTimeout) || keepAliveTimeout < 0 ) { keepAliveTimeout = undefined; } console.log(` ╔══════════════════════════════════════════════════════════════╗ ║ DeepStudio Pro - Starting Production Server ║ ║ Built with anycoder → https://huggingface.co/spaces/akhaliq/anycoder ║ ╠══════════════════════════════════════════════════════════════╣ Port: ${config.port} Hostname: ${config.hostname} Node Env: ${process.env.NODE_ENV} Node Ver: ${process.version} Start Time: ${new Date().toISOString()} ╚══════════════════════════════════════════════════════════════╝ `); try { // Start the Next.js server const server = await startNextServer({ dir, isDev: false, config: nextConfig, hostname: config.hostname, port: config.port, allowRetry: false, keepAliveTimeout, }); // Get the underlying HTTP server to add custom middleware const httpServer = server.server; // Track connections for graceful shutdown httpServer.on('connection', (socket) => { metrics.activeConnections++; socket.on('close', () => { metrics.activeConnections--; }); }); // Custom request handling for health checks and metrics const originalHandler = httpServer.listeners('request')[0]; httpServer.removeAllListeners('request'); httpServer.on('request', (req, res) => { const startTime = Date.now(); // Set security headers on all responses setSecurityHeaders(res); // Intercept health check requests const parsedUrl = parse(req.url, true); if (parsedUrl.pathname === '/api/health') { healthCheck(req, res); return; } // Metrics endpoint (basic auth in production recommended) if (parsedUrl.pathname === '/api/metrics') { metricsEndpoint(req, res); return; } // Log response when finished res.on('finish', () => logRequest(req, res, startTime)); // Pass to Next.js handler originalHandler(req, res); }); // Graceful shutdown handling const shutdown = (signal) => { console.log(`\n[SHUTDOWN] Received ${signal}. Starting graceful shutdown...`); console.log(`[SHUTDOWN] Active connections: ${metrics.activeConnections}`); // Stop accepting new connections httpServer.close(() => { console.log('[SHUTDOWN] HTTP server closed'); process.exit(0); }); // Force shutdown after timeout setTimeout(() => { console.error('[SHUTDOWN] Forced shutdown after timeout'); process.exit(1); }, 30000); }; process.on('SIGTERM', () => shutdown('SIGTERM')); process.on('SIGINT', () => shutdown('SIGINT')); // Handle uncaught errors process.on('uncaughtException', (err) => { console.error('[FATAL] Uncaught exception:', err); process.exit(1); }); process.on('unhandledRejection', (reason, promise) => { console.error('[FATAL] Unhandled rejection at:', promise, 'reason:', reason); process.exit(1); }); console.log(`[READY] Server running at http://${config.hostname}:${config.port}`); return server; } catch (err) { console.error('[FATAL] Failed to start server:', err); process.exit(1); } } // Start the server startServer();