Portal Community

Status State Machine

                    connect()
  disconnected ─────────────────→ connecting
                                       │
                              success  │  failure
                                 ↓         ↓
                            connected     error
                                 │
                          drops  │
                                 ↓
                          reconnecting
                                 │
                     reconnect   │   all attempts
                     succeeds    │   exhausted
                         ↓           ↓
                     connected    disconnected

  disconnect() from any state → disconnected

Monitoring Status Changes

const server = stream.server('bas')!;

// Subscribe to all status transitions
const unsub = server.transport.onStatusChange((status) => {
  switch (status) {
    case 'connecting':
      console.log('[BAS] Connecting to server...');
      break;
    case 'connected':
      console.log('[BAS] Connected');
      connectionStore.setStatus('bas', 'connected');
      break;
    case 'reconnecting':
      console.log('[BAS] Connection lost — reconnecting...');
      connectionStore.setStatus('bas', 'reconnecting');
      break;
    case 'error':
      console.error('[BAS] Connection error:', server.transport.lastError?.message);
      connectionStore.setStatus('bas', 'error');
      break;
    case 'disconnected':
      console.log('[BAS] Disconnected');
      connectionStore.setStatus('bas', 'disconnected');
      break;
  }
});

// Unsubscribe when done
unsub(); // remove the handler

Per-Transport Lifecycle Details

EventSignalRWebSocketSSEHTTP Polling
connectingstart() callednew WebSocket()new EventSource()poll loop starts
connectedonreconnected or start resolvesws.onopeneventSource.openfirst successful GET
reconnectingonreconnecting callbackws.onclose + retryeventSource error + closedconsecutive GET failures
errorstart() rejectsws.onerroreventSource error (not closed)unrecoverable fetch error
disconnectedonclose (after stop)disconnect() calleddisconnect() calleddisconnect() called

lastError Property

// Access the last error that occurred on the transport
const transport = stream.server('bas')!.transport;

if (transport.status === 'error') {
  console.error('Last error:', transport.lastError?.message);
  // e.g. 'WebSocket connection timeout'
  // e.g. 'SignalR connection not connected'
  // e.g. 'HTTP 401: Unauthorized'
}

Error Monitoring

server.transport.onError((error) => {
  // Called whenever a transport-level error occurs
  // This is separate from status — status may still be 'reconnecting'
  // while errors are being logged
  metrics.increment('edge_stream.transport_error', { server: 'bas' });
  errorMonitor.capture(error, { transport: 'signalr', server: 'bas' });
});

Idempotent Connect and Disconnect

// connect() is idempotent — calling when already connected is a no-op
await transport.connect(); // connects
await transport.connect(); // returns immediately — already connected

// disconnect() is idempotent — calling when already disconnected is a no-op
await transport.disconnect(); // disconnects
await transport.disconnect(); // returns immediately
BaseTransport Deduplication setStatus() in BaseTransport only fires handlers when the status actually changes. If a reconnect attempt emits 'reconnecting' repeatedly, handlers only receive one call for that status — not one per retry attempt.