@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.
Files changed (66) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/README.md +495 -0
  3. package/dist/api-server.d.ts +41 -0
  4. package/dist/api-server.d.ts.map +1 -0
  5. package/dist/api-server.js +536 -0
  6. package/dist/api-server.js.map +1 -0
  7. package/dist/auth-middleware.d.ts +31 -0
  8. package/dist/auth-middleware.d.ts.map +1 -0
  9. package/dist/auth-middleware.js +35 -0
  10. package/dist/auth-middleware.js.map +1 -0
  11. package/dist/cli.d.ts +3 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +65 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/client.d.ts +137 -0
  16. package/dist/client.d.ts.map +1 -0
  17. package/dist/client.js +412 -0
  18. package/dist/client.js.map +1 -0
  19. package/dist/file-service.d.ts +94 -0
  20. package/dist/file-service.d.ts.map +1 -0
  21. package/dist/file-service.js +203 -0
  22. package/dist/file-service.js.map +1 -0
  23. package/dist/http-exposure-service.d.ts +71 -0
  24. package/dist/http-exposure-service.d.ts.map +1 -0
  25. package/dist/http-exposure-service.js +172 -0
  26. package/dist/http-exposure-service.js.map +1 -0
  27. package/dist/index.d.ts +59 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +66 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/sandbox-manager.d.ts +76 -0
  32. package/dist/sandbox-manager.d.ts.map +1 -0
  33. package/dist/sandbox-manager.js +161 -0
  34. package/dist/sandbox-manager.js.map +1 -0
  35. package/dist/sandbox.d.ts +118 -0
  36. package/dist/sandbox.d.ts.map +1 -0
  37. package/dist/sandbox.js +303 -0
  38. package/dist/sandbox.js.map +1 -0
  39. package/dist/server.d.ts +7 -0
  40. package/dist/server.d.ts.map +1 -0
  41. package/dist/server.js +240 -0
  42. package/dist/server.js.map +1 -0
  43. package/dist/stream-service.d.ts +35 -0
  44. package/dist/stream-service.d.ts.map +1 -0
  45. package/dist/stream-service.js +136 -0
  46. package/dist/stream-service.js.map +1 -0
  47. package/dist/terminal.d.ts +46 -0
  48. package/dist/terminal.d.ts.map +1 -0
  49. package/dist/terminal.js +264 -0
  50. package/dist/terminal.js.map +1 -0
  51. package/dist/websocket.d.ts +48 -0
  52. package/dist/websocket.d.ts.map +1 -0
  53. package/dist/websocket.js +332 -0
  54. package/dist/websocket.js.map +1 -0
  55. package/package.json +59 -0
  56. package/src/api-server.ts +658 -0
  57. package/src/auth-middleware.ts +65 -0
  58. package/src/cli.ts +71 -0
  59. package/src/client.ts +537 -0
  60. package/src/file-service.ts +273 -0
  61. package/src/http-exposure-service.ts +232 -0
  62. package/src/index.ts +101 -0
  63. package/src/sandbox-manager.ts +202 -0
  64. package/src/sandbox.ts +396 -0
  65. package/src/stream-service.ts +174 -0
  66. package/tsconfig.json +37 -0
@@ -0,0 +1,136 @@
1
+ import { Readable } from 'stream';
2
+ /**
3
+ * Service for creating Server-Sent Events (SSE) streams
4
+ */
5
+ export class StreamService {
6
+ /**
7
+ * Create an SSE stream for command execution
8
+ */
9
+ static createExecStream(sandbox, command, options = {}) {
10
+ const stream = new Readable({
11
+ read() { },
12
+ });
13
+ const sendEvent = (event) => {
14
+ const data = JSON.stringify(event);
15
+ stream.push(`data: ${data}\n\n`);
16
+ };
17
+ // Send start event
18
+ sendEvent({
19
+ type: 'start',
20
+ timestamp: Date.now(),
21
+ });
22
+ // Execute command with streaming
23
+ sandbox
24
+ .exec(command, {
25
+ ...options,
26
+ stream: true,
27
+ onOutput: (outputStream, data) => {
28
+ sendEvent({
29
+ type: outputStream,
30
+ data,
31
+ timestamp: Date.now(),
32
+ });
33
+ },
34
+ })
35
+ .then((result) => {
36
+ // Send complete event
37
+ sendEvent({
38
+ type: 'complete',
39
+ exitCode: result.exitCode,
40
+ timestamp: Date.now(),
41
+ });
42
+ stream.push(null); // End stream
43
+ })
44
+ .catch((error) => {
45
+ // Send error event
46
+ sendEvent({
47
+ type: 'error',
48
+ error: error.message,
49
+ timestamp: Date.now(),
50
+ });
51
+ stream.push(null); // End stream
52
+ });
53
+ return stream;
54
+ }
55
+ /**
56
+ * Create an SSE stream for process logs
57
+ */
58
+ static createProcessLogStream(sandbox, processId) {
59
+ const stream = new Readable({
60
+ read() { },
61
+ });
62
+ const sendEvent = (event) => {
63
+ const data = JSON.stringify(event);
64
+ stream.push(`data: ${data}\n\n`);
65
+ };
66
+ // Listen for process output
67
+ const outputListener = (data) => {
68
+ if (data.processId === processId) {
69
+ sendEvent({
70
+ type: 'log',
71
+ data: data.data,
72
+ stream: data.stream,
73
+ timestamp: Date.now(),
74
+ });
75
+ }
76
+ };
77
+ const exitListener = (data) => {
78
+ if (data.processId === processId) {
79
+ // End stream when process exits
80
+ stream.push(null);
81
+ cleanup();
82
+ }
83
+ };
84
+ // Attach listeners
85
+ sandbox.on('process_output', outputListener);
86
+ sandbox.on('process_exit', exitListener);
87
+ // Cleanup function
88
+ const cleanup = () => {
89
+ sandbox.off('process_output', outputListener);
90
+ sandbox.off('process_exit', exitListener);
91
+ };
92
+ // Cleanup on stream close
93
+ stream.on('close', cleanup);
94
+ return stream;
95
+ }
96
+ /**
97
+ * Helper to parse SSE stream on client side
98
+ * This is exported for client library usage
99
+ */
100
+ static async *parseSSEStream(stream) {
101
+ const reader = stream.getReader();
102
+ const decoder = new TextDecoder();
103
+ let buffer = '';
104
+ try {
105
+ while (true) {
106
+ const { done, value } = await reader.read();
107
+ if (done) {
108
+ break;
109
+ }
110
+ buffer += decoder.decode(value, { stream: true });
111
+ // Split by double newline (SSE event delimiter)
112
+ const events = buffer.split('\n\n');
113
+ buffer = events.pop() || '';
114
+ for (const event of events) {
115
+ if (event.trim()) {
116
+ // Parse SSE format (data: {json})
117
+ const match = event.match(/^data: (.+)$/m);
118
+ if (match) {
119
+ try {
120
+ const data = JSON.parse(match[1]);
121
+ yield data;
122
+ }
123
+ catch {
124
+ // Ignore parse errors
125
+ }
126
+ }
127
+ }
128
+ }
129
+ }
130
+ }
131
+ finally {
132
+ reader.releaseLock();
133
+ }
134
+ }
135
+ }
136
+ //# sourceMappingURL=stream-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-service.js","sourceRoot":"","sources":["../src/stream-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { EventEmitter } from 'events';
2
+ import * as pty from 'node-pty';
3
+ export interface TerminalSession {
4
+ id: string;
5
+ process: pty.IPty;
6
+ eventEmitter: EventEmitter;
7
+ createdAt: Date;
8
+ lastActivity: Date;
9
+ cwd?: string;
10
+ env?: Record<string, string>;
11
+ cols?: number;
12
+ rows?: number;
13
+ }
14
+ export interface PersistedSessionData {
15
+ id: string;
16
+ createdAt: string;
17
+ lastActivity: string;
18
+ cwd: string;
19
+ env: Record<string, string>;
20
+ cols: number;
21
+ rows: number;
22
+ }
23
+ export declare class TerminalService {
24
+ private static sessions;
25
+ private static readonly SESSION_TIMEOUT;
26
+ private static readonly PERSISTENCE_DIR;
27
+ private static readonly SESSIONS_FILE;
28
+ static createSession(sessionId: string, options?: {
29
+ cwd?: string;
30
+ cols?: number;
31
+ rows?: number;
32
+ }): TerminalSession;
33
+ static getSession(sessionId: string): TerminalSession | undefined;
34
+ static executeCommand(sessionId: string, command: string): boolean;
35
+ static destroySession(sessionId: string): boolean;
36
+ static getAllSessions(): TerminalSession[];
37
+ static cleanupExpiredSessions(): number;
38
+ private static scheduleSessionCleanup;
39
+ static setupGlobalCleanup(): void;
40
+ private static ensurePersistenceDir;
41
+ private static persistSessionData;
42
+ private static removePersistedSession;
43
+ private static loadPersistedSessions;
44
+ static updateSessionActivity(sessionId: string): void;
45
+ }
46
+ //# sourceMappingURL=terminal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../src/terminal.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAKhC,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC;IAClB,YAAY,EAAE,YAAY,CAAC;IAC3B,SAAS,EAAE,IAAI,CAAC;IAChB,YAAY,EAAE,IAAI,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAsC;IAC7D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAkB;IACzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAwD;IAC/F,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAoD;IAEzF,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,eAAe;IAsElH,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAIjE,MAAM,CAAC,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAgBlE,MAAM,CAAC,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IA0BjD,MAAM,CAAC,cAAc,IAAI,eAAe,EAAE;IAI1C,MAAM,CAAC,sBAAsB,IAAI,MAAM;IAgBvC,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAgBrC,MAAM,CAAC,kBAAkB,IAAI,IAAI;IA0BjC,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAUnC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IA0CjC,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAgBrC,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAoCpC,MAAM,CAAC,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAOtD"}
@@ -0,0 +1,264 @@
1
+ import { EventEmitter } from 'events';
2
+ import * as pty from 'node-pty';
3
+ import * as fs from 'node:fs';
4
+ import * as path from 'node:path';
5
+ import * as os from 'node:os';
6
+ export class TerminalService {
7
+ static sessions = new Map();
8
+ static SESSION_TIMEOUT = 30 * 60 * 1000; // 30 minutes
9
+ static PERSISTENCE_DIR = path.join(os.tmpdir(), '.treesap-sandbox-terminals');
10
+ static SESSIONS_FILE = path.join(this.PERSISTENCE_DIR, 'sessions.json');
11
+ static createSession(sessionId, options) {
12
+ // Clean up any existing session with the same ID
13
+ this.destroySession(sessionId);
14
+ const eventEmitter = new EventEmitter();
15
+ // Increase max listeners to handle multiple terminal tabs and connections
16
+ eventEmitter.setMaxListeners(20);
17
+ // Use provided options or defaults
18
+ const cwd = options?.cwd || process.cwd();
19
+ const cols = options?.cols || 80;
20
+ const rows = options?.rows || 24;
21
+ const env = {};
22
+ // Filter out undefined values from process.env
23
+ for (const [key, value] of Object.entries(process.env)) {
24
+ if (value !== undefined) {
25
+ env[key] = value;
26
+ }
27
+ }
28
+ // Create a PTY process for proper terminal behavior
29
+ const ptyProcess = pty.spawn(process.platform === 'win32' ? 'cmd.exe' : process.env.SHELL || '/bin/bash', [], {
30
+ name: 'xterm-256color',
31
+ cols,
32
+ rows,
33
+ cwd,
34
+ env
35
+ });
36
+ const session = {
37
+ id: sessionId,
38
+ process: ptyProcess,
39
+ eventEmitter,
40
+ createdAt: new Date(),
41
+ lastActivity: new Date(),
42
+ cwd,
43
+ env,
44
+ cols,
45
+ rows
46
+ };
47
+ // Handle process output
48
+ ptyProcess.onData((data) => {
49
+ session.lastActivity = new Date();
50
+ eventEmitter.emit('output', {
51
+ type: 'output',
52
+ content: data
53
+ });
54
+ });
55
+ ptyProcess.onExit((e) => {
56
+ eventEmitter.emit('output', {
57
+ type: 'exit',
58
+ code: e.exitCode
59
+ });
60
+ this.destroySession(sessionId);
61
+ });
62
+ this.sessions.set(sessionId, session);
63
+ // Set up session cleanup
64
+ this.scheduleSessionCleanup(sessionId);
65
+ // Persist session data
66
+ this.persistSessionData(session);
67
+ return session;
68
+ }
69
+ static getSession(sessionId) {
70
+ return this.sessions.get(sessionId);
71
+ }
72
+ static executeCommand(sessionId, command) {
73
+ const session = this.getSession(sessionId);
74
+ if (!session) {
75
+ return false;
76
+ }
77
+ try {
78
+ session.lastActivity = new Date();
79
+ session.process.write(command + '\n');
80
+ return true;
81
+ }
82
+ catch (error) {
83
+ console.error(`Error executing command in session ${sessionId}:`, error);
84
+ return false;
85
+ }
86
+ }
87
+ static destroySession(sessionId) {
88
+ const session = this.sessions.get(sessionId);
89
+ if (!session) {
90
+ return false;
91
+ }
92
+ try {
93
+ // Clean up the PTY process
94
+ session.process.kill();
95
+ // Remove event listeners
96
+ session.eventEmitter.removeAllListeners();
97
+ // Remove from sessions map
98
+ this.sessions.delete(sessionId);
99
+ // Remove from persistent storage
100
+ this.removePersistedSession(sessionId);
101
+ return true;
102
+ }
103
+ catch (error) {
104
+ console.error(`Error destroying session ${sessionId}:`, error);
105
+ return false;
106
+ }
107
+ }
108
+ static getAllSessions() {
109
+ return Array.from(this.sessions.values());
110
+ }
111
+ static cleanupExpiredSessions() {
112
+ const now = new Date();
113
+ let cleanedCount = 0;
114
+ for (const [sessionId, session] of this.sessions.entries()) {
115
+ const timeSinceLastActivity = now.getTime() - session.lastActivity.getTime();
116
+ if (timeSinceLastActivity > this.SESSION_TIMEOUT) {
117
+ this.destroySession(sessionId);
118
+ cleanedCount++;
119
+ }
120
+ }
121
+ return cleanedCount;
122
+ }
123
+ static scheduleSessionCleanup(sessionId) {
124
+ setTimeout(() => {
125
+ const session = this.getSession(sessionId);
126
+ if (session) {
127
+ const timeSinceLastActivity = new Date().getTime() - session.lastActivity.getTime();
128
+ if (timeSinceLastActivity >= this.SESSION_TIMEOUT) {
129
+ console.log(`Cleaning up expired terminal session: ${sessionId}`);
130
+ this.destroySession(sessionId);
131
+ }
132
+ else {
133
+ // Reschedule cleanup
134
+ this.scheduleSessionCleanup(sessionId);
135
+ }
136
+ }
137
+ }, this.SESSION_TIMEOUT);
138
+ }
139
+ static setupGlobalCleanup() {
140
+ // Load persisted sessions on startup
141
+ this.loadPersistedSessions();
142
+ // Cleanup all sessions on process exit
143
+ const cleanup = () => {
144
+ console.log('Cleaning up all terminal sessions...');
145
+ for (const sessionId of this.sessions.keys()) {
146
+ this.destroySession(sessionId);
147
+ }
148
+ };
149
+ process.on('SIGINT', cleanup);
150
+ process.on('SIGTERM', cleanup);
151
+ process.on('exit', cleanup);
152
+ // Periodic cleanup of expired sessions
153
+ setInterval(() => {
154
+ const cleaned = this.cleanupExpiredSessions();
155
+ if (cleaned > 0) {
156
+ console.log(`Cleaned up ${cleaned} expired terminal sessions`);
157
+ }
158
+ }, 5 * 60 * 1000); // Every 5 minutes
159
+ }
160
+ // Persistence methods
161
+ static ensurePersistenceDir() {
162
+ try {
163
+ if (!fs.existsSync(this.PERSISTENCE_DIR)) {
164
+ fs.mkdirSync(this.PERSISTENCE_DIR, { recursive: true });
165
+ }
166
+ }
167
+ catch (error) {
168
+ console.error('Error creating persistence directory:', error);
169
+ }
170
+ }
171
+ static persistSessionData(session) {
172
+ try {
173
+ this.ensurePersistenceDir();
174
+ const sessionData = {
175
+ id: session.id,
176
+ createdAt: session.createdAt.toISOString(),
177
+ lastActivity: session.lastActivity.toISOString(),
178
+ cwd: session.cwd || process.cwd(),
179
+ env: session.env || (() => {
180
+ const env = {};
181
+ for (const [key, value] of Object.entries(process.env)) {
182
+ if (value !== undefined) {
183
+ env[key] = value;
184
+ }
185
+ }
186
+ return env;
187
+ })(),
188
+ cols: session.cols || 80,
189
+ rows: session.rows || 24
190
+ };
191
+ let existingData = [];
192
+ if (fs.existsSync(this.SESSIONS_FILE)) {
193
+ const content = fs.readFileSync(this.SESSIONS_FILE, 'utf8');
194
+ if (content.trim()) {
195
+ existingData = JSON.parse(content);
196
+ }
197
+ }
198
+ // Remove existing session data if present
199
+ existingData = existingData.filter(s => s.id !== session.id);
200
+ // Add new session data
201
+ existingData.push(sessionData);
202
+ fs.writeFileSync(this.SESSIONS_FILE, JSON.stringify(existingData, null, 2));
203
+ }
204
+ catch (error) {
205
+ console.error('Error persisting session data:', error);
206
+ }
207
+ }
208
+ static removePersistedSession(sessionId) {
209
+ try {
210
+ if (!fs.existsSync(this.SESSIONS_FILE))
211
+ return;
212
+ const content = fs.readFileSync(this.SESSIONS_FILE, 'utf8');
213
+ if (!content.trim())
214
+ return;
215
+ let existingData = JSON.parse(content);
216
+ existingData = existingData.filter(s => s.id !== sessionId);
217
+ fs.writeFileSync(this.SESSIONS_FILE, JSON.stringify(existingData, null, 2));
218
+ }
219
+ catch (error) {
220
+ console.error('Error removing persisted session:', error);
221
+ }
222
+ }
223
+ static loadPersistedSessions() {
224
+ try {
225
+ if (!fs.existsSync(this.SESSIONS_FILE))
226
+ return;
227
+ const content = fs.readFileSync(this.SESSIONS_FILE, 'utf8');
228
+ if (!content.trim())
229
+ return;
230
+ const persistedSessions = JSON.parse(content);
231
+ console.log(`Found ${persistedSessions.length} persisted terminal session(s)`);
232
+ for (const sessionData of persistedSessions) {
233
+ // Check if session is not too old
234
+ const lastActivity = new Date(sessionData.lastActivity);
235
+ const timeSinceLastActivity = Date.now() - lastActivity.getTime();
236
+ if (timeSinceLastActivity < this.SESSION_TIMEOUT) {
237
+ console.log(`Restoring terminal session: ${sessionData.id}`);
238
+ // Create new session with the persisted options
239
+ this.createSession(sessionData.id, {
240
+ cwd: sessionData.cwd,
241
+ cols: sessionData.cols,
242
+ rows: sessionData.rows
243
+ });
244
+ }
245
+ else {
246
+ console.log(`Skipping expired session: ${sessionData.id}`);
247
+ this.removePersistedSession(sessionData.id);
248
+ }
249
+ }
250
+ }
251
+ catch (error) {
252
+ console.error('Error loading persisted sessions:', error);
253
+ }
254
+ }
255
+ // Update session activity and persist
256
+ static updateSessionActivity(sessionId) {
257
+ const session = this.getSession(sessionId);
258
+ if (session) {
259
+ session.lastActivity = new Date();
260
+ this.persistSessionData(session);
261
+ }
262
+ }
263
+ }
264
+ //# sourceMappingURL=terminal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.js","sourceRoot":"","sources":["../src/terminal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import { WebSocket } from 'ws';
2
+ import type { Server } from 'http';
3
+ export interface WebSocketClient {
4
+ id: string;
5
+ ws: WebSocket;
6
+ sessionId?: string;
7
+ terminalId?: string;
8
+ lastPing: Date;
9
+ }
10
+ export interface WebSocketMessage {
11
+ type: 'join' | 'leave' | 'input' | 'resize' | 'ping' | 'pong';
12
+ sessionId?: string;
13
+ terminalId?: string;
14
+ data?: string;
15
+ cols?: number;
16
+ rows?: number;
17
+ timestamp?: number;
18
+ }
19
+ export declare class WebSocketTerminalService {
20
+ private static wss;
21
+ private static clients;
22
+ private static sessionClients;
23
+ static initialize(server: Server): void;
24
+ private static setupPingPong;
25
+ private static handleMessage;
26
+ private static handleJoin;
27
+ private static handleLeave;
28
+ private static handleInput;
29
+ private static handleResize;
30
+ private static handleDisconnect;
31
+ private static addClientToSession;
32
+ private static removeClientFromSession;
33
+ private static setupSessionOutputListener;
34
+ private static cleanupSessionOutputListener;
35
+ private static broadcastToSession;
36
+ private static broadcastClientCount;
37
+ private static sendToClient;
38
+ static getSessionClients(sessionId: string): string[];
39
+ static sendCommandToSession(sessionId: string, command: string): boolean;
40
+ static getActiveSessions(): Array<{
41
+ sessionId: string;
42
+ clientCount: number;
43
+ }>;
44
+ static getConnectedClients(): number;
45
+ static closeSession(sessionId: string): void;
46
+ static cleanup(): void;
47
+ }
48
+ //# sourceMappingURL=websocket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../src/websocket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,SAAS,EAAE,MAAM,IAAI,CAAC;AAKhD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,SAAS,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,IAAI,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,wBAAwB;IACnC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAgC;IAClD,OAAO,CAAC,MAAM,CAAC,OAAO,CAAsC;IAC5D,OAAO,CAAC,MAAM,CAAC,cAAc,CAAkC;IAE/D,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM;IA8ChC,OAAO,CAAC,MAAM,CAAC,aAAa;IAsB5B,OAAO,CAAC,MAAM,CAAC,aAAa;IAqC5B,OAAO,CAAC,MAAM,CAAC,UAAU;IAuCzB,OAAO,CAAC,MAAM,CAAC,WAAW;IAe1B,OAAO,CAAC,MAAM,CAAC,WAAW;IA8B1B,OAAO,CAAC,MAAM,CAAC,YAAY;IA0B3B,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAY/B,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAOjC,OAAO,CAAC,MAAM,CAAC,uBAAuB;IAYtC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAiBzC,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAQ3C,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAcjC,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAenC,OAAO,CAAC,MAAM,CAAC,YAAY;IAe3B,MAAM,CAAC,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE;IAKrD,MAAM,CAAC,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAaxE,MAAM,CAAC,iBAAiB,IAAI,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAO7E,MAAM,CAAC,mBAAmB,IAAI,MAAM;IAIpC,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM;IAoBrC,MAAM,CAAC,OAAO;CAUf"}