const express = require('express'); const cors = require('cors'); const SimpleSandboxManager = require('./simple-sandbox-manager'); const app = express(); // Development ke liye sabhi origins ko allow karein app.use(cors({ origin: '*' })); app.use(express.json({ limit: '50mb' })); const sandboxManager = new SimpleSandboxManager(); (async () => { await sandboxManager.initialize(); console.log('🚀 Custom Sandbox Manager is ready.'); })(); // Health check app.get('/health', (req, res) => { res.status(200).json({ status: 'healthy', sandboxes: sandboxManager.sandboxes.size }); }); // === Vercel SDK Compatible API Endpoints === // 1. Create a new sandbox app.post('/api/sandboxes', async (req, res) => { try { const { timeout = 600000, template = 'next-js' } = req.body; const sandboxId = `sbx_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const sandbox = await sandboxManager.createSandbox(sandboxId, { timeout, template }); // Sirf sandboxId return karein, jaisa original SDK expect karta hai res.json({ id: sandboxId, sandboxId: sandboxId }); // 'id' for compatibility } catch (error) { console.error('❌ Create error:', error); res.status(500).json({ error: error.message }); } }); // 2. Get sandbox status (for findById) app.get('/api/sandboxes/:id', async (req, res) => { try { const { id } = req.params; const sandbox = sandboxManager.getSandbox(id); if (!sandbox || sandboxManager.isTimedOut(id)) { if (sandbox) await sandboxManager.destroySandbox(id); return res.status(404).json({ error: 'Sandbox not found or has timed out' }); } // Status running bhejein agar sandbox maujood hai res.json({ status: 'running' }); } catch (error) { console.error('❌ Status error:', error); res.status(500).json({ error: error.message }); } }); // 3. Execute a command app.post('/api/sandboxes/:id/cmd', async (req, res) => { try { const { id } = req.params; const { command } = req.body; const result = await sandboxManager.executeCommand(id, command); res.json({ commandId: result.commandId, id: result.commandId }); // 'id' for compatibility } catch (error) { console.error('❌ Command error:', error); res.status(500).json({ error: error.message }); } }); // 4. Get final command info (for cmd.wait()) app.get('/api/sandboxes/:id/cmds/:cmdId', async (req, res) => { try { const { id, cmdId } = req.params; const cmdData = sandboxManager.getCommandData(id, cmdId); if (!cmdData || cmdData.exitCode === null) { // Agar command abhi bhi chal raha hai ya nahi mil raha, to running state bhejein return res.json({ exitCode: null, stdout: cmdData?.stdout || '', stderr: cmdData?.stderr || '' }); } res.json({ exitCode: cmdData.exitCode, stdout: cmdData.stdout || '', stderr: cmdData.stderr || '' }); } catch (error) { console.error('❌ Get command error:', error); res.status(404).json({ error: 'Command not found' }); } }); // 5. Stream command logs (SSE) app.get('/api/sandboxes/:id/cmds/:cmdId/logs', (req, res) => { const { id, cmdId } = req.params; console.log(`📡 SSE stream requested for ${id}/${cmdId}`); res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); res.setHeader('X-Accel-Buffering', 'no'); res.setHeader('Access-Control-Allow-Origin', '*'); res.flushHeaders(); sandboxManager.addStreamClient(id, cmdId, res); req.on('close', () => { sandboxManager.removeStreamClient(id, cmdId, res); console.log(`📡 SSE stream closed for ${id}/${cmdId}`); res.end(); }); }); // 6. Write a file app.post('/api/sandboxes/:id/fs/write', async (req, res) => { try { const { id } = req.params; const { path: filePath, content } = req.body; await sandboxManager.writeFile(id, filePath, content); res.status(204).send(); // 204 No Content is standard for successful writes } catch (error) { console.error('❌ File write error:', error); res.status(500).json({ error: error.message }); } }); // 7. Get Sandbox URL app.get('/api/sandboxes/:id/url', async (req, res) => { try { const { id } = req.params; const url = await sandboxManager.getURL(id); res.json({ url }); } catch (error) { console.error('❌ Get URL error:', error); res.status(404).json({ error: 'Sandbox or URL not found' }); } }); // Auto cleanup inactive sandboxes setInterval(() => { sandboxManager.cleanupInactive(); }, 5 * 60 * 1000); // Har 5 minute me check karein const PORT = 3001; app.listen(PORT, '0.0.0.0', () => { console.log(`🚀 Custom Sandbox API running on http://localhost:${PORT}`); }); process.on('SIGTERM', async () => { console.log('⚠️ Shutting down... cleaning up all sandboxes.'); await sandboxManager.destroyAllSandboxes(); process.exit(0); });