Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/outray-tunnel/outray/llms.txt

Use this file to discover all available pages before exploring further.

OutrayClient accepts a single options object in its constructor. All fields except localPort are optional.
import { OutrayClient } from '@outray/core';

const client = new OutrayClient(options: OutrayClientOptions);

TypeScript interface

Verbatim from packages/core/src/types.ts:
export interface OutrayClientOptions {
  /** Local port to proxy requests to */
  localPort: number;

  /**
   * Outray server WebSocket URL
   * @default 'wss://api.outray.dev/'
   */
  serverUrl?: string;

  /** API key for authentication */
  apiKey?: string;

  /**
   * Subdomain to use for the tunnel URL
   * Requires authentication
   */
  subdomain?: string;

  /**
   * Custom domain for the tunnel
   * Must be configured in the Outray dashboard first
   */
  customDomain?: string;

  /**
   * Tunnel protocol type
   * @default 'http'
   */
  protocol?: TunnelProtocol;

  /** Remote port for TCP/UDP tunnels */
  remotePort?: number;

  /** Callback fired when tunnel is successfully established */
  onTunnelReady?: (url: string, port?: number) => void;

  /** Callback fired when tunnel encounters an error */
  onError?: (error: Error, code?: string) => void;

  /** Callback fired when tunnel is closed */
  onClose?: (reason?: string) => void;

  /** Callback fired when attempting to reconnect */
  onReconnecting?: (attempt: number, delay: number) => void;

  /** Callback fired for each proxied request (HTTP only) */
  onRequest?: (info: RequestInfo) => void;
}

export interface RequestInfo {
  method: string;
  path: string;
  statusCode: number;
  duration: number;
  error?: string;
}

export type TunnelProtocol = "http" | "tcp" | "udp";

Connection options

localPort
number
required
The local port that OutRay forwards incoming traffic to. Must be an integer between 1 and 65535.
localPort: 3000
serverUrl
string
default:"wss://api.outray.dev/"
WebSocket URL of the OutRay tunnel server. Must use the ws:// or wss:// scheme. Override this when connecting to a self-hosted OutRay server.
serverUrl: 'wss://api.outray.dev/'
apiKey
string
API key used to authenticate with the OutRay server. Without a key the server issues an anonymous, unauthenticated tunnel with a randomly generated URL and no subdomain control.
apiKey: process.env.OUTRAY_API_KEY

Tunnel options

protocol
string
default:"http"
The tunnel protocol. One of "http", "tcp", or "udp".
protocol: 'tcp'
subdomain
string
Request a specific subdomain for the tunnel URL. Requires authentication. If the subdomain is taken when reconnecting, the client automatically attempts a takeover.
subdomain: 'my-app'
// → https://my-app.tunnel.outray.app
customDomain
string
Use a fully-qualified custom domain instead of a generated subdomain URL. The domain must be set up in the OutRay dashboard and DNS must point to the OutRay server before traffic can be served.
customDomain: 'app.example.com'
remotePort
number
Request a specific public port for TCP or UDP tunnels. If the port is unavailable the server assigns a different one.
remotePort: 20000

Callbacks

onTunnelReady

onTunnelReady?: (url: string, port?: number) => void
Called once when the tunnel is successfully established (or re-established after a reconnect). url is the public HTTPS URL for HTTP tunnels. For TCP/UDP tunnels port contains the assigned public port number.
onTunnelReady: (url, port) => {
  if (port) {
    console.log(`TCP tunnel open on port ${port}`);
  } else {
    console.log(`HTTP tunnel ready at ${url}`);
  }
}

onError

onError?: (error: Error, code?: string) => void
Called when the tunnel encounters an error. code is one of the error codes when the error originates from the OutRay server, or undefined for network-level errors.
When code is AUTH_FAILED or LIMIT_EXCEEDED the client stops reconnecting automatically. All other errors trigger a reconnect with exponential backoff.
onError: (error, code) => {
  switch (code) {
    case 'AUTH_FAILED':
      console.error('Invalid API key');
      break;
    case 'SUBDOMAIN_IN_USE':
      console.warn('Subdomain conflict – attempting takeover');
      break;
    default:
      console.error(error.message);
  }
}

onClose

onClose?: (reason?: string) => void
Called when the tunnel is closed cleanly (for example, when client.stop() is called or the server sends a "Tunnel stopped by user" close frame). Not called on error-induced disconnects — those trigger onError followed by onReconnecting.
onClose: (reason) => {
  console.log(`Tunnel closed: ${reason ?? 'no reason given'}`);
}

onReconnecting

onReconnecting?: (attempt: number, delay: number) => void
Called before each reconnect attempt. attempt is the 1-based attempt count. delay is the number of milliseconds the client will wait before opening a new WebSocket connection. The backoff is exponential, capped at 30 seconds: Math.min(2000 * 2^attempt, 30000).
onReconnecting: (attempt, delay) => {
  console.log(`Reconnecting in ${delay}ms (attempt ${attempt})`);
}

onRequest

onRequest?: (info: RequestInfo) => void
Called after each HTTP request is proxied to the local server. Not called for TCP or UDP traffic.
info.method
string
HTTP method of the request, for example "GET" or "POST".
info.path
string
Request path including query string, for example "/api/users?page=1".
info.statusCode
number
HTTP status code returned by the local server. Set to 502 when the local server is unreachable.
info.duration
number
Round-trip time in milliseconds from receiving the request to sending the response.
info.error
string
Error message string when the local server returned an error or was unreachable. undefined on successful requests.
onRequest: (info) => {
  const status = info.error ? `ERR ${info.error}` : info.statusCode;
  console.log(`${info.method} ${info.path}${status} (${info.duration}ms)`);
}

Client methods

Once constructed, OutrayClient exposes four methods:
MethodReturnsDescription
start()voidOpen the WebSocket connection and begin tunneling.
stop()voidClose the connection, cancel any pending reconnects, and release resources.
getUrl()string | nullReturn the currently assigned tunnel URL, or null if not yet connected.
isConnected()booleanReturn true if the WebSocket connection is open.
client.start();

// Check status at any time
console.log('Connected:', client.isConnected());
console.log('URL:', client.getUrl());

// Graceful shutdown
client.stop();