Skip to main content

startTcpTunnel()

Starts a persistent TCP → WebSocket proxy. The function creates a local TCP server that listens on an ephemeral port on 127.0.0.1. When a TCP client connects, it forwards all traffic between that client and remoteURL through an authenticated WebSocket. The server remains active even after the client disconnects, allowing reconnection without recreating the tunnel.
import { startTcpTunnel } from 'limrun';

const tunnel = await startTcpTunnel(
  'wss://example.com/instance',
  'your-token',
  '127.0.0.1',
  0,
  { mode: 'singleton' }
);

console.log(`Tunnel listening on ${tunnel.address.address}:${tunnel.address.port}`);

// Close the tunnel when done
tunnel.close();

Parameters

remoteURL
string
required
Remote WebSocket endpoint (e.g. wss://example.com/instance)
token
string
required
Bearer token sent as Authorization header
hostname
string
required
IP address to listen on. Use ‘127.0.0.1’ for localhost.
port
number
required
Port number to listen on. Use 0 to ask Node.js to find an available non-privileged port.
options
TcpTunnelOptions
Tunnel configuration options
maxReconnectAttempts
number
default:6
Maximum number of reconnection attempts
reconnectDelay
number
default:1000
Initial reconnection delay in milliseconds
maxReconnectDelay
number
default:30000
Maximum reconnection delay in milliseconds
logLevel
LogLevel
default:"info"
Controls logging verbosity. One of: 'none', 'error', 'warn', 'info', 'debug'
mode
TunnelMode
default:"singleton"
Tunnel mode for handling TCP connections:
  • 'singleton': Single TCP connection forwarded to WebSocket (default)
  • 'multiplexed': Multiple TCP connections multiplexed over a single WebSocket, each packet prefixed with a 4-byte connection ID

Returns

tunnel
Promise<Tunnel>
A promise that resolves to a Tunnel object

Examples

// Single TCP connection at a time
const tunnel = await startTcpTunnel(
  'wss://example.com/adb',
  token,
  '127.0.0.1',
  0,
  { mode: 'singleton' }
);

console.log(`ADB tunnel at localhost:${tunnel.address.port}`);

Tunnel

Represents an active TCP tunnel.

Properties

address
{ address: string; port: number }
The local address and port the tunnel is listening on
address
string
IP address (e.g. ‘127.0.0.1’)
port
number
Port number

Methods

close()

Close the tunnel and stop accepting connections.
tunnel.close();

getConnectionState()

Get current WebSocket connection state.
const state = tunnel.getConnectionState();
console.log(state); // 'connected'
state
TunnelConnectionState
One of: 'connecting', 'connected', 'disconnected', 'reconnecting'

onConnectionStateChange()

Register callback for WebSocket connection state changes.
const unregister = tunnel.onConnectionStateChange((state) => {
  console.log(`State changed to: ${state}`);
});

// Unregister when done
unregister();
callback
TunnelConnectionStateCallback
required
Callback function called when connection state changes
(state: TunnelConnectionState) => void
unregister
() => void
A function to unregister the callback

Tunnel Modes

Singleton Mode

In singleton mode (default), the tunnel accepts one TCP connection at a time. Each connection gets its own WebSocket session. Use cases:
  • ADB connections
  • SSH tunnels
  • Simple proxying scenarios
Behavior:
  • Only one TCP client can connect at a time
  • New connections are rejected while an existing connection is active
  • WebSocket reconnects automatically on network issues
  • TCP connection is maintained across WebSocket reconnects using a session ID

Multiplexed Mode

In multiplexed mode, multiple TCP connections are multiplexed over a single WebSocket connection. Each TCP connection is assigned a unique 32-bit connection ID, and all data is prefixed with a 4-byte big-endian header. Use cases:
  • Multiple simultaneous connections
  • Scenarios where WebSocket connection overhead matters
  • High-throughput applications
Behavior:
  • Multiple TCP clients can connect simultaneously
  • All connections share a single WebSocket
  • Each packet is prefixed with a 4-byte connection ID header
  • Close signals are sent as header-only packets (4 bytes, no payload)
Protocol:
┌─────────────┬─────────────────────┐
│ Connection  │      Payload        │
│ ID (4 bytes)│   (variable length) │
└─────────────┴─────────────────────┘

Types

TcpTunnelOptions

interface TcpTunnelOptions {
  maxReconnectAttempts?: number; // default: 6
  reconnectDelay?: number; // default: 1000
  maxReconnectDelay?: number; // default: 30000
  logLevel?: LogLevel; // default: 'info'
  mode?: TunnelMode; // default: 'singleton'
}
Configuration options for TCP tunnel.

TunnelMode

type TunnelMode = 'singleton' | 'multiplexed';
Tunnel mode for TCP connections:
  • 'singleton': Single TCP connection forwarded to WebSocket (default)
  • 'multiplexed': Multiple TCP connections multiplexed over a single WebSocket

TunnelConnectionState

type TunnelConnectionState = 'connecting' | 'connected' | 'disconnected' | 'reconnecting';
Connection state of the tunnel’s WebSocket.

TunnelConnectionStateCallback

type TunnelConnectionStateCallback = (state: TunnelConnectionState) => void;
Callback function for tunnel connection state changes.

LogLevel

type LogLevel = 'none' | 'error' | 'warn' | 'info' | 'debug';
Controls the verbosity of logging in the tunnel.

Build docs developers (and LLMs) love