Package Exports
- @shelltender/server
Readme
@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
npm install @shelltender/serverNote: This package has a peer dependency on express for HTTP server integration.
Quick Start
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.
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 sessiongetSession(sessionId)- Retrieve an existing sessionsendCommand(sessionId, command)- Send a command with newlinesendRawInput(sessionId, data)- Send raw input without modificationsendKey(sessionId, key)- Send special key sequencesresizeSession(sessionId, cols, rows)- Resize terminal dimensionskillSession(sessionId)- Terminate a sessiongetAllSessions()- Get all active sessions
Special Key Support
// 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.
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.
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.
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.
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 sessionAdvanced Usage
Creating a Restricted Demo Environment
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
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
// 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
// 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
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
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 for a complete working example of all features.
API Reference
For detailed API documentation of all classes and methods, see the TypeScript definitions or generate docs with:
npm run docsRelated Packages
- @shelltender/core - Shared types and interfaces
- @shelltender/client - React components for the frontend
- shelltender - All-in-one package
License
MIT