File size: 4,996 Bytes
0bedc61
 
cdda8ef
0bedc61
 
c904528
c4549b1
0bedc61
 
cdda8ef
19036c5
c4549b1
161aa64
c904528
c4549b1
0bedc61
0447e79
7dd64e7
 
 
 
 
 
 
c904528
 
 
3026f42
0bedc61
c904528
0447e79
 
3026f42
0bedc61
c904528
 
0bedc61
cdda8ef
0447e79
d3855e1
 
 
c904528
3026f42
d3855e1
0447e79
 
d3855e1
3026f42
 
c904528
d3855e1
0447e79
c904528
3026f42
d3855e1
0447e79
0bedc61
 
 
 
c904528
3026f42
0bedc61
0447e79
c904528
0bedc61
c904528
 
0bedc61
19036c5
0447e79
0bedc61
 
 
c904528
3026f42
7dd64e7
0447e79
c904528
7dd64e7
c904528
 
 
d3855e1
0447e79
d3855e1
c904528
6727a51
 
d3855e1
7dd64e7
41a968b
c904528
7dd64e7
 
 
c904528
3026f42
0447e79
41a968b
7dd64e7
 
 
 
 
 
 
 
0447e79
7dd64e7
 
3026f42
41a968b
7dd64e7
 
 
 
c904528
3026f42
0bedc61
0447e79
3026f42
 
c904528
0bedc61
7a4e883
0447e79
0bedc61
 
 
c904528
3026f42
7a4e883
3026f42
 
 
7a4e883
3026f42
 
7a4e883
 
 
c904528
cdda8ef
 
c904528
cdda8ef
c70a332
0bedc61
3026f42
cdda8ef
 
 
c904528
3026f42
cdda8ef
3026f42
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
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);
});