@treesap/sandbox 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +107 -0
- package/README.md +495 -0
- package/dist/api-server.d.ts +41 -0
- package/dist/api-server.d.ts.map +1 -0
- package/dist/api-server.js +536 -0
- package/dist/api-server.js.map +1 -0
- package/dist/auth-middleware.d.ts +31 -0
- package/dist/auth-middleware.d.ts.map +1 -0
- package/dist/auth-middleware.js +35 -0
- package/dist/auth-middleware.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +65 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +137 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +412 -0
- package/dist/client.js.map +1 -0
- package/dist/file-service.d.ts +94 -0
- package/dist/file-service.d.ts.map +1 -0
- package/dist/file-service.js +203 -0
- package/dist/file-service.js.map +1 -0
- package/dist/http-exposure-service.d.ts +71 -0
- package/dist/http-exposure-service.d.ts.map +1 -0
- package/dist/http-exposure-service.js +172 -0
- package/dist/http-exposure-service.js.map +1 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +66 -0
- package/dist/index.js.map +1 -0
- package/dist/sandbox-manager.d.ts +76 -0
- package/dist/sandbox-manager.d.ts.map +1 -0
- package/dist/sandbox-manager.js +161 -0
- package/dist/sandbox-manager.js.map +1 -0
- package/dist/sandbox.d.ts +118 -0
- package/dist/sandbox.d.ts.map +1 -0
- package/dist/sandbox.js +303 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +240 -0
- package/dist/server.js.map +1 -0
- package/dist/stream-service.d.ts +35 -0
- package/dist/stream-service.d.ts.map +1 -0
- package/dist/stream-service.js +136 -0
- package/dist/stream-service.js.map +1 -0
- package/dist/terminal.d.ts +46 -0
- package/dist/terminal.d.ts.map +1 -0
- package/dist/terminal.js +264 -0
- package/dist/terminal.js.map +1 -0
- package/dist/websocket.d.ts +48 -0
- package/dist/websocket.d.ts.map +1 -0
- package/dist/websocket.js +332 -0
- package/dist/websocket.js.map +1 -0
- package/package.json +59 -0
- package/src/api-server.ts +658 -0
- package/src/auth-middleware.ts +65 -0
- package/src/cli.ts +71 -0
- package/src/client.ts +537 -0
- package/src/file-service.ts +273 -0
- package/src/http-exposure-service.ts +232 -0
- package/src/index.ts +101 -0
- package/src/sandbox-manager.ts +202 -0
- package/src/sandbox.ts +396 -0
- package/src/stream-service.ts +174 -0
- package/tsconfig.json +37 -0
package/dist/sandbox.js
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import * as fs from 'fs/promises';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { EventEmitter } from 'events';
|
|
5
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
6
|
+
/**
|
|
7
|
+
* Represents a single isolated sandbox instance
|
|
8
|
+
* Each sandbox has its own working directory and process management
|
|
9
|
+
*/
|
|
10
|
+
export class Sandbox extends EventEmitter {
|
|
11
|
+
id;
|
|
12
|
+
workDir;
|
|
13
|
+
createdAt;
|
|
14
|
+
processes = new Map();
|
|
15
|
+
runningProcesses = new Map();
|
|
16
|
+
config;
|
|
17
|
+
destroyed = false;
|
|
18
|
+
constructor(config = {}) {
|
|
19
|
+
super();
|
|
20
|
+
this.id = config.id || uuidv4();
|
|
21
|
+
this.workDir = config.workDir || path.join(process.cwd(), '.sandboxes', this.id);
|
|
22
|
+
this.config = { ...config, env: config.env || {} };
|
|
23
|
+
this.createdAt = Date.now();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Initialize the sandbox (create working directory)
|
|
27
|
+
*/
|
|
28
|
+
async initialize() {
|
|
29
|
+
if (this.destroyed) {
|
|
30
|
+
throw new Error('Sandbox has been destroyed');
|
|
31
|
+
}
|
|
32
|
+
// Create working directory
|
|
33
|
+
await fs.mkdir(this.workDir, { recursive: true });
|
|
34
|
+
this.emit('initialized', { id: this.id, workDir: this.workDir });
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Execute a command and return the complete result
|
|
38
|
+
*/
|
|
39
|
+
async exec(command, options = {}) {
|
|
40
|
+
if (this.destroyed) {
|
|
41
|
+
throw new Error('Sandbox has been destroyed');
|
|
42
|
+
}
|
|
43
|
+
return new Promise((resolve) => {
|
|
44
|
+
let stdout = '';
|
|
45
|
+
let stderr = '';
|
|
46
|
+
let timedOut = false;
|
|
47
|
+
// Parse command and args
|
|
48
|
+
const [cmd, ...args] = this.parseCommand(command);
|
|
49
|
+
const childProcess = spawn(cmd, args, {
|
|
50
|
+
cwd: options.cwd || this.workDir,
|
|
51
|
+
env: { ...process.env, ...this.config.env, ...options.env },
|
|
52
|
+
shell: true,
|
|
53
|
+
});
|
|
54
|
+
// Handle timeout
|
|
55
|
+
let timeoutId;
|
|
56
|
+
const timeout = options.timeout || this.config.timeout;
|
|
57
|
+
if (timeout) {
|
|
58
|
+
timeoutId = setTimeout(() => {
|
|
59
|
+
timedOut = true;
|
|
60
|
+
childProcess.kill('SIGTERM');
|
|
61
|
+
// Force kill after 5 seconds
|
|
62
|
+
setTimeout(() => {
|
|
63
|
+
if (!childProcess.killed) {
|
|
64
|
+
childProcess.kill('SIGKILL');
|
|
65
|
+
}
|
|
66
|
+
}, 5000);
|
|
67
|
+
}, timeout);
|
|
68
|
+
}
|
|
69
|
+
// Capture stdout
|
|
70
|
+
childProcess.stdout?.on('data', (data) => {
|
|
71
|
+
const text = data.toString();
|
|
72
|
+
stdout += text;
|
|
73
|
+
if (options.stream && options.onOutput) {
|
|
74
|
+
options.onOutput('stdout', text);
|
|
75
|
+
}
|
|
76
|
+
this.emit('output', { stream: 'stdout', data: text });
|
|
77
|
+
});
|
|
78
|
+
// Capture stderr
|
|
79
|
+
childProcess.stderr?.on('data', (data) => {
|
|
80
|
+
const text = data.toString();
|
|
81
|
+
stderr += text;
|
|
82
|
+
if (options.stream && options.onOutput) {
|
|
83
|
+
options.onOutput('stderr', text);
|
|
84
|
+
}
|
|
85
|
+
this.emit('output', { stream: 'stderr', data: text });
|
|
86
|
+
});
|
|
87
|
+
// Handle process completion
|
|
88
|
+
childProcess.on('close', (exitCode) => {
|
|
89
|
+
if (timeoutId) {
|
|
90
|
+
clearTimeout(timeoutId);
|
|
91
|
+
}
|
|
92
|
+
const response = {
|
|
93
|
+
success: !timedOut && exitCode === 0,
|
|
94
|
+
stdout,
|
|
95
|
+
stderr,
|
|
96
|
+
exitCode: exitCode || 0,
|
|
97
|
+
timedOut,
|
|
98
|
+
};
|
|
99
|
+
this.emit('exec_complete', response);
|
|
100
|
+
resolve(response);
|
|
101
|
+
});
|
|
102
|
+
childProcess.on('error', (error) => {
|
|
103
|
+
if (timeoutId) {
|
|
104
|
+
clearTimeout(timeoutId);
|
|
105
|
+
}
|
|
106
|
+
const response = {
|
|
107
|
+
success: false,
|
|
108
|
+
stdout,
|
|
109
|
+
stderr: stderr + '\n' + error.message,
|
|
110
|
+
exitCode: 1,
|
|
111
|
+
};
|
|
112
|
+
this.emit('exec_error', error);
|
|
113
|
+
resolve(response);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Start a long-running background process
|
|
119
|
+
*/
|
|
120
|
+
async startProcess(command, options = {}) {
|
|
121
|
+
if (this.destroyed) {
|
|
122
|
+
throw new Error('Sandbox has been destroyed');
|
|
123
|
+
}
|
|
124
|
+
// Check max processes limit
|
|
125
|
+
if (this.config.maxProcesses && this.runningProcesses.size >= this.config.maxProcesses) {
|
|
126
|
+
throw new Error(`Maximum process limit reached (${this.config.maxProcesses})`);
|
|
127
|
+
}
|
|
128
|
+
const processId = uuidv4();
|
|
129
|
+
const [cmd, ...args] = this.parseCommand(command);
|
|
130
|
+
const childProcess = spawn(cmd, args, {
|
|
131
|
+
cwd: options.cwd || this.workDir,
|
|
132
|
+
env: { ...process.env, ...this.config.env, ...options.env },
|
|
133
|
+
shell: true,
|
|
134
|
+
});
|
|
135
|
+
const processInfo = {
|
|
136
|
+
id: processId,
|
|
137
|
+
pid: childProcess.pid,
|
|
138
|
+
command,
|
|
139
|
+
status: 'running',
|
|
140
|
+
startTime: Date.now(),
|
|
141
|
+
};
|
|
142
|
+
this.processes.set(processId, processInfo);
|
|
143
|
+
this.runningProcesses.set(processId, childProcess);
|
|
144
|
+
// Listen for output
|
|
145
|
+
childProcess.stdout?.on('data', (data) => {
|
|
146
|
+
this.emit('process_output', {
|
|
147
|
+
processId,
|
|
148
|
+
stream: 'stdout',
|
|
149
|
+
data: data.toString(),
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
childProcess.stderr?.on('data', (data) => {
|
|
153
|
+
this.emit('process_output', {
|
|
154
|
+
processId,
|
|
155
|
+
stream: 'stderr',
|
|
156
|
+
data: data.toString(),
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
// Handle process exit
|
|
160
|
+
childProcess.on('close', (exitCode) => {
|
|
161
|
+
const info = this.processes.get(processId);
|
|
162
|
+
if (info) {
|
|
163
|
+
info.status = exitCode === 0 ? 'completed' : 'failed';
|
|
164
|
+
info.exitCode = exitCode || 0;
|
|
165
|
+
}
|
|
166
|
+
this.runningProcesses.delete(processId);
|
|
167
|
+
this.emit('process_exit', { processId, exitCode });
|
|
168
|
+
});
|
|
169
|
+
this.emit('process_started', processInfo);
|
|
170
|
+
return processInfo;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* List all processes (running and completed)
|
|
174
|
+
*/
|
|
175
|
+
listProcesses() {
|
|
176
|
+
return Array.from(this.processes.values());
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Get information about a specific process
|
|
180
|
+
*/
|
|
181
|
+
getProcess(processId) {
|
|
182
|
+
return this.processes.get(processId);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Kill a specific process
|
|
186
|
+
*/
|
|
187
|
+
async killProcess(processId, signal = 'SIGTERM') {
|
|
188
|
+
const childProcess = this.runningProcesses.get(processId);
|
|
189
|
+
if (!childProcess) {
|
|
190
|
+
throw new Error(`Process ${processId} not found or already stopped`);
|
|
191
|
+
}
|
|
192
|
+
childProcess.kill(signal);
|
|
193
|
+
// Update process info
|
|
194
|
+
const info = this.processes.get(processId);
|
|
195
|
+
if (info) {
|
|
196
|
+
info.status = 'failed';
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Kill all running processes
|
|
201
|
+
*/
|
|
202
|
+
async killAllProcesses(signal = 'SIGTERM') {
|
|
203
|
+
const killPromises = Array.from(this.runningProcesses.keys()).map((processId) => this.killProcess(processId, signal).catch(() => {
|
|
204
|
+
// Ignore errors if process already stopped
|
|
205
|
+
}));
|
|
206
|
+
await Promise.all(killPromises);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Get sandbox status
|
|
210
|
+
*/
|
|
211
|
+
getStatus() {
|
|
212
|
+
return {
|
|
213
|
+
id: this.id,
|
|
214
|
+
workDir: this.workDir,
|
|
215
|
+
createdAt: this.createdAt,
|
|
216
|
+
uptime: Date.now() - this.createdAt,
|
|
217
|
+
processCount: this.runningProcesses.size,
|
|
218
|
+
totalProcesses: this.processes.size,
|
|
219
|
+
destroyed: this.destroyed,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
// ============================================================================
|
|
223
|
+
// Environment Variable Management
|
|
224
|
+
// ============================================================================
|
|
225
|
+
/**
|
|
226
|
+
* Set a single environment variable
|
|
227
|
+
*/
|
|
228
|
+
setEnv(key, value) {
|
|
229
|
+
if (this.destroyed) {
|
|
230
|
+
throw new Error('Sandbox has been destroyed');
|
|
231
|
+
}
|
|
232
|
+
this.config.env[key] = value;
|
|
233
|
+
this.emit('env_changed', { key, value, action: 'set' });
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Set multiple environment variables at once
|
|
237
|
+
*/
|
|
238
|
+
setEnvBatch(variables) {
|
|
239
|
+
if (this.destroyed) {
|
|
240
|
+
throw new Error('Sandbox has been destroyed');
|
|
241
|
+
}
|
|
242
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
243
|
+
this.config.env[key] = value;
|
|
244
|
+
}
|
|
245
|
+
this.emit('env_changed', { variables, action: 'batch_set' });
|
|
246
|
+
}
|
|
247
|
+
getEnv(key) {
|
|
248
|
+
if (key !== undefined) {
|
|
249
|
+
return this.config.env[key];
|
|
250
|
+
}
|
|
251
|
+
return { ...this.config.env };
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Get list of environment variable names (for security, not exposing values)
|
|
255
|
+
*/
|
|
256
|
+
getEnvKeys() {
|
|
257
|
+
return Object.keys(this.config.env);
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Unset (remove) an environment variable
|
|
261
|
+
*/
|
|
262
|
+
unsetEnv(key) {
|
|
263
|
+
if (this.destroyed) {
|
|
264
|
+
throw new Error('Sandbox has been destroyed');
|
|
265
|
+
}
|
|
266
|
+
if (key in this.config.env) {
|
|
267
|
+
delete this.config.env[key];
|
|
268
|
+
this.emit('env_changed', { key, action: 'unset' });
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Destroy the sandbox (kill all processes, optionally clean up files)
|
|
275
|
+
*/
|
|
276
|
+
async destroy(options = {}) {
|
|
277
|
+
if (this.destroyed) {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
// Kill all running processes
|
|
281
|
+
await this.killAllProcesses('SIGKILL');
|
|
282
|
+
// Clean up files if requested
|
|
283
|
+
if (options.cleanup) {
|
|
284
|
+
try {
|
|
285
|
+
await fs.rm(this.workDir, { recursive: true, force: true });
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
// Ignore cleanup errors
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
this.destroyed = true;
|
|
292
|
+
this.emit('destroyed', { id: this.id });
|
|
293
|
+
this.removeAllListeners();
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Parse a command string into command and arguments
|
|
297
|
+
*/
|
|
298
|
+
parseCommand(command) {
|
|
299
|
+
// Simple parsing - for more complex commands, shell: true handles it
|
|
300
|
+
return command.split(' ').filter(Boolean);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
//# sourceMappingURL=sandbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAgB,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC;AAmCpC;;;GAGG;AACH,MAAM,OAAO,OAAQ,SAAQ,YAAY;IACvB,EAAE,CAAS;IACX,OAAO,CAAS;IAChB,SAAS,CAAS;IAC1B,SAAS,GAA6B,IAAI,GAAG,EAAE,CAAC;IAChD,gBAAgB,GAA8B,IAAI,GAAG,EAAE,CAAC;IACxD,MAAM,CAAgB;IACtB,SAAS,GAAY,KAAK,CAAC;IAEnC,YAAY,SAAwB,EAAE;QACpC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,EAAE,IAAI,MAAM,EAAE,CAAC;QAChC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QACjF,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC;QACnD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU;QACd,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QAED,2BAA2B;QAC3B,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAElD,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IACnE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,OAAe,EAAE,UAAuB,EAAE;QACnD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,IAAI,QAAQ,GAAG,KAAK,CAAC;YAErB,yBAAyB;YACzB,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YAElD,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE;gBACpC,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,OAAO;gBAChC,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;gBAC3D,KAAK,EAAE,IAAI;aACZ,CAAC,CAAC;YAEH,iBAAiB;YACjB,IAAI,SAAqC,CAAC;YAC1C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;YACvD,IAAI,OAAO,EAAE,CAAC;gBACZ,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;oBAC1B,QAAQ,GAAG,IAAI,CAAC;oBAChB,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;oBAE7B,6BAA6B;oBAC7B,UAAU,CAAC,GAAG,EAAE;wBACd,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;4BACzB,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;wBAC/B,CAAC;oBACH,CAAC,EAAE,IAAI,CAAC,CAAC;gBACX,CAAC,EAAE,OAAO,CAAC,CAAC;YACd,CAAC;YAED,iBAAiB;YACjB,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;gBAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC7B,MAAM,IAAI,IAAI,CAAC;gBAEf,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;oBACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;gBACnC,CAAC;gBAED,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACxD,CAAC,CAAC,CAAC;YAEH,iBAAiB;YACjB,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;gBAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC7B,MAAM,IAAI,IAAI,CAAC;gBAEf,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;oBACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;gBACnC,CAAC;gBAED,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACxD,CAAC,CAAC,CAAC;YAEH,4BAA4B;YAC5B,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE;gBACpC,IAAI,SAAS,EAAE,CAAC;oBACd,YAAY,CAAC,SAAS,CAAC,CAAC;gBAC1B,CAAC;gBAED,MAAM,QAAQ,GAAoB;oBAChC,OAAO,EAAE,CAAC,QAAQ,IAAI,QAAQ,KAAK,CAAC;oBACpC,MAAM;oBACN,MAAM;oBACN,QAAQ,EAAE,QAAQ,IAAI,CAAC;oBACvB,QAAQ;iBACT,CAAC;gBAEF,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;gBACrC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACpB,CAAC,CAAC,CAAC;YAEH,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjC,IAAI,SAAS,EAAE,CAAC;oBACd,YAAY,CAAC,SAAS,CAAC,CAAC;gBAC1B,CAAC;gBAED,MAAM,QAAQ,GAAoB;oBAChC,OAAO,EAAE,KAAK;oBACd,MAAM;oBACN,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,KAAK,CAAC,OAAO;oBACrC,QAAQ,EAAE,CAAC;iBACZ,CAAC;gBAEF,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;gBAC/B,OAAO,CAAC,QAAQ,CAAC,CAAC;YACpB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY,CAAC,OAAe,EAAE,UAAuB,EAAE;QAC3D,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QAED,4BAA4B;QAC5B,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,IAAI,CAAC,gBAAgB,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YACvF,MAAM,IAAI,KAAK,CAAC,kCAAkC,IAAI,CAAC,MAAM,CAAC,YAAY,GAAG,CAAC,CAAC;QACjF,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAElD,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE;YACpC,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,OAAO;YAChC,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;YAC3D,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC;QAEH,MAAM,WAAW,GAAgB;YAC/B,EAAE,EAAE,SAAS;YACb,GAAG,EAAE,YAAY,CAAC,GAAI;YACtB,OAAO;YACP,MAAM,EAAE,SAAS;YACjB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC;QAEF,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAC3C,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QAEnD,oBAAoB;QACpB,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YAC/C,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE;gBAC1B,SAAS;gBACT,MAAM,EAAE,QAAQ;gBAChB,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE;aACtB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YAC/C,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE;gBAC1B,SAAS;gBACT,MAAM,EAAE,QAAQ;gBAChB,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE;aACtB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,sBAAsB;QACtB,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE;YACpC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAC3C,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,MAAM,GAAG,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC;gBACtD,IAAI,CAAC,QAAQ,GAAG,QAAQ,IAAI,CAAC,CAAC;YAChC,CAAC;YAED,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACxC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,WAAW,CAAC,CAAC;QAC1C,OAAO,WAAW,CAAC;IACrB,CAAC;IAED;;OAEG;IACH,aAAa;QACX,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,SAAiB;QAC1B,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CAAC,SAAiB,EAAE,SAAiB,SAAS;QAC7D,MAAM,YAAY,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC1D,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,WAAW,SAAS,+BAA+B,CAAC,CAAC;QACvE,CAAC;QAED,YAAY,CAAC,IAAI,CAAC,MAAwB,CAAC,CAAC;QAE5C,sBAAsB;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC3C,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC;QACzB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB,CAAC,SAAiB,SAAS;QAC/C,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAC9E,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YAC7C,2CAA2C;QAC7C,CAAC,CAAC,CACH,CAAC;QAEF,MAAM,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO;YACL,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS;YACnC,YAAY,EAAE,IAAI,CAAC,gBAAgB,CAAC,IAAI;YACxC,cAAc,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI;YACnC,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC;IACJ,CAAC;IAED,+EAA+E;IAC/E,kCAAkC;IAClC,+EAA+E;IAE/E;;OAEG;IACH,MAAM,CAAC,GAAW,EAAE,KAAa;QAC/B,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,GAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,SAAiC;QAC3C,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QACD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YACrD,IAAI,CAAC,MAAM,CAAC,GAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAChC,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;IAC/D,CAAC;IASD,MAAM,CAAC,GAAY;QACjB,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC,MAAM,CAAC,GAAI,CAAC,GAAG,CAAC,CAAC;QAC/B,CAAC;QACD,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,UAAU;QACR,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAI,CAAC,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,GAAW;QAClB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QACD,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,GAAI,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC,MAAM,CAAC,GAAI,CAAC,GAAG,CAAC,CAAC;YAC7B,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;YACnD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,UAAiC,EAAE;QAC/C,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,OAAO;QACT,CAAC;QAED,6BAA6B;QAC7B,MAAM,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;QAEvC,8BAA8B;QAC9B,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,IAAI,CAAC;gBACH,MAAM,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9D,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,wBAAwB;YAC1B,CAAC;QACH,CAAC;QAED,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QACxC,IAAI,CAAC,kBAAkB,EAAE,CAAC;IAC5B,CAAC;IAED;;OAEG;IACK,YAAY,CAAC,OAAe;QAClC,qEAAqE;QACrE,OAAO,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;CACF"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Server } from 'http';
|
|
2
|
+
export interface SandboxConfig {
|
|
3
|
+
port?: number;
|
|
4
|
+
projectRoot?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function startSandboxServer(config?: SandboxConfig): Promise<Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>>;
|
|
7
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAGnC,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,kBAAkB,CAAC,MAAM,GAAE,aAAkB,gGA4RlE"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { TerminalService } from "./terminal.js";
|
|
3
|
+
import { WebSocketTerminalService } from "./websocket.js";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
export async function startSandboxServer(config = {}) {
|
|
6
|
+
const { port = 3000, projectRoot = process.cwd() } = config;
|
|
7
|
+
// Change the current working directory to the project root
|
|
8
|
+
process.chdir(projectRoot);
|
|
9
|
+
const app = new Hono();
|
|
10
|
+
// Health check endpoint
|
|
11
|
+
app.get("/", (c) => {
|
|
12
|
+
return c.json({
|
|
13
|
+
status: "ok",
|
|
14
|
+
message: "Treesap Sandbox Server",
|
|
15
|
+
version: "0.1.0",
|
|
16
|
+
endpoints: {
|
|
17
|
+
terminal_sessions: "/api/terminal/sessions",
|
|
18
|
+
websocket: "ws://localhost:" + port + "/terminal/ws"
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
// List active terminal sessions with WebSocket client info
|
|
23
|
+
app.get("/api/terminal/sessions", (c) => {
|
|
24
|
+
const sessions = TerminalService.getAllSessions();
|
|
25
|
+
const wsActiveSessions = WebSocketTerminalService.getActiveSessions();
|
|
26
|
+
return c.json({
|
|
27
|
+
sessions: sessions.map(session => {
|
|
28
|
+
const wsInfo = wsActiveSessions.find(ws => ws.sessionId === session.id);
|
|
29
|
+
return {
|
|
30
|
+
id: session.id,
|
|
31
|
+
createdAt: session.createdAt,
|
|
32
|
+
lastActivity: session.lastActivity,
|
|
33
|
+
connectedClients: wsInfo ? wsInfo.clientCount : 0
|
|
34
|
+
};
|
|
35
|
+
}),
|
|
36
|
+
totalConnectedClients: WebSocketTerminalService.getConnectedClients()
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
// Get specific terminal session status
|
|
40
|
+
app.get("/api/terminal/sessions/:sessionId/status", (c) => {
|
|
41
|
+
const sessionId = c.req.param('sessionId');
|
|
42
|
+
const session = TerminalService.getSession(sessionId);
|
|
43
|
+
if (!session) {
|
|
44
|
+
return c.json({ error: "Session not found" }, 404);
|
|
45
|
+
}
|
|
46
|
+
const clients = WebSocketTerminalService.getSessionClients(sessionId);
|
|
47
|
+
return c.json({
|
|
48
|
+
id: session.id,
|
|
49
|
+
createdAt: session.createdAt,
|
|
50
|
+
lastActivity: session.lastActivity,
|
|
51
|
+
connectedClients: clients.length,
|
|
52
|
+
clientIds: clients
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
// Send command to terminal via API
|
|
56
|
+
app.post("/api/terminal/sessions/:sessionId/command", async (c) => {
|
|
57
|
+
const sessionId = c.req.param('sessionId');
|
|
58
|
+
const body = await c.req.json();
|
|
59
|
+
const { command } = body;
|
|
60
|
+
if (!command) {
|
|
61
|
+
return c.json({ error: "Command is required" }, 400);
|
|
62
|
+
}
|
|
63
|
+
// Get or create terminal session
|
|
64
|
+
let session = TerminalService.getSession(sessionId);
|
|
65
|
+
if (!session) {
|
|
66
|
+
session = TerminalService.createSession(sessionId);
|
|
67
|
+
}
|
|
68
|
+
const success = WebSocketTerminalService.sendCommandToSession(sessionId, command);
|
|
69
|
+
if (success) {
|
|
70
|
+
return c.json({
|
|
71
|
+
success: true,
|
|
72
|
+
message: `Command sent to session ${sessionId}`,
|
|
73
|
+
connectedClients: WebSocketTerminalService.getSessionClients(sessionId).length
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
return c.json({ error: "Failed to send command to terminal" }, 500);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
// Get recent output from terminal session (for API clients)
|
|
81
|
+
app.get("/api/terminal/sessions/:sessionId/output", async (c) => {
|
|
82
|
+
const sessionId = c.req.param('sessionId');
|
|
83
|
+
const session = TerminalService.getSession(sessionId);
|
|
84
|
+
if (!session) {
|
|
85
|
+
return c.json({ error: "Session not found" }, 404);
|
|
86
|
+
}
|
|
87
|
+
// Note: This is a basic implementation. For production, you'd want to
|
|
88
|
+
// store recent output history in the TerminalService
|
|
89
|
+
return c.json({
|
|
90
|
+
sessionId,
|
|
91
|
+
message: "Output streaming available via WebSocket connection",
|
|
92
|
+
connectedClients: WebSocketTerminalService.getSessionClients(sessionId).length,
|
|
93
|
+
websocketUrl: `ws://${c.req.header('host')}/terminal/ws`
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
// Terminal endpoints
|
|
97
|
+
app.post("/terminal/execute/:sessionId", async (c) => {
|
|
98
|
+
const sessionId = c.req.param('sessionId');
|
|
99
|
+
const body = await c.req.json();
|
|
100
|
+
const { command } = body;
|
|
101
|
+
if (!command) {
|
|
102
|
+
return c.json({ error: "Command is required" }, 400);
|
|
103
|
+
}
|
|
104
|
+
// Get or create terminal session
|
|
105
|
+
let session = TerminalService.getSession(sessionId);
|
|
106
|
+
if (!session) {
|
|
107
|
+
session = TerminalService.createSession(sessionId);
|
|
108
|
+
}
|
|
109
|
+
const success = TerminalService.executeCommand(sessionId, command);
|
|
110
|
+
if (success) {
|
|
111
|
+
return c.json({ success: true });
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
return c.json({ error: "Failed to execute command" }, 500);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
app.post("/terminal/input/:sessionId", async (c) => {
|
|
118
|
+
const sessionId = c.req.param('sessionId');
|
|
119
|
+
const body = await c.req.json();
|
|
120
|
+
const { input } = body;
|
|
121
|
+
if (input === undefined) {
|
|
122
|
+
return c.json({ error: "Input is required" }, 400);
|
|
123
|
+
}
|
|
124
|
+
// Get or create terminal session
|
|
125
|
+
let session = TerminalService.getSession(sessionId);
|
|
126
|
+
if (!session) {
|
|
127
|
+
session = TerminalService.createSession(sessionId);
|
|
128
|
+
}
|
|
129
|
+
// Send input directly to PTY
|
|
130
|
+
try {
|
|
131
|
+
session.lastActivity = new Date();
|
|
132
|
+
session.process.write(input);
|
|
133
|
+
return c.json({ success: true });
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
console.error(`Error sending input to session ${sessionId}:`, error);
|
|
137
|
+
return c.json({ error: "Failed to send input" }, 500);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
app.get("/terminal/stream/:sessionId", async (c) => {
|
|
141
|
+
const sessionId = c.req.param('sessionId');
|
|
142
|
+
// Get or create terminal session
|
|
143
|
+
let session = TerminalService.getSession(sessionId);
|
|
144
|
+
if (!session) {
|
|
145
|
+
session = TerminalService.createSession(sessionId);
|
|
146
|
+
}
|
|
147
|
+
// Set SSE headers
|
|
148
|
+
c.header('Content-Type', 'text/event-stream');
|
|
149
|
+
c.header('Cache-Control', 'no-cache');
|
|
150
|
+
c.header('Connection', 'keep-alive');
|
|
151
|
+
c.header('Access-Control-Allow-Origin', '*');
|
|
152
|
+
const stream = new ReadableStream({
|
|
153
|
+
start(controller) {
|
|
154
|
+
const encoder = new TextEncoder();
|
|
155
|
+
// Send initial connection event
|
|
156
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ type: 'connected' })}\n\n`));
|
|
157
|
+
// Set up output listener
|
|
158
|
+
const handleOutput = (data) => {
|
|
159
|
+
try {
|
|
160
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`));
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
console.error('Error sending terminal output:', error);
|
|
164
|
+
// Remove listener on error to prevent memory leaks
|
|
165
|
+
session.eventEmitter.removeListener('output', handleOutput);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
session.eventEmitter.on('output', handleOutput);
|
|
169
|
+
// Handle client disconnect
|
|
170
|
+
const handleDisconnect = () => {
|
|
171
|
+
try {
|
|
172
|
+
session.eventEmitter.removeListener('output', handleOutput);
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
console.error('Error removing output listener:', error);
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
// Clean up on stream close
|
|
179
|
+
return () => {
|
|
180
|
+
handleDisconnect();
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
return new Response(stream, {
|
|
185
|
+
headers: {
|
|
186
|
+
'Content-Type': 'text/event-stream',
|
|
187
|
+
'Cache-Control': 'no-cache',
|
|
188
|
+
'Connection': 'keep-alive',
|
|
189
|
+
'Access-Control-Allow-Origin': '*'
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
// Delete terminal session
|
|
194
|
+
app.delete("/terminal/session/:sessionId", async (c) => {
|
|
195
|
+
const sessionId = c.req.param('sessionId');
|
|
196
|
+
if (!sessionId) {
|
|
197
|
+
return c.json({ error: "Session ID is required" }, 400);
|
|
198
|
+
}
|
|
199
|
+
const success = TerminalService.destroySession(sessionId);
|
|
200
|
+
if (success) {
|
|
201
|
+
return c.json({ message: `Terminal session ${sessionId} destroyed successfully` });
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
console.log(`Terminal session not found: ${sessionId}`);
|
|
205
|
+
return c.json({ error: `Terminal session ${sessionId} not found` }, 404);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
const { serve } = await import('@hono/node-server');
|
|
209
|
+
// Start the server and initialize WebSocket
|
|
210
|
+
const server = serve({
|
|
211
|
+
fetch: app.fetch,
|
|
212
|
+
port,
|
|
213
|
+
});
|
|
214
|
+
// Initialize WebSocket service
|
|
215
|
+
WebSocketTerminalService.initialize(server);
|
|
216
|
+
// Setup global graceful shutdown
|
|
217
|
+
const setupGlobalShutdown = () => {
|
|
218
|
+
const cleanup = async () => {
|
|
219
|
+
console.log('\nš Shutting down sandbox server and all terminal sessions...');
|
|
220
|
+
// Clean up WebSocket connections
|
|
221
|
+
WebSocketTerminalService.cleanup();
|
|
222
|
+
process.exit(0);
|
|
223
|
+
};
|
|
224
|
+
// Handle Ctrl+C (SIGINT)
|
|
225
|
+
process.on('SIGINT', () => {
|
|
226
|
+
cleanup().catch(() => process.exit(1));
|
|
227
|
+
});
|
|
228
|
+
// Handle termination signal
|
|
229
|
+
process.on('SIGTERM', () => {
|
|
230
|
+
cleanup().catch(() => process.exit(1));
|
|
231
|
+
});
|
|
232
|
+
};
|
|
233
|
+
setupGlobalShutdown();
|
|
234
|
+
// Initialize terminal service cleanup
|
|
235
|
+
TerminalService.setupGlobalCleanup();
|
|
236
|
+
console.log(`\nš³ Treesap Sandbox Server running at http://localhost:${port}`);
|
|
237
|
+
console.log(`š WebSocket terminal server available at ws://localhost:${port}/terminal/ws\n`);
|
|
238
|
+
return server;
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Sandbox, ExecOptions } from './sandbox';
|
|
2
|
+
import { Readable } from 'stream';
|
|
3
|
+
export type ExecEventType = 'start' | 'stdout' | 'stderr' | 'complete' | 'error';
|
|
4
|
+
export interface ExecEvent {
|
|
5
|
+
type: ExecEventType;
|
|
6
|
+
data?: string;
|
|
7
|
+
exitCode?: number;
|
|
8
|
+
error?: string;
|
|
9
|
+
timestamp: number;
|
|
10
|
+
}
|
|
11
|
+
export interface LogEvent {
|
|
12
|
+
type: 'log';
|
|
13
|
+
data: string;
|
|
14
|
+
timestamp: number;
|
|
15
|
+
stream?: 'stdout' | 'stderr';
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Service for creating Server-Sent Events (SSE) streams
|
|
19
|
+
*/
|
|
20
|
+
export declare class StreamService {
|
|
21
|
+
/**
|
|
22
|
+
* Create an SSE stream for command execution
|
|
23
|
+
*/
|
|
24
|
+
static createExecStream(sandbox: Sandbox, command: string, options?: ExecOptions): Readable;
|
|
25
|
+
/**
|
|
26
|
+
* Create an SSE stream for process logs
|
|
27
|
+
*/
|
|
28
|
+
static createProcessLogStream(sandbox: Sandbox, processId: string): Readable;
|
|
29
|
+
/**
|
|
30
|
+
* Helper to parse SSE stream on client side
|
|
31
|
+
* This is exported for client library usage
|
|
32
|
+
*/
|
|
33
|
+
static parseSSEStream<T = ExecEvent | LogEvent>(stream: ReadableStream): AsyncGenerator<T>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=stream-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-service.d.ts","sourceRoot":"","sources":["../src/stream-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAElC,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;AAEjF,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,KAAK,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAC9B;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,QAAQ;IAqD/F;;OAEG;IACH,MAAM,CAAC,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ;IA8C5E;;;OAGG;WACW,cAAc,CAAC,CAAC,GAAG,SAAS,GAAG,QAAQ,EACnD,MAAM,EAAE,cAAc,GACrB,cAAc,CAAC,CAAC,CAAC;CAsCrB"}
|