mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-03-27 09:45:53 +00:00
- 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
532 lines
No EOL
16 KiB
Markdown
532 lines
No EOL
16 KiB
Markdown
# 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):
|
||
```typescript
|
||
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):
|
||
```typescript
|
||
{
|
||
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):
|
||
```typescript
|
||
{
|
||
text: string; // Input text or special keys: 'enter', 'escape', 'arrow_up', etc.
|
||
}
|
||
```
|
||
|
||
#### Terminal Resize Request (POST /api/sessions/:id/resize):
|
||
```typescript
|
||
{
|
||
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**:
|
||
|
||
```javascript
|
||
// 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
|
||
// 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:
|
||
```json
|
||
{
|
||
"command": ["bash", "-l"],
|
||
"workingDir": "/path/to/dir",
|
||
"name": "session_name"
|
||
}
|
||
```
|
||
|
||
#### Rust API Format:
|
||
```json
|
||
{
|
||
"command": ["bash", "-l"],
|
||
"workingDir": "/path/to/dir",
|
||
"term": "xterm-256color",
|
||
"spawn_terminal": true
|
||
}
|
||
```
|
||
|
||
#### Go Format:
|
||
```json
|
||
{
|
||
"name": "session_name",
|
||
"command": ["bash", "-l"],
|
||
"workingDir": "/path/to/dir",
|
||
"width": 120,
|
||
"height": 30
|
||
}
|
||
```
|
||
|
||
#### Swift Format:
|
||
```json
|
||
{
|
||
"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**:
|
||
```javascript
|
||
const specialKeys = [
|
||
'arrow_up', 'arrow_down', 'arrow_left', 'arrow_right',
|
||
'escape', 'enter', 'ctrl_enter', 'shift_enter'
|
||
];
|
||
```
|
||
|
||
**Go**:
|
||
```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**:
|
||
```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:
|
||
```json
|
||
{
|
||
"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:
|
||
```json
|
||
{
|
||
"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:
|
||
```json
|
||
{
|
||
"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:
|
||
```json
|
||
[{
|
||
"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:
|
||
```json
|
||
{
|
||
"error": "Session not found"
|
||
}
|
||
```
|
||
|
||
#### Rust API Error Format:
|
||
```json
|
||
{
|
||
"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):
|
||
```javascript
|
||
function resolvePath(inputPath, fallback) {
|
||
if (inputPath.startsWith('~')) {
|
||
return path.join(os.homedir(), inputPath.slice(1));
|
||
}
|
||
return path.resolve(inputPath);
|
||
}
|
||
```
|
||
|
||
**Go** (Basic):
|
||
```go
|
||
// 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
|
||
// 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. |