Skip to main content

Connection Lifecycle

The WebSocket connection follows a specific lifecycle:

Message Format

All WebSocket messages use SuperJSON encoding for type-safe serialization.

Base Event Structure

interface WebSocketEvent<T = unknown> {
  type: string
  data: T
  metadata: {
    source: MetadataEventSource
    event: {
      id: string
      parentId?: string
    }
  }
  route?: {
    destinations?: Array<string | RouteTargetExpression>
    bypass?: boolean
  }
}
type
string
required
Event type identifier (e.g., 'module:authenticate', 'ui:configure')
data
T
required
Event-specific payload data
metadata.source
MetadataEventSource
required
Source information including plugin identity
metadata.event.id
string
required
Unique event identifier for tracing
metadata.event.parentId
string
Parent event ID for request-response correlation
route.destinations
Array<string | RouteTargetExpression>
Target destinations for event routing
route.bypass
boolean
Whether to bypass routing policies (requires devtools label)

Event Types

Authentication Events

module:authenticate

Sent by client to authenticate with the server.
{
  type: 'module:authenticate',
  data: {
    token: string
  }
}

module:authenticated

Server response indicating authentication status.
{
  type: 'module:authenticated',
  data: {
    authenticated: boolean
  }
}

Module Registration

module:announce

Client announces itself to the module registry.
{
  type: 'module:announce',
  data: {
    name: string
    index?: number
    identity: MetadataEventSource
  }
}
name
string
required
Module name (must be non-empty string)
index
number
Module instance index (must be non-negative integer)
identity
MetadataEventSource
required
Module identity with plugin information

registry:modules:sync

Server broadcasts current module registry to newly connected clients.
{
  type: 'registry:modules:sync',
  data: {
    modules: Array<{
      name: string
      index?: number
      identity: MetadataEventSource
    }>
  }
}

Configuration Events

ui:configure

Sent from UI to configure a specific module.
{
  type: 'ui:configure',
  data: {
    moduleName: string
    moduleIndex?: number
    identity?: MetadataEventSource
    config: Record<string, unknown>
  }
}
The server transforms this into module:configure and routes it to the target module:
{
  type: 'module:configure',
  data: {
    config: Record<string, unknown>
  }
}

Heartbeat Events

transport:connection:heartbeat

Bidirectional heartbeat messages to maintain connection health.
{
  type: 'transport:connection:heartbeat',
  data: {
    kind: 'ping' | 'pong'
    message: MessageHeartbeat | string
    at: number  // timestamp
  }
}
kind
'ping' | 'pong'
required
Heartbeat message type
message
MessageHeartbeat | string
required
Heartbeat message content
at
number
required
Unix timestamp in milliseconds

Error Events

error

Server error response.
{
  type: 'error',
  data: {
    message: string
  }
}

Connection Management

Peer State

The server maintains the following state for each connected peer:
interface AuthenticatedPeer {
  peer: Peer
  authenticated: boolean
  name: string
  index?: number
  identity?: MetadataEventSource
  lastHeartbeatAt: number
}

Heartbeat Timeout

Connections are automatically closed if no heartbeat is received within the configured timeout period (default: 60 seconds).
// Client should send heartbeat ping before timeout
const heartbeatInterval = setInterval(() => {
  client.send({
    type: 'transport:connection:heartbeat',
    data: {
      kind: 'ping',
      message: MessageHeartbeat.Ping,
      at: Date.now()
    }
  })
}, 30000) // Send every 30 seconds

Best Practices

The server uses source metadata for module identification and routing. Always include complete plugin identity information.
If the server requires authentication, wait for module:authenticated before announcing your module.
Send heartbeat pings at regular intervals (recommended: every 30 seconds) to prevent connection timeout.
Generate unique event IDs and use parentId for request-response correlation to enable end-to-end tracing.
Implement exponential backoff for reconnection attempts when connection is lost.

Error Handling

Common error scenarios:
Error MessageCauseSolution
not authenticatedClient sent event before authenticationWait for authentication confirmation
invalid JSONMalformed messageUse SuperJSON for serialization
invalid tokenWrong authentication tokenVerify token configuration
module not foundTarget module not registeredWait for registry sync before sending
Field validation errorsInvalid field values in eventsCheck field type and range requirements

Next Steps

Event System

Learn about event routing and middleware

Server SDK

Use the client SDK for easy integration

Build docs developers (and LLMs) love