Client
Framework-agnostic TypeScript WebSocket client with auto-reconnect and session persistence. Use this in any JavaScript environment — no React required.
client/src/client.tsInstall
npm install @walkie-talkie/clientQuick Start
import { WalkieTalkieClient } from '@walkie-talkie/client';
const client = new WalkieTalkieClient();
// Listen for state changes
client.onStateChange((state) => {
console.log('Connection:', state);
// 'connecting' | 'authenticating' | 'connected' | 'reconnecting' | ...
});
// Listen for messages
client.onMessage((msg) => {
if (msg.type === 'terminal:output') {
process.stdout.write(msg.data);
}
if (msg.type === 'terminal:created') {
console.log('Terminal ready:', msg.terminal.id);
}
});
// Connect with a token
client.connect('http://localhost:3456', 'abcd-ef01-2345-6789');Connection States
type ConnectionState =
| 'disconnected' // Not connected
| 'connecting' // WebSocket opening
| 'authenticating' // WS open, waiting for auth response
| 'connected' // Authenticated and ready
| 'reconnecting' // Auto-reconnecting after disconnect
| 'error'; // Auth failed or fatal errorState transitions are emitted via onStateChange(). The client auto-reconnects on unexpected disconnects using exponential backoff (1s to 30s max).
API
WalkieTalkieClient
| Method | Description |
|---|---|
connect(serverUrl, token) | Connect and authenticate with a one-time token |
resumeSession(serverUrl, sessionId) | Reconnect using an existing session ID |
disconnect() | Close connection (no auto-reconnect) |
send(msg) | Send a ClientMessage |
onMessage(handler) | Subscribe to server messages. Returns unsubscribe function. |
onStateChange(handler) | Subscribe to connection state changes. Returns unsubscribe function. |
getSessionId() | Current session ID or null |
getServerUrl() | Current server URL |
getState() | Current ConnectionState |
isResuming | true during session resume (vs. fresh connect) |
Sending Messages
Use send() with typed protocol messages:
// Create a terminal
client.send({
type: 'terminal:create',
cols: 120,
rows: 40,
});
// Send input (e.g. a command)
client.send({
type: 'terminal:input',
terminalId: 'uuid-of-terminal',
data: 'ls -la\n',
});
// Resize
client.send({
type: 'terminal:resize',
terminalId: 'uuid-of-terminal',
cols: 160,
rows: 50,
});
// Kill a terminal
client.send({
type: 'terminal:kill',
terminalId: 'uuid-of-terminal',
});
// List all terminals in the session
client.send({ type: 'terminal:list' });Session Resume
After a successful auth, the server returns a sessionId. Save it and use it to reconnect later — no new token needed:
// First connection — save the session
client.onStateChange((state) => {
if (state === 'connected') {
const sessionId = client.getSessionId();
localStorage.setItem('wt-session', sessionId);
localStorage.setItem('wt-server', client.getServerUrl());
}
});
// Later — resume
const sessionId = localStorage.getItem('wt-session');
const serverUrl = localStorage.getItem('wt-server');
if (sessionId && serverUrl) {
client.resumeSession(serverUrl, sessionId);
}On resume, the server replays the terminal list and scrollback buffer, so your terminals appear exactly where you left off.
Auto-Reconnect
If the WebSocket disconnects unexpectedly (network drop, server restart), the client automatically reconnects using exponential backoff:
- First retry: 1 second
- Doubles each time: 2s, 4s, 8s, 16s...
- Max delay: 30 seconds
- Uses
auth:resumeif a session exists
Call disconnect() to stop reconnection attempts.
Storage Utilities
client/src/storage.tsThe client package also exports localStorage helpers for managing saved connections:
import {
getSavedConnections,
saveConnection,
removeConnection,
clearConnections,
loadState,
saveState,
} from '@walkie-talkie/client';
// Get recent connections (max 10)
const connections = getSavedConnections();
// → [{ serverUrl, sessionId, connectedAt }]
// Save a connection
saveConnection({
serverUrl: 'http://localhost:3456',
sessionId: 'uuid-here',
connectedAt: Date.now(),
});
// Generic state persistence
saveState('my-key', { zoom: 1.5 });
const state = loadState('my-key', { zoom: 1 });