vibetunnel/docs/API.md
Peter Steinberger a9fd66c291 refactor: major project restructuring - move macOS app to mac/ directory
- Move all macOS-specific code from root to mac/ directory
- Move app icons and assets to dedicated assets/ directory
- Update GitHub workflows for new structure
- Consolidate documentation files
- Clean up root directory for better multi-platform organization
2025-06-20 13:20:01 +02:00

16 KiB
Raw Blame History

VibeTunnel API Analysis

Summary

This document analyzes the API endpoints implemented across all VibeTunnel servers, what the web client expects, and identifies critical differences, implementation errors, and semantic inconsistencies. The analysis covers:

  1. Node.js/TypeScript Server (web/src/server.ts) - Complete
  2. Rust API Server (tty-fwd/src/api_server.rs) - Complete
  3. Go Server (linux/pkg/api/server.go) - Complete
  4. Swift Server (VibeTunnel/Core/Services/TunnelServer.swift) - Complete
  5. Web Client (web/src/client/) - Expected API calls and formats

Note: Rust HTTP Server (tty-fwd/src/http_server.rs) is excluded as it's a utility component for static file serving, not a standalone API server.

API Endpoint Comparison

Endpoint Client Expects Node.js Rust API Go Swift Status
GET /api/health Used Complete
GET /api/sessions Critical Complete
POST /api/sessions Critical Complete
DELETE /api/sessions/:id Critical Complete
DELETE /api/sessions/:id/cleanup Not used Complete
GET /api/sessions/:id/stream Critical SSE Complete
GET /api/sessions/:id/snapshot Critical Complete
POST /api/sessions/:id/input Critical Complete
POST /api/sessions/:id/resize Critical ⚠️ Missing in Rust API & Swift
POST /api/cleanup-exited Used Complete
GET /api/fs/browse Critical Complete
POST /api/mkdir Used Complete
GET /api/sessions/multistream Not used Complete
GET /api/pty/status Not used Node.js Only
GET /api/test-cast Not used Node.js Only
POST /api/ngrok/start Not used Go/Swift Only
POST /api/ngrok/stop Not used Go/Swift Only
GET /api/ngrok/status Not used Go/Swift Only

Web Client API Requirements

Based on analysis of web/src/client/, the client requires these endpoints to function:

Critical Endpoints (App breaks without these):

  1. GET /api/sessions - Session list (polled every 3s)
  2. POST /api/sessions - Session creation
  3. DELETE /api/sessions/:id - Session termination
  4. GET /api/sessions/:id/stream - SSE streaming (real-time terminal output)
  5. GET /api/sessions/:id/snapshot - Terminal snapshot for initial display
  6. POST /api/sessions/:id/input - Keyboard/mouse input to terminal
  7. POST /api/sessions/:id/resize - Terminal resize (debounced, 250ms)
  8. GET /api/fs/browse - Directory browsing for session creation
  9. POST /api/cleanup-exited - Cleanup exited sessions

Expected Request/Response Formats by Client:

Session List Response (GET /api/sessions):

Session[] = {
  id: string;
  command: string;
  workingDir: string;
  name?: string;
  status: 'running' | 'exited';
  exitCode?: number;
  startedAt: string;
  lastModified: string;
  pid?: number;
  waiting?: boolean;  // Node.js only
  width?: number;     // Go only  
  height?: number;    // Go only
}[]

Session Creation Request (POST /api/sessions):

{
  command: string[];        // Required: parsed command array
  workingDir: string;       // Required: working directory path
  name?: string;           // Optional: session name
  spawn_terminal?: boolean; // Used by Rust API/Swift (always true)
  width?: number;          // Used by Go (default: 120)
  height?: number;         // Used by Go (default: 30)
}

Session Input Request (POST /api/sessions/:id/input):

{
  text: string; // Input text or special keys: 'enter', 'escape', 'arrow_up', etc.
}

Terminal Resize Request (POST /api/sessions/:id/resize):

{
  width: number;  // Terminal columns  
  height: number; // Terminal rows
}

Major Implementation Differences

1. Server Implementation Status

All API servers are fully functional and complete:

Rust API Server (tty-fwd/src/api_server.rs):

  • Purpose: Full terminal session management server
  • APIs: Complete implementation of all session endpoints
  • Features: Authentication, SSE streaming, file system APIs
  • Missing: Terminal resize endpoint only

Architecture Note: The Rust HTTP Server (tty-fwd/src/http_server.rs) is a utility component for static file serving and HTTP/SSE primitives, not a standalone API server. It's correctly excluded from this analysis.

2. CRITICAL: Missing Terminal Resize API

Impact: ⚠️ Client expects this endpoint and calls it continuously Affected: Rust API Server, Swift Server Endpoints: POST /api/sessions/:id/resize

Client Behavior:

  • Calls resize endpoint on window resize events (debounced 250ms)
  • Tracks last sent dimensions to avoid redundant requests
  • Logs warnings on failure but continues operation
  • Will cause 404 errors on Rust API and Swift servers

Working Implementation Analysis:

// Node.js Implementation (✅ Complete)
app.post('/api/sessions/:sessionId/resize', async (req, res) => {
  const { width, height } = req.body;
  // Validation: 1-1000 range
  if (width < 1 || height < 1 || width > 1000 || height > 1000) {
    return res.status(400).json({ error: 'Width and height must be between 1 and 1000' });
  }
  ptyService.resizeSession(sessionId, width, height);
});
// Go Implementation (✅ Complete)
func (s *Server) handleResizeSession(w http.ResponseWriter, r *http.Request) {
  // Includes validation for positive integers
  if req.Width <= 0 || req.Height <= 0 {
    http.Error(w, "Width and height must be positive integers", http.StatusBadRequest)
    return
  }
}

Missing in:

  • Rust API Server: No resize endpoint
  • Swift Server: No resize endpoint

3. Session Creation Request Format Inconsistencies

Node.js Format:

{
  "command": ["bash", "-l"],
  "workingDir": "/path/to/dir",
  "name": "session_name"
}

Rust API Format:

{
  "command": ["bash", "-l"],
  "workingDir": "/path/to/dir",
  "term": "xterm-256color",
  "spawn_terminal": true
}

Go Format:

{
  "name": "session_name",
  "command": ["bash", "-l"],
  "workingDir": "/path/to/dir",
  "width": 120,
  "height": 30
}

Swift Format:

{
  "command": ["bash", "-l"],
  "workingDir": "/path/to/dir",
  "term": "xterm-256color",
  "spawnTerminal": true
}

Issues:

  1. Inconsistent field naming (workingDir vs working_dir)
  2. Different optional fields across implementations
  3. Terminal dimensions only in Go implementation

4. Authentication Implementation Differences

Server Auth Method Details
Node.js None No authentication middleware
Rust API Basic Auth Configurable password, realm="tty-fwd"
Go Basic Auth Fixed username "admin", realm="VibeTunnel"
Swift Basic Auth Lazy keychain-based password loading

Problems:

  1. Different realm names ("tty-fwd" vs "VibeTunnel")
  2. Inconsistent username requirements
  3. Node.js completely lacks authentication

5. Session Input Handling Inconsistencies

Special Key Mappings Differ:

Node.js:

const specialKeys = [
  'arrow_up', 'arrow_down', 'arrow_left', 'arrow_right',
  'escape', 'enter', 'ctrl_enter', 'shift_enter'
];

Go:

specialKeys := map[string]string{
  "arrow_up":    "\x1b[A",
  "arrow_down":  "\x1b[B", 
  "arrow_right": "\x1b[C",
  "arrow_left":  "\x1b[D",
  "escape":      "\x1b",
  "enter":       "\r",        // CR, not LF
  "ctrl_enter":  "\r",        // CR for ctrl+enter
  "shift_enter": "\x1b\x0d", // ESC + CR for shift+enter
}

Swift:

let specialKeys = [
  "arrow_up", "arrow_down", "arrow_left", "arrow_right",
  "escape", "enter", "ctrl_enter", "shift_enter"
]

Issues:

  1. Go provides explicit escape sequence mappings
  2. Node.js and Swift rely on PTY service for mapping
  3. Different enter key handling (\r vs \n)

6. Session Response Format Inconsistencies

Node.js Session List Response:

{
  "id": "session-123",
  "command": "bash -l",
  "workingDir": "/home/user",
  "name": "my-session",
  "status": "running",
  "exitCode": null,
  "startedAt": "2024-01-01T00:00:00Z",
  "lastModified": "2024-01-01T00:01:00Z",
  "pid": 1234,
  "waiting": false
}

Rust API Session List Response:

{
  "id": "session-123",
  "command": "bash -l",
  "workingDir": "/home/user",
  "status": "running",
  "exitCode": null,
  "startedAt": "2024-01-01T00:00:00Z",
  "lastModified": "2024-01-01T00:01:00Z",
  "pid": 1234
}

Differences:

  1. Node.js includes name and waiting fields
  2. Rust API missing these fields
  3. Field naming inconsistencies across servers

7. File System API Response Format Differences

Node.js FS Browse Response:

{
  "absolutePath": "/home/user",
  "files": [{
    "name": "file.txt",
    "created": "2024-01-01T00:00:00Z",
    "lastModified": "2024-01-01T00:01:00Z",
    "size": 1024,
    "isDir": false
  }]
}

Go FS Browse Response:

[{
  "name": "file.txt",
  "path": "/home/user/file.txt",
  "is_dir": false,
  "size": 1024,
  "mode": "-rw-r--r--",
  "mod_time": "2024-01-01T00:01:00Z"
}]

Issues:

  1. Different response structures (object vs array)
  2. Different field names (isDir vs is_dir)
  3. Go includes additional fields (path, mode)
  4. Missing created field in Go

8. Error Response Format Inconsistencies

Node.js Error Format:

{
  "error": "Session not found"
}

Rust API Error Format:

{
  "success": null,
  "message": null,
  "error": "Session not found",
  "sessionId": null
}

Go Simple Error:

"Session not found" (plain text)

Problems:

  1. Inconsistent error response structures
  2. Some servers use structured responses, others plain text
  3. Different HTTP status codes for same error conditions

Critical Security Issues

1. Inconsistent Authentication

  • Node.js server has NO authentication
  • Different authentication realms across servers
  • No standardized credential management

2. Path Traversal Vulnerabilities

Different path sanitization across servers:

Node.js (Proper):

function resolvePath(inputPath, fallback) {
  if (inputPath.startsWith('~')) {
    return path.join(os.homedir(), inputPath.slice(1));
  }
  return path.resolve(inputPath);
}

Go (Basic):

// Expand ~ in working directory
if cwd != "" && cwd[0] == '~' {
  // Simple tilde expansion
}

Missing Features by Server

Node.js Missing:

  • ngrok tunnel management
  • Terminal dimensions in session creation

Rust HTTP Server Missing:

  • ALL API endpoints (only static file serving)

Rust API Server Missing:

  • Terminal resize functionality
  • ngrok tunnel management

Go Server Missing:

  • None (most complete implementation)

Swift Server Missing:

  • Terminal resize functionality

Recommendations

1. Immediate Fixes Required

  1. Standardize Request/Response Formats:

    • Use consistent field naming (camelCase vs snake_case)
    • Standardize error response structure
    • Align session creation request formats
  2. Implement Missing Critical APIs:

    • Add resize endpoint to Rust API and Swift servers
    • Add authentication to Node.js server
    • Deprecate or complete Rust HTTP server
  3. Fix Security Issues:

    • Standardize authentication realms
    • Implement consistent path sanitization
    • Add proper input validation

2. Semantic Alignment

  1. Session Management:

    • Standardize session ID generation
    • Align session status values
    • Consistent PID handling
  2. Special Key Handling:

    • Standardize escape sequence mappings
    • Consistent enter key behavior
    • Align special key names
  3. File System Operations:

    • Standardize directory listing format
    • Consistent path resolution
    • Align file metadata fields

3. Architecture Improvements

  1. API Versioning:

    • Implement /api/v1/ prefix
    • Version all endpoint contracts
    • Plan backward compatibility
  2. Error Handling:

    • Standardize HTTP status codes
    • Consistent error response format
    • Proper error categorization
  3. Documentation:

    • OpenAPI/Swagger specifications
    • API contract testing
    • Cross-server compatibility tests

Rust Server Architecture Analysis

After deeper analysis, the Rust servers have a clear separation of concerns:

Rust Session Management (tty-fwd/src/sessions.rs)

Complete session management implementation:

  • list_sessions() - Full session listing with status checking
  • send_key_to_session() - Special key input (arrow keys, enter, escape, etc.)
  • send_text_to_session() - Text input to sessions
  • send_signal_to_session() - Signal sending (SIGTERM, SIGKILL, etc.)
  • cleanup_sessions() - Session cleanup with PID validation
  • spawn_command() - New session creation
  • Process monitoring and zombie reaping
  • Pipe-based I/O with timeout protection

Rust Protocol Support (tty-fwd/src/protocol.rs)

Complete streaming and protocol support:

  • Asciinema format reading/writing
  • SSE streaming with StreamingIterator
  • Terminal escape sequence processing
  • Real-time event streaming with file monitoring
  • UTF-8 handling and buffering

Main Binary (tty-fwd/src/main.rs)

Complete CLI interface:

  • Session listing: --list-sessions
  • Key input: --send-key <key>
  • Text input: --send-text <text>
  • Process control: --signal, --stop, --kill
  • Cleanup: --cleanup
  • HTTP Server: --serve <addr> (launches API server)

Key Finding: tty-fwd --serve launches the API server, not the HTTP server.

Corrected Assessment

Rust Implementation Status: COMPLETE AND CORRECT

All servers are properly implemented:

  1. Node.js Server: Complete - PTY service wrapper
  2. Rust HTTP Server: Complete - Utility HTTP server (not meant for direct client use)
  3. Rust API Server: Complete - Full session management server
  4. Go Server: Complete - Native session management
  5. Swift Server: Complete - Wraps tty-fwd binary

Remaining Issues (Reduced Severity):

  1. Terminal Resize Missing (Rust API, Swift) - Client compatibility issue
  2. Request/Response Format Inconsistencies - Client needs adaptation
  3. Authentication Differences - Security/compatibility issue

Updated Recommendations

1. Immediate Priority: Terminal Resize

Add resize endpoint to Rust API and Swift servers:

// Rust API Server needs:
POST /api/sessions/{sessionId}/resize

2. Response Format Standardization

Align session list responses across all servers for client compatibility.

3. Authentication Standardization

Implement consistent Basic Auth across all servers.

Conclusion

Previous Assessment Correction: The Rust servers are fully functional and complete. The HTTP server is correctly designed as a utility component, while the API server provides full session management.

Current Status: 4 out of 5 servers are client-compatible. Only missing terminal resize in Rust API and Swift servers.

Impact: Much lower than initially assessed. The main issues are:

  1. Terminal resize functionality - causes 404s but client continues working
  2. Response format variations - may cause field mapping issues
  3. Authentication inconsistencies - different security models

The project has solid API coverage across all platforms with minor compatibility issues rather than fundamental implementation gaps.