> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/moeru-ai/airi/llms.txt
> Use this file to discover all available pages before exploring further.

# WebSocket Protocol

> WebSocket connection protocol, message format, and lifecycle

## Connection Lifecycle

The WebSocket connection follows a specific lifecycle:

```mermaid theme={null}
sequenceDiagram
    participant Client
    participant Server
    
    Client->>Server: Connect to /ws
    Server->>Client: Connection Open
    
    alt Authentication Required
        Server->>Client: Awaiting Authentication
        Client->>Server: module:authenticate
        Server->>Client: module:authenticated
    else No Authentication
        Server->>Client: module:authenticated
    end
    
    Server->>Client: registry:modules:sync
    Client->>Server: module:announce
    
    loop Heartbeat
        Client->>Server: transport:connection:heartbeat (ping)
        Server->>Client: transport:connection:heartbeat (pong)
    end
    
    Client->>Server: Custom Events
    Server->>Client: Routed Events
    
    Client->>Server: Close Connection
    Server->>Client: Connection Closed
```

## Message Format

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

### Base Event Structure

```typescript theme={null}
interface WebSocketEvent<T = unknown> {
  type: string
  data: T
  metadata: {
    source: MetadataEventSource
    event: {
      id: string
      parentId?: string
    }
  }
  route?: {
    destinations?: Array<string | RouteTargetExpression>
    bypass?: boolean
  }
}
```

<ParamField path="type" type="string" required>
  Event type identifier (e.g., `'module:authenticate'`, `'ui:configure'`)
</ParamField>

<ParamField path="data" type="T" required>
  Event-specific payload data
</ParamField>

<ParamField path="metadata.source" type="MetadataEventSource" required>
  Source information including plugin identity
</ParamField>

<ParamField path="metadata.event.id" type="string" required>
  Unique event identifier for tracing
</ParamField>

<ParamField path="metadata.event.parentId" type="string" optional>
  Parent event ID for request-response correlation
</ParamField>

<ParamField path="route.destinations" type="Array<string | RouteTargetExpression>" optional>
  Target destinations for event routing
</ParamField>

<ParamField path="route.bypass" type="boolean" optional>
  Whether to bypass routing policies (requires devtools label)
</ParamField>

## Event Types

### Authentication Events

#### `module:authenticate`

Sent by client to authenticate with the server.

```typescript theme={null}
{
  type: 'module:authenticate',
  data: {
    token: string
  }
}
```

#### `module:authenticated`

Server response indicating authentication status.

```typescript theme={null}
{
  type: 'module:authenticated',
  data: {
    authenticated: boolean
  }
}
```

### Module Registration

#### `module:announce`

Client announces itself to the module registry.

```typescript theme={null}
{
  type: 'module:announce',
  data: {
    name: string
    index?: number
    identity: MetadataEventSource
  }
}
```

<ParamField path="name" type="string" required>
  Module name (must be non-empty string)
</ParamField>

<ParamField path="index" type="number" optional>
  Module instance index (must be non-negative integer)
</ParamField>

<ParamField path="identity" type="MetadataEventSource" required>
  Module identity with plugin information
</ParamField>

#### `registry:modules:sync`

Server broadcasts current module registry to newly connected clients.

```typescript theme={null}
{
  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.

```typescript theme={null}
{
  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:

```typescript theme={null}
{
  type: 'module:configure',
  data: {
    config: Record<string, unknown>
  }
}
```

### Heartbeat Events

#### `transport:connection:heartbeat`

Bidirectional heartbeat messages to maintain connection health.

```typescript theme={null}
{
  type: 'transport:connection:heartbeat',
  data: {
    kind: 'ping' | 'pong'
    message: MessageHeartbeat | string
    at: number  // timestamp
  }
}
```

<ParamField path="kind" type="'ping' | 'pong'" required>
  Heartbeat message type
</ParamField>

<ParamField path="message" type="MessageHeartbeat | string" required>
  Heartbeat message content
</ParamField>

<ParamField path="at" type="number" required>
  Unix timestamp in milliseconds
</ParamField>

### Error Events

#### `error`

Server error response.

```typescript theme={null}
{
  type: 'error',
  data: {
    message: string
  }
}
```

## Connection Management

### Peer State

The server maintains the following state for each connected peer:

```typescript theme={null}
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).

```typescript theme={null}
// 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

<AccordionGroup>
  <Accordion title="Always include metadata.source">
    The server uses source metadata for module identification and routing. Always include complete plugin identity information.
  </Accordion>

  <Accordion title="Handle authentication properly">
    If the server requires authentication, wait for `module:authenticated` before announcing your module.
  </Accordion>

  <Accordion title="Implement heartbeat">
    Send heartbeat pings at regular intervals (recommended: every 30 seconds) to prevent connection timeout.
  </Accordion>

  <Accordion title="Use event IDs for tracing">
    Generate unique event IDs and use parentId for request-response correlation to enable end-to-end tracing.
  </Accordion>

  <Accordion title="Handle reconnection">
    Implement exponential backoff for reconnection attempts when connection is lost.
  </Accordion>
</AccordionGroup>

## Error Handling

Common error scenarios:

| Error Message           | Cause                                   | Solution                                |
| ----------------------- | --------------------------------------- | --------------------------------------- |
| `not authenticated`     | Client sent event before authentication | Wait for authentication confirmation    |
| `invalid JSON`          | Malformed message                       | Use SuperJSON for serialization         |
| `invalid token`         | Wrong authentication token              | Verify token configuration              |
| `module not found`      | Target module not registered            | Wait for registry sync before sending   |
| Field validation errors | Invalid field values in events          | Check field type and range requirements |

## Next Steps

<CardGroup cols={2}>
  <Card title="Event System" icon="bolt" href="/api/server-runtime/events">
    Learn about event routing and middleware
  </Card>

  <Card title="Server SDK" icon="code" href="/api/packages/server-sdk">
    Use the client SDK for easy integration
  </Card>
</CardGroup>
