Bridge SDK

BridgeClient

WebSocket client for real-time streaming events from ORO Claude Bridge.

BridgeClient

Socket.IO-based client for real-time events. Handles automatic reconnection, room management, and typed event emission.

Constructor

import { BridgeClient } from '@oro.ad/bridge-sdk'

const client = new BridgeClient({
  url: 'http://localhost:3000',
  auth: {
    clientId: 'my-adapter',
    clientType: 'adapter',
    nickname: 'TG Adapter'
  },
  autoReconnect: true,            // default: true
  reconnectionDelayMs: 1000,      // default: 1000
  reconnectionDelayMaxMs: 30000,  // default: 30000
  transports: ['websocket'],      // default: ['websocket']
})
OptionTypeDefaultDescription
urlstringrequiredBridge server URL
pathstringCustom Socket.IO path
authobjectAuthentication payload
autoConnectbooleanfalseConnect immediately on construction
autoReconnectbooleantrueReconnect on disconnect
reconnectionDelayMsnumber1000Initial reconnection delay
reconnectionDelayMaxMsnumber30000Max reconnection delay
transportsstring[]['websocket']Socket.IO transports
loggerLoggerStructured logger

Lifecycle

client.connect()

// Wait for connection (with timeout)
await client.connected(10_000)

console.log(client.isConnected()) // true

client.close()

Room Management

Each bridge session is a "room". You must join a room to receive its stream events.

client.join('claude_abc123')
client.leave('claude_abc123')

client.isJoined('claude_abc123')  // boolean
client.getJoinedRooms()           // string[]

Outgoing Events

// Send a message through the socket (alternative to REST)
client.emitSendMessage({
  conversationId: 'claude_abc123',
  content: 'Hello!',
  attachments: []
})

// Stop generation
client.emitStopGeneration('claude_abc123')

// Register for shared session
client.emitRegisterShare({
  conversationId: 'claude_abc123',
  clientId: 'my-client',
  nickname: 'John'
})

Stream Events

All stream events include a conversationId field for routing.

Connection Events

client.on('connect', () => {
  console.log('Connected to bridge')
})

client.on('disconnect', (reason: string) => {
  console.log('Disconnected:', reason)
})

client.on('connect_error', (err: Error) => {
  console.error('Connection failed:', err.message)
})

Session List

Broadcasted when sessions change (created, deleted, status update).

client.on('sessions:list', (sessions: SessionSummary[]) => {
  // Full session list — reconcile your containers
})

Server Status

Periodic heartbeat across all sessions. Useful for "any activity?" dashboards and liveness probes.

client.on('server:status', (status) => {
  // status.anyProcessing: boolean
  // status.activeSessions: number
  // status.uptime: number (seconds)
})

Stream Lifecycle

// User message accepted by bridge
client.on('stream:user_message', (e) => {
  // e.id, e.content, e.senderId, e.senderNickname, e.conversationId
})

// Message buffered (multi-user, waiting to flush)
client.on('stream:buffered', (e) => {
  // e.id, e.content, e.senderId, e.timestamp, e.conversationId
})

// Buffer flushed into a composed prompt
client.on('stream:buffer_flushed', (e) => {
  // e.messages[], e.composedPrompt, e.conversationId
})

// Assistant turn begins
client.on('stream:message_start', (e) => {
  // e.id, e.conversationId, e.triggerMessageId
})

// Incremental text
client.on('stream:text_delta', (e) => {
  // e.text, e.conversationId
})

// Tool invocation
client.on('stream:tool_use', (e) => {
  // e.id, e.name, e.input, e.conversationId
})

// Tool result
client.on('stream:tool_result', (e) => {
  // e.tool_use_id, e.name, e.content, e.is_error, e.conversationId
})

// Turn complete (full response available)
client.on('stream:message_complete', (e) => {
  // e.id, e.model, e.content, e.contentBlocks, e.conversationId
})

// Final result with usage/cost
client.on('stream:result', (e) => {
  // e.subtype, e.cost_usd, e.usage, e.duration_ms, e.conversationId
})

// Generation stopped (user or system)
client.on('stream:stopped', (e) => {
  // e.message, e.partialContent, e.conversationId
})

// User message queued behind an in-flight turn
client.on('stream:queued', (e) => {
  // e.messageId, e.position (0-based), e.triggerMessageId, e.conversationId
})

// Mid-turn state snapshot for late joiners / reconnects
client.on('stream:sync', (e) => {
  // e.messageId, e.triggerMessageId, e.contentBlocks[], e.accumulatedText,
  // e.model, e.status ('processing'), e.conversationId
})

Session Status

client.on('session:status', (e) => {
  // e.processing: boolean, e.conversationId
})

client.on('session:error', (e) => {
  // e.error: string, e.conversationId, e.exitCode?
})

Loop Mode Events

client.on('session:loop_started', (e) => {
  // e.conversationId, e.config: LoopConfig
})

client.on('session:loop_paused', (e) => {
  // e.conversationId, e.reason: string
})

client.on('session:loop_stopped', (e) => {
  // e.conversationId
})

client.on('session:loop_iteration', (e) => {
  // e.conversationId, e.iteration, e.totalCostUsd
})

Shared Session Events

client.on('share:users', (users: ConnectedUser[]) => { })
client.on('share:user_joined', (e) => { })
client.on('share:user_left', (e) => { })
client.on('share:registered', (e) => { })
client.on('share:nickname_taken', (e) => { })

Raw Socket Access

For advanced use cases, access the underlying Socket.IO instance:

client.rawSocket.on('custom:event', handler)

Reconnection behavior

BridgeClient enables automatic reconnection via Socket.IO's built-in exponential backoff (reconnectionDelayMsreconnectionDelayMaxMs). Joined rooms are tracked in memory and re-emitted as session:join automatically on every connect event — you don't need to re-join manually after a disconnect.

To tell "fresh connect" from "reconnect", track state yourself:

let firstConnect = true
client.on('connect', () => {
  if (!firstConnect) console.log('reconnected')
  firstConnect = false
})

Graceful shutdown

async function shutdown() {
  // Unsubscribe from rooms so the server stops pushing events.
  for (const room of client.getJoinedRooms()) client.leave(room)
  client.close()
}
process.on('SIGTERM', shutdown)