Spaces:
Sleeping
Sleeping
| import express from "express"; | |
| import cors from "cors"; | |
| import fs from "fs-extra"; | |
| import path from "path"; | |
| import { spawn, exec } from "child_process"; | |
| import httpProxy from "http-proxy"; | |
| const app = express(); | |
| /* ================= CONFIGURATION ================= */ | |
| const PORT = 7860; | |
| const VITE_PORT = parseInt(process.env.VITE_PORT || "5173"); | |
| const PROJECT_DIR = path.join(process.cwd(), "project"); | |
| const MASTER_KEY = "AVNEESH_GOD_MODE_777"; | |
| const ALLOWED_ORIGINS = [ | |
| "https://avneesh123-autodev-mark2.hf.space", | |
| "https://avneesh123-autodev-mark2-engine.hf.space", | |
| "https://avneesh123-autodev-mark2.hf.space/chat", | |
| "http://localhost:5173", | |
| "http://localhost:3000", | |
| "http://127.0.0.1:5173", | |
| ]; | |
| // ================= SECURE IFRAME LOCK ================= | |
| app.use((req, res, next) => { | |
| res.removeHeader("X-Frame-Options"); | |
| res.setHeader( | |
| "Content-Security-Policy", | |
| "frame-ancestors 'self' https://*.hf.space http://localhost:* http://127.0.0.1:*" | |
| ); | |
| next(); | |
| }); | |
| // --- Process Managers --- | |
| let viteProcess = null; | |
| let isBooting = false; | |
| let buildRetryCount = 0; | |
| const MAX_RETRIES = 3; | |
| const bgProcesses = new Map(); | |
| // ================= PERSISTENT LOCK FILES ================= | |
| const FOUNDATION_LOCK = path.join(process.cwd(), ".foundation_lock"); | |
| const DEPS_LOCK = path.join(process.cwd(), ".deps_lock"); | |
| /* ================= BINARY FILE EXTENSIONS ================= */ | |
| const BINARY_EXTS = [ | |
| ".png", ".jpg", ".jpeg", ".gif", ".webp", ".ico", ".svg", | |
| ".pdf", ".zip", ".tar", ".gz", | |
| ".ttf", ".woff", ".woff2", ".otf", ".eot", | |
| ".mp3", ".mp4", ".wav" | |
| ]; | |
| function isBinaryFile(filePath) { | |
| const ext = path.extname(filePath).toLowerCase(); | |
| return BINARY_EXTS.includes(ext); | |
| } | |
| /* ================= IDLE TRACKER ================= */ | |
| let lastActivityTime = Date.now(); | |
| const IDLE_TIMEOUT = 10 * 60 * 1000; | |
| const IGNORE_ACTIVITY_PATHS = ["/api/logs", "/health", "/api/status"]; | |
| function updateActivity(req) { | |
| if (!IGNORE_ACTIVITY_PATHS.some(p => req.path.startsWith(p))) { | |
| lastActivityTime = Date.now(); | |
| } | |
| } | |
| setInterval(async () => { | |
| const idleMs = Date.now() - lastActivityTime; | |
| if (idleMs > IDLE_TIMEOUT && viteProcess) { | |
| pushLog(`[IDLE] No activity for ${Math.round(idleMs / 60000)} min β stopping Vite to save resources`, "warning"); | |
| await killVite(); | |
| bgProcesses.forEach((_, id) => killBgProcess(id)); | |
| } | |
| }, 60 * 1000); | |
| /* ================= LOG STREAM ================= */ | |
| let logs = []; | |
| let clients = new Set(); | |
| function pushLog(message, type = "info") { | |
| const entry = { | |
| id: Date.now() + Math.random(), | |
| time: new Date().toLocaleTimeString(), | |
| timestamp: Date.now(), | |
| message, | |
| type | |
| }; | |
| logs.push(entry); | |
| if (logs.length > 500) logs.shift(); | |
| const payload = `data: ${JSON.stringify(entry)}\n\n`; | |
| clients.forEach(c => { | |
| try { c.write(payload); } catch { clients.delete(c); } | |
| }); | |
| console.log(`[${type.toUpperCase()}] ${message}`); | |
| } | |
| /* ================= MIDDLEWARE ================= */ | |
| app.use(cors({ | |
| origin: (origin, callback) => { | |
| if (!origin) return callback(null, true); | |
| if (ALLOWED_ORIGINS.includes(origin) || origin.endsWith(".hf.space")) return callback(null, true); | |
| pushLog(`[SECURITY] CORS DENIED β origin: ${origin}`, "error"); | |
| callback(new Error("ACTION_DENIED")); | |
| }, | |
| credentials: true | |
| })); | |
| app.use(express.json({ limit: "50mb" })); | |
| app.use((err, req, res, next) => { | |
| if (err.message === "ACTION_DENIED") { | |
| return res.status(403).json({ error: "ACTION_DENIED", message: "Origin not allowed" }); | |
| } | |
| next(err); | |
| }); | |
| if (!fs.existsSync(PROJECT_DIR)) { | |
| fs.mkdirSync(PROJECT_DIR, { recursive: true }); | |
| } | |
| /* ================= RATE LIMITER & TOKEN SECURITY ================= */ | |
| const rateLimitMap = new Map(); | |
| function rateLimit(req, res, maxRequests = 30, windowMs = 60000) { | |
| const ip = req.ip || req.socket.remoteAddress; | |
| const now = Date.now(); | |
| const windowStart = now - windowMs; | |
| if (!rateLimitMap.has(ip)) rateLimitMap.set(ip, []); | |
| const requests = rateLimitMap.get(ip).filter(t => t > windowStart); | |
| requests.push(now); | |
| rateLimitMap.set(ip, requests); | |
| if (requests.length > maxRequests) { | |
| pushLog(`[RATE LIMIT] IP ${ip} throttled`, "warning"); | |
| res.status(429).json({ error: "TOO_MANY_REQUESTS", retryAfter: 60 }); | |
| return false; | |
| } | |
| return true; | |
| } | |
| function verifyToken(req, res) { | |
| const token = req.body?.token || req.query?.token || req.headers?.["x-api-key"]; | |
| if (token !== MASTER_KEY) { | |
| pushLog(`[SECURITY] Unauthorized access attempt from ${req.ip}`, "error"); | |
| res.status(403).json({ error: "ACTION_DENIED", message: "Invalid token" }); | |
| return false; | |
| } | |
| return true; | |
| } | |
| /* ================= SSE LOG STREAM ================= */ | |
| app.get("/api/logs", (req, res) => { | |
| res.setHeader("Content-Type", "text/event-stream"); | |
| res.setHeader("Cache-Control", "no-cache"); | |
| res.setHeader("Connection", "keep-alive"); | |
| // BUG FIX #1: X-Accel-Buffering missing tha β HF/nginx ke peeche SSE buffer | |
| // ho jaata tha, logs real-time nahi aate the client tak | |
| res.setHeader("X-Accel-Buffering", "no"); | |
| const last = parseInt(req.query.last) || 50; | |
| logs.slice(-last).forEach(l => res.write(`data: ${JSON.stringify(l)}\n\n`)); | |
| // Heartbeat β 30s mein connection alive rakhne ke liye | |
| const heartbeat = setInterval(() => { | |
| try { res.write(`: heartbeat\n\n`); } catch { clearInterval(heartbeat); } | |
| }, 30000); | |
| clients.add(res); | |
| req.on("close", () => { | |
| clients.delete(res); | |
| clearInterval(heartbeat); | |
| }); | |
| }); | |
| /* ================= MULTI-SERVER MANAGER ================= */ | |
| function startBgProcess(id, command, port = null) { | |
| if (bgProcesses.has(id)) { | |
| pushLog(`[SERVER] Process ${id} is already running`, "warning"); | |
| return false; | |
| } | |
| pushLog(`[SERVER] Starting background process [${id}]: ${command}`, "system"); | |
| const proc = spawn(command, { | |
| cwd: PROJECT_DIR, | |
| shell: true, | |
| env: { ...process.env, PORT: port ? String(port) : undefined } | |
| }); | |
| proc.stdout.on("data", d => pushLog(`[${id.toUpperCase()}] ${d.toString().trim()}`, "info")); | |
| proc.stderr.on("data", d => pushLog(`[${id.toUpperCase()} ERROR] ${d.toString().trim()}`, "error")); | |
| proc.on("close", code => { | |
| pushLog(`[SERVER] Process ${id} stopped (code: ${code})`, "system"); | |
| bgProcesses.delete(id); | |
| }); | |
| bgProcesses.set(id, { process: proc, command, port }); | |
| return true; | |
| } | |
| function killBgProcess(id) { | |
| if (!bgProcesses.has(id)) return false; | |
| const { process: proc } = bgProcesses.get(id); | |
| proc.kill("SIGKILL"); | |
| bgProcesses.delete(id); | |
| pushLog(`[SERVER] Killed background process: ${id}`, "warning"); | |
| return true; | |
| } | |
| app.post("/api/process/start", (req, res) => { | |
| if (!verifyToken(req, res)) return; | |
| const { id, command, port } = req.body; | |
| if (!id || !command) return res.status(400).json({ error: "ID and command required" }); | |
| const success = startBgProcess(id, command, port); | |
| res.json({ success, message: success ? "Process started" : "Process already running" }); | |
| }); | |
| app.post("/api/process/stop", (req, res) => { | |
| if (!verifyToken(req, res)) return; | |
| const { id } = req.body; | |
| const success = killBgProcess(id); | |
| res.json({ success, message: success ? "Process stopped" : "Process not found" }); | |
| }); | |
| /* ================= VITE MANAGER ================= */ | |
| function killVite() { | |
| return new Promise((resolve) => { | |
| if (viteProcess) { | |
| pushLog("[SYSTEM] Killing existing Vite process", "system"); | |
| viteProcess.kill("SIGKILL"); | |
| viteProcess = null; | |
| } | |
| const killCmd = process.platform === "win32" | |
| ? `for /f "tokens=5" %a in ('netstat -aon ^| findstr :${VITE_PORT}') do taskkill /F /PID %a` | |
| : `fuser -k ${VITE_PORT}/tcp`; | |
| exec(killCmd, () => setTimeout(resolve, 1500)); | |
| }); | |
| } | |
| function startVite(forceRestart = false) { | |
| if (isBooting && !forceRestart) return; | |
| if (viteProcess && !forceRestart) return; | |
| if (forceRestart) { | |
| isBooting = true; | |
| killVite().then(() => bootVite()); | |
| } else { | |
| bootVite(); | |
| } | |
| } | |
| function bootVite() { | |
| pushLog("[SYSTEM] Starting Vite dev server...", "system"); | |
| isBooting = true; | |
| const nodeModules = path.join(PROJECT_DIR, "node_modules"); | |
| const boot = () => { | |
| viteProcess = spawn("pnpm", ["run", "dev", "--", "--host", "0.0.0.0", "--port", String(VITE_PORT)], { | |
| cwd: PROJECT_DIR, | |
| shell: true, | |
| env: { ...process.env, FORCE_COLOR: "0" } | |
| }); | |
| viteProcess.stdout.on("data", d => { | |
| const msg = d.toString().trim(); | |
| if (!msg) return; | |
| pushLog("[VITE] " + msg, "info"); | |
| if (msg.includes("Local:") || msg.includes("ready in") || msg.includes("localhost")) { | |
| isBooting = false; | |
| buildRetryCount = 0; | |
| pushLog("[SYSTEM] β Vite is ready!", "success"); | |
| } | |
| }); | |
| viteProcess.stderr.on("data", d => { | |
| const msg = d.toString().trim(); | |
| if (!msg) return; | |
| pushLog("[VITE ERROR] " + msg, "error"); | |
| }); | |
| viteProcess.on("close", (code) => { | |
| pushLog(`[SYSTEM] Vite stopped (exit code: ${code})`, "system"); | |
| viteProcess = null; | |
| isBooting = false; | |
| if (code !== null && code !== 0 && buildRetryCount < MAX_RETRIES) { | |
| buildRetryCount++; | |
| pushLog(`[SYSTEM] Auto-restarting Vite (attempt ${buildRetryCount}/${MAX_RETRIES})...`, "warning"); | |
| setTimeout(() => killVite().then(() => bootVite()), 3000); | |
| } | |
| }); | |
| }; | |
| if (fs.existsSync(DEPS_LOCK) && fs.existsSync(nodeModules)) { | |
| pushLog("[INSTALL] β Dependencies locked β skipping install", "success"); | |
| boot(); | |
| return; | |
| } | |
| pushLog("[INSTALL] Installing dependencies...", "system"); | |
| const install = spawn("pnpm", ["install"], { cwd: PROJECT_DIR, shell: true }); | |
| install.stdout.on("data", d => pushLog("[INSTALL] " + d.toString().trim(), "info")); | |
| install.stderr.on("data", d => pushLog("[INSTALL] " + d.toString().trim(), "warning")); | |
| install.on("close", code => { | |
| if (code === 0) { | |
| fs.writeFileSync(DEPS_LOCK, new Date().toISOString()); | |
| pushLog("[INSTALL] β Dependencies installed!", "success"); | |
| boot(); | |
| } else { | |
| pushLog("[ERROR] β pnpm install failed!", "error"); | |
| isBooting = false; | |
| } | |
| }); | |
| } | |
| /* ================= STATUS ================= */ | |
| app.get("/api/status", (req, res) => { | |
| res.json({ | |
| ready: !!viteProcess && !isBooting, | |
| booting: isBooting, | |
| viteRunning: !!viteProcess, | |
| activeBackgroundProcesses: Array.from(bgProcesses.keys()), | |
| uptime: process.uptime(), | |
| logCount: logs.length | |
| }); | |
| }); | |
| /* ================= FILE UPDATE ================= */ | |
| app.post("/api/update", async (req, res) => { | |
| if (!verifyToken(req, res)) return; | |
| if (!rateLimit(req, res, 20, 60000)) return; | |
| updateActivity(req); | |
| const foundationAlreadyWritten = fs.existsSync(FOUNDATION_LOCK); | |
| const { files, restart = false } = req.body; | |
| try { | |
| if (files && Object.keys(files).length > 0) { | |
| const updatedFiles = []; | |
| for (const [p, contentObj] of Object.entries(files)) { | |
| const safePath = path.normalize(p).replace(/^(\.\.[\/\\])+/, ""); | |
| const fp = path.join(PROJECT_DIR, safePath); | |
| if (!fp.startsWith(PROJECT_DIR)) { | |
| pushLog(`[SECURITY] Blocked path traversal: ${p}`, "error"); | |
| continue; | |
| } | |
| await fs.ensureDir(path.dirname(fp)); | |
| // BUG FIX #2: contentObj null/undefined hone par crash hota tha | |
| // typeof check se pehle null guard lagao | |
| const fileContent = contentObj == null | |
| ? "" | |
| : typeof contentObj === "string" | |
| ? contentObj | |
| : contentObj.content ?? ""; | |
| const isBase64 = contentObj?.isBase64 || isBinaryFile(safePath); | |
| if (isBase64 && fileContent) { | |
| await fs.writeFile(fp, Buffer.from(fileContent, "base64")); | |
| } else { | |
| await fs.writeFile(fp, fileContent, "utf-8"); | |
| } | |
| updatedFiles.push(safePath); | |
| } | |
| if (!foundationAlreadyWritten) { | |
| fs.writeFileSync(FOUNDATION_LOCK, new Date().toISOString()); | |
| } | |
| pushLog(`[FILES] β Updated ${updatedFiles.length} files`, "success"); | |
| } | |
| if (restart) startVite(true); | |
| else startVite(); | |
| res.json({ success: true, filesUpdated: Object.keys(files || {}).length }); | |
| } catch (e) { | |
| pushLog("[ERROR] File update failed: " + e.message, "error"); | |
| res.status(500).json({ error: e.message }); | |
| } | |
| }); | |
| /* ================= FILE READ ================= */ | |
| app.post("/api/read", async (req, res) => { | |
| if (!verifyToken(req, res)) return; | |
| updateActivity(req); | |
| const { filePath } = req.body; | |
| try { | |
| const safePath = path.normalize(filePath).replace(/^(\.\.[\/\\])+/, ""); | |
| const fp = path.join(PROJECT_DIR, safePath); | |
| if (!fp.startsWith(PROJECT_DIR)) return res.status(403).json({ error: "Path traversal blocked" }); | |
| if (!fs.existsSync(fp)) return res.status(404).json({ error: "File not found" }); | |
| const isBinary = isBinaryFile(safePath); | |
| const content = isBinary | |
| ? await fs.readFile(fp, "base64") | |
| : await fs.readFile(fp, "utf-8"); | |
| res.json({ success: true, content, path: safePath, isBase64: isBinary }); | |
| } catch (e) { | |
| res.status(500).json({ error: e.message }); | |
| } | |
| }); | |
| /* ================= FILE LIST & DELETE ================= */ | |
| app.post("/api/files", async (req, res) => { | |
| if (!verifyToken(req, res)) return; | |
| updateActivity(req); | |
| async function walkDir(dir, base = "") { | |
| const items = []; | |
| try { | |
| const entries = await fs.readdir(dir, { withFileTypes: true }); | |
| for (const entry of entries) { | |
| if (["node_modules", ".git", "dist", ".cache"].includes(entry.name)) continue; | |
| const relPath = path.join(base, entry.name); | |
| if (entry.isDirectory()) { | |
| const children = await walkDir(path.join(dir, entry.name), relPath); | |
| items.push({ name: entry.name, path: relPath, type: "dir", children }); | |
| } else { | |
| items.push({ name: entry.name, path: relPath, type: "file" }); | |
| } | |
| } | |
| } catch {} | |
| return items; | |
| } | |
| const tree = await walkDir(PROJECT_DIR); | |
| res.json({ success: true, tree }); | |
| }); | |
| app.post("/api/delete", async (req, res) => { | |
| if (!verifyToken(req, res)) return; | |
| updateActivity(req); | |
| const { filePath } = req.body; | |
| try { | |
| const safePath = path.normalize(filePath).replace(/^(\.\.[\/\\])+/, ""); | |
| const fp = path.join(PROJECT_DIR, safePath); | |
| if (!fp.startsWith(PROJECT_DIR)) return res.status(403).json({ error: "Path traversal blocked" }); | |
| await fs.remove(fp); | |
| pushLog(`[FILES] Deleted: ${safePath}`, "warning"); | |
| res.json({ success: true }); | |
| } catch (e) { | |
| res.status(500).json({ error: e.message }); | |
| } | |
| }); | |
| /* ================= COMMAND EXEC ================= */ | |
| const BLOCKED_COMMANDS = ["rm -rf /", "mkfs", ":(){ :|:& };:", "shutdown", "reboot", "format"]; | |
| app.post("/api/execute", (req, res) => { | |
| if (!verifyToken(req, res)) return; | |
| if (!rateLimit(req, res, 15, 60000)) return; | |
| updateActivity(req); | |
| const { command, timeout = 30000 } = req.body; | |
| const isBlocked = BLOCKED_COMMANDS.some(cmd => command.includes(cmd)); | |
| if (isBlocked) { | |
| pushLog(`[SECURITY] Blocked dangerous command: ${command}`, "error"); | |
| return res.status(403).json({ error: "COMMAND_BLOCKED" }); | |
| } | |
| pushLog("[TERMINAL] $ " + command, "system"); | |
| const child = exec(command, { cwd: PROJECT_DIR, timeout, maxBuffer: 1024 * 1024 * 10 }, (err, stdout, stderr) => { | |
| const output = stdout || stderr || err?.message || ""; | |
| const success = !err; | |
| const exitCode = child.exitCode ?? (err ? 1 : 0); | |
| if (success) pushLog("[TERMINAL] β Done", "success"); | |
| else pushLog("[TERMINAL] β " + (err?.message || "Command failed"), "error"); | |
| res.json({ success, output, exitCode }); | |
| }); | |
| }); | |
| /* ================= HEALTH CHECK ================= */ | |
| app.get("/health", (req, res) => { | |
| res.json({ | |
| status: "ok", | |
| uptime: process.uptime(), | |
| memory: process.memoryUsage(), | |
| vite: !!viteProcess, | |
| timestamp: new Date().toISOString() | |
| }); | |
| }); | |
| /* ================= VITE CONTROL & RESET ================= */ | |
| app.post("/api/vite/restart", async (req, res) => { | |
| if (!verifyToken(req, res)) return; | |
| updateActivity(req); | |
| pushLog("[SYSTEM] Manual Vite restart requested", "system"); | |
| buildRetryCount = 0; | |
| startVite(true); | |
| res.json({ success: true, message: "Vite restart initiated" }); | |
| }); | |
| app.post("/api/vite/stop", async (req, res) => { | |
| if (!verifyToken(req, res)) return; | |
| await killVite(); | |
| res.json({ success: true, message: "Vite stopped" }); | |
| }); | |
| app.post("/api/reset", async (req, res) => { | |
| if (!verifyToken(req, res)) return; | |
| try { | |
| pushLog("[SYSTEM] Resetting project...", "warning"); | |
| await killVite(); | |
| bgProcesses.forEach((_, id) => killBgProcess(id)); | |
| await fs.remove(PROJECT_DIR); | |
| fs.mkdirSync(PROJECT_DIR, { recursive: true }); | |
| if (fs.existsSync(FOUNDATION_LOCK)) fs.removeSync(FOUNDATION_LOCK); | |
| if (fs.existsSync(DEPS_LOCK)) fs.removeSync(DEPS_LOCK); | |
| buildRetryCount = 0; | |
| pushLog("[SYSTEM] β Project reset complete", "success"); | |
| res.json({ success: true }); | |
| } catch (e) { | |
| res.status(500).json({ error: e.message }); | |
| } | |
| }); | |
| /* ================= PROXY ================= */ | |
| const proxy = httpProxy.createProxyServer({ | |
| target: `http://127.0.0.1:${VITE_PORT}`, | |
| changeOrigin: true, | |
| ws: true | |
| }); | |
| const PREVIEW_SECRET = "AUTODEV_PREVIEW_777"; | |
| const ACCESS_DENIED_PAGE = `<!DOCTYPE html><html><head><title>Access Denied</title><style>body{background:#09090b;color:#fff;font-family:monospace;display:flex;align-items:center;justify-content:center;height:100vh;flex-direction:column;gap:16px;}.title{color:#ef4444;font-size:1.4rem;font-weight:bold;}</style></head><body><div class="title">ACCESS DENIED</div><div>This preview is protected</div></body></html>`; | |
| const BOOTING_PAGE = `<!DOCTYPE html><html><head><title>Booting...</title><style>body{background:#09090b;color:#facc15;font-family:monospace;display:flex;align-items:center;justify-content:center;height:100vh;}</style><script>setTimeout(()=>location.reload(), 2000)</script></head><body>β‘ AutoDev is booting up...</body></html>`; | |
| // BUG FIX #3: proxyRes handler WRONG tha β http-proxy already headers forward | |
| // kar chuka hota hai jab proxyRes fire hota hai, toh wahan set karna useless tha. | |
| // Sahi fix: upar wala app.use iframe middleware engine responses cover karta hai. | |
| // proxyRes handler hata diya. | |
| proxy.on("error", (err, req, res) => { | |
| if (res && typeof res.writeHead === "function") { | |
| try { | |
| res.writeHead(503, { "Content-Type": "text/html" }); | |
| res.end(BOOTING_PAGE); | |
| } catch {} | |
| } else if (res && typeof res.destroy === "function") { | |
| res.destroy(); | |
| } | |
| }); | |
| app.use((req, res, next) => { | |
| if (req.path.startsWith("/api") || req.path === "/health") return next(); | |
| const isRootRequest = req.path === "/" || req.path === ""; | |
| if (isRootRequest) { | |
| const previewHeader = req.headers["x-autodev-preview"]; | |
| const previewParam = req.query["__autodev"]; | |
| if (previewHeader !== PREVIEW_SECRET && previewParam !== PREVIEW_SECRET) { | |
| pushLog(`[SECURITY] Preview blocked β direct access attempt`, "warning"); | |
| return res.status(403).send(ACCESS_DENIED_PAGE); | |
| } | |
| } | |
| updateActivity(req); | |
| if (!viteProcess && !isBooting) startVite(); | |
| proxy.web(req, res); | |
| }); | |
| const server = app.listen(PORT, () => { | |
| pushLog(`[SYSTEM] AutoDev Engine running on port ${PORT}`, "system"); | |
| }); | |
| server.on("upgrade", (req, socket, head) => proxy.ws(req, socket, head)); | |
| /* ================= GRACEFUL SHUTDOWN ================= */ | |
| process.on("SIGTERM", async () => { | |
| pushLog("[SYSTEM] Shutting down...", "system"); | |
| await killVite(); | |
| bgProcesses.forEach((_, id) => killBgProcess(id)); | |
| process.exit(0); | |
| }); | |
| process.on("SIGINT", async () => { | |
| await killVite(); | |
| bgProcesses.forEach((_, id) => killBgProcess(id)); | |
| process.exit(0); | |
| }); | |
| process.on("uncaughtException", err => pushLog("[CRITICAL] Uncaught Exception: " + err.message, "error")); | |
| process.on("unhandledRejection", reason => pushLog("[CRITICAL] Unhandled Rejection: " + reason, "error")); |