@shelltender/server
Version:
Server-side terminal session management for Shelltender
341 lines (263 loc) • 9.33 kB
Markdown
# @shelltender/server
Server-side terminal session management for Shelltender. This package provides robust backend components for creating and managing persistent web-based terminal sessions with features like session persistence, buffer management, and security restrictions.
## Installation
```bash
npm install @shelltender/server
```
Note: This package has a peer dependency on `express` for HTTP server integration.
## Quick Start
```typescript
import { SessionManager, WebSocketServer, BufferManager, SessionStore } from '@shelltender/server';
// Initialize components
const bufferManager = new BufferManager();
const sessionStore = new SessionStore();
const sessionManager = new SessionManager(bufferManager, sessionStore);
// Start WebSocket server
const wsServer = new WebSocketServer(8080, sessionManager, bufferManager);
// Create a session
const session = sessionManager.createSession({
command: '/bin/bash',
cwd: process.env.HOME,
cols: 80,
rows: 24
});
console.log(`Session created: ${session.id}`);
```
## Core Components
### SessionManager
The heart of the server package, managing terminal session lifecycles.
```typescript
const sessionManager = new SessionManager(bufferManager, sessionStore);
// Create a new session
const session = sessionManager.createSession({
command: '/bin/zsh',
args: ['--login'],
cwd: '/home/user',
env: { TERM: 'xterm-256color' },
cols: 120,
rows: 40
});
// Send commands
sessionManager.sendCommand(session.id, 'ls -la');
sessionManager.sendKey(session.id, 'ctrl-c');
sessionManager.sendRawInput(session.id, 'Hello World');
// Manage session
sessionManager.resizeSession(session.id, 80, 24);
sessionManager.killSession(session.id);
```
#### Key Methods
- `createSession(options)` - Create a new terminal session
- `getSession(sessionId)` - Retrieve an existing session
- `sendCommand(sessionId, command)` - Send a command with newline
- `sendRawInput(sessionId, data)` - Send raw input without modification
- `sendKey(sessionId, key)` - Send special key sequences
- `resizeSession(sessionId, cols, rows)` - Resize terminal dimensions
- `killSession(sessionId)` - Terminate a session
- `getAllSessions()` - Get all active sessions
#### Special Key Support
```typescript
// Supported special keys
sessionManager.sendKey(sessionId, 'ctrl-c'); // Interrupt
sessionManager.sendKey(sessionId, 'ctrl-d'); // EOF
sessionManager.sendKey(sessionId, 'ctrl-z'); // Suspend
sessionManager.sendKey(sessionId, 'ctrl-l'); // Clear
sessionManager.sendKey(sessionId, 'ctrl-r'); // Reverse search
sessionManager.sendKey(sessionId, 'ctrl-a'); // Beginning of line
sessionManager.sendKey(sessionId, 'ctrl-e'); // End of line
sessionManager.sendKey(sessionId, 'tab'); // Tab completion
sessionManager.sendKey(sessionId, 'escape'); // Escape
sessionManager.sendKey(sessionId, 'up'); // Arrow keys
sessionManager.sendKey(sessionId, 'down');
sessionManager.sendKey(sessionId, 'left');
sessionManager.sendKey(sessionId, 'right');
```
### BufferManager
Maintains scrollback buffers for session history.
```typescript
const bufferManager = new BufferManager(100000); // 100KB max per session
// Buffer is automatically managed by SessionManager
// Direct access for advanced use cases:
const buffer = bufferManager.getBuffer(sessionId);
bufferManager.clearBuffer(sessionId);
```
#### Configuration
- `maxBufferSize` - Maximum characters per session (default: 100,000)
### SessionStore
Provides disk persistence for sessions.
```typescript
const sessionStore = new SessionStore('.sessions'); // Custom path
// Sessions are automatically persisted by SessionManager
// Direct access for advanced use cases:
await sessionStore.saveSession(sessionId, session, buffer);
const restored = await sessionStore.loadSession(sessionId);
const allSessions = await sessionStore.loadAllSessions();
```
#### Features
- Automatic session persistence on state changes
- Session restoration on server restart
- Buffer updates saved incrementally
- JSON-based storage format
### RestrictedShell
Create sandboxed terminal sessions with security restrictions.
```typescript
const session = sessionManager.createSession({
// Filesystem restrictions
restrictToPath: '/home/demo/sandbox',
allowUpwardNavigation: false,
// Command restrictions
blockedCommands: ['rm', 'dd', 'mkfs', 'sudo'],
// Read-only mode
readOnlyMode: true,
// Custom prompt
env: {
PS1: 'sandbox> '
}
});
```
#### Security Features
- **Path Restriction** - Confine session to specific directory
- **Command Blocking** - Prevent dangerous commands
- **Read-Only Mode** - Block all write operations
- **Navigation Control** - Prevent upward directory traversal
### WebSocketServer
Handles real-time communication with web clients.
```typescript
const wsServer = new WebSocketServer(8080, sessionManager, bufferManager);
// Server handles these message types automatically:
// - create: Create new session
// - connect: Connect to existing session
// - input: Send terminal input
// - resize: Resize terminal
// - disconnect: Disconnect from session
```
#### Features
- **Multi-Session Support**: Single WebSocket connection can subscribe to multiple terminal sessions
- **Incremental Updates**: Efficient data transmission with sequence tracking
- **Automatic Reconnection**: Clients can resume from where they left off
- **Event Subscriptions**: Pattern matching and terminal event notifications
## Advanced Usage
### Creating a Restricted Demo Environment
```typescript
const demoSession = sessionManager.createSession({
restrictToPath: '/opt/demo',
blockedCommands: ['rm', 'mv', 'cp', 'dd', 'sudo', 'su'],
readOnlyMode: false,
allowUpwardNavigation: false,
env: {
PS1: '\\u@demo:\\w$ ',
TERM: 'xterm-256color'
},
cwd: '/opt/demo',
locked: true // Prevent further modifications
});
```
### Monitoring Session Events
```typescript
sessionManager.on('sessionCreated', (session) => {
console.log(`New session: ${session.id}`);
});
sessionManager.on('sessionOutput', (sessionId, data) => {
// Process output (e.g., detect patterns)
if (data.includes('ERROR')) {
console.log(`Error detected in session ${sessionId}`);
}
});
sessionManager.on('sessionExit', (sessionId, exitCode) => {
console.log(`Session ${sessionId} exited with code ${exitCode}`);
});
```
### Custom Session Commands
```typescript
// Run a specific command instead of a shell
const pythonRepl = sessionManager.createSession({
command: '/usr/bin/python3',
args: ['-i'],
env: {
PYTHONUNBUFFERED: '1'
}
});
// Run a Node.js REPL
const nodeRepl = sessionManager.createSession({
command: 'node',
args: ['--interactive']
});
```
### Session Persistence and Recovery
```typescript
// Load previously saved sessions on startup
async function restoreSessions() {
const savedSessions = await sessionStore.loadAllSessions();
for (const [sessionId, data] of savedSessions) {
// Recreate session with saved state
const session = sessionManager.createSession({
...data.session,
// Restore to saved directory
cwd: data.cwd || data.session.cwd
});
// Restore buffer content
bufferManager.addToBuffer(session.id, data.buffer);
}
}
// Clean up old sessions
await sessionStore.deleteAllSessions();
```
## Integration with Express
```typescript
import express from 'express';
import { createServer } from 'http';
const app = express();
const server = createServer(app);
// Serve terminal UI
app.use(express.static('public'));
// REST endpoints for session management
app.get('/api/sessions', (req, res) => {
res.json(sessionManager.getAllSessions());
});
app.post('/api/sessions', (req, res) => {
const session = sessionManager.createSession(req.body);
res.json(session);
});
app.delete('/api/sessions/:id', (req, res) => {
sessionManager.killSession(req.params.id);
res.sendStatus(204);
});
server.listen(3000);
```
## Best Practices
### Security
- Always use HTTPS/WSS in production
- Implement authentication before session creation
- Use RestrictedShell for untrusted users
- Set resource limits (CPU, memory) for PTY processes
- Validate and sanitize all user inputs
### Performance
- Set appropriate buffer sizes based on expected usage
- Implement session timeouts for idle connections
- Monitor system resources and set session limits
- Use session persistence selectively for important sessions
### Error Handling
```typescript
try {
const session = sessionManager.createSession(options);
} catch (error) {
console.error('Failed to create session:', error);
// Handle error appropriately
}
// Monitor for session errors
sessionManager.on('sessionError', (sessionId, error) => {
console.error(`Session ${sessionId} error:`, error);
});
```
## Examples
See the [demo app](../../apps/demo) for a complete working example of all features.
## API Reference
For detailed API documentation of all classes and methods, see the [TypeScript definitions](./dist/index.d.ts) or generate docs with:
```bash
npm run docs
```
## Related Packages
- [@shelltender/core](../core) - Shared types and interfaces
- [@shelltender/client](../client) - React components for the frontend
- [shelltender](../shelltender) - All-in-one package
## License
MIT