Spaces:
Build error
Build error
| /** | |
| * 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(); |