Portal Community

One Transport Per Server

The architecture is: EdgeStream → Servers → Transport. Each server owns one transport. Multiple servers = multiple transports, all managed by a single EdgeStream instance:

EdgeStream
├── Server 'bas'  →  SignalRTransport (/hubs/edge-stream)
├── Server 'chat' →  RawWebSocketTransport (wss://chat.bizfirst.com/ws)
└── Server 'audit' → SseTransport (/api/audit/stream)

Registering Multiple Transports

const stream = createEdgeStream({ logLevel: 'info' });

// Transport 1: SignalR for workflow + HIL events
stream.registerServer({
  id: 'bas',
  type: 'bas',
  url: '/hubs/edge-stream',
  transportConfig: {
    type: 'signalr',
    url: '/hubs/edge-stream',
    accessToken: authStore.getToken(),
  }
});

// Transport 2: Raw WebSocket for Octopus agent streaming (low latency)
stream.registerServer({
  id: 'chat',
  type: 'chat',
  url: 'wss://chat.bizfirst.com/ws',
  transportConfig: {
    type: 'websocket',
    url: 'wss://chat.bizfirst.com/ws',
    queryParams: { token: authStore.getChatToken() },
  }
});

// Transport 3: SSE for read-only audit stream
stream.registerServer({
  id: 'audit',
  type: 'bas',
  url: '/api/audit/stream',
  transportConfig: {
    type: 'sse',
    url: '/api/audit/stream',
    queryParams: { tenantId: tenantId },
  }
});

// All three connect concurrently
await stream.start();

Subscribing per Transport

// Subscribe to workflow events (SignalR)
stream.subscribe('bas', 'workflow.*', workflowHandler);
stream.subscribe('bas', 'hil.*', hilHandler);

// Subscribe to agent streaming (WebSocket)
stream.subscribe('chat', 'agent.chat.*', chatHandler);

// Subscribe to audit events (SSE — receive only)
stream.subscribe('audit', 'audit.*', auditHandler);

Monitoring Transport Status Independently

// Monitor each transport independently
const basTransport = stream.server('bas')!.transport;
const chatTransport = stream.server('chat')!.transport;

basTransport.onStatusChange((status) => {
  uiStore.setBASStatus(status); // 'connected' | 'reconnecting' | ...
});

chatTransport.onStatusChange((status) => {
  uiStore.setChatStatus(status);
});

// Or use EdgeStream lifecycle events (server-level)
stream.on('server:connected', (event) => {
  console.log(`${event.serverId} transport connected`);
  // event.serverId is 'bas', 'chat', or 'audit'
});

stream.on('server:disconnected', (event) => {
  console.warn(`${event.serverId} transport disconnected`);
});

Transport Isolation

Each server's transport is fully isolated from others. A reconnecting WebSocket does not affect the SignalR connection:

EventAffectedUnaffected
Chat WebSocket dropsServer 'chat' → reconnectingServer 'bas' (SignalR) continues normally
BAS SignalR errorServer 'bas' → errorServer 'chat', Server 'audit' unaffected
stream.stop()ALL servers disconnected concurrentlyN/A
start() and stop() Are Global stream.start() connects ALL registered servers concurrently via Promise.all. stream.stop() disconnects ALL servers concurrently. To connect/disconnect a single server independently, call server.start() or server.stop() directly on the server reference.
Next: Observability Learn how to monitor hook activity, subscriber delivery, and pipeline health in real-time using EdgeStream's observability hooks. See Guide 7: Observability.