Portal Community

Architectural Layers

EdgeStream is organized into five distinct layers. Each layer has a single responsibility and communicates with adjacent layers through TypeScript interfaces — making every layer independently testable and replaceable.

LayerComponentsResponsibility
FacadeEdgeStream, IEdgeStreamOrchestrates all servers, exposes the top-level API
ServerServer, IServerSingle connection context — transport + pipelines + subscriptions
PipelineIncomingPipeline, OutgoingPipelineOrdered hook execution with abort/pause support
HooksIHook, built-in hooksComposable message transformers and interceptors
TransportSignalRTransport, SseTransport, RawWebSocketTransportLow-level network I/O — raw bytes in and out

The EdgeStream Facade

The EdgeStream class is the entry point. It owns a Map<string, IServer> of registered servers and delegates all operations to the appropriate server instance.

// EdgeStream facade — top-level orchestrator
export class EdgeStream implements IEdgeStream {
  readonly servers: Map<string, IServer> = new Map();
  status: EdgeStreamStatus = 'idle';

  // Starts all registered servers concurrently
  async start(): Promise<void> {
    const startPromises = Array.from(this.servers.values()).map(s => s.start());
    await Promise.all(startPromises);
    this.status = 'running';
    this.emit('stream:started', { timestamp: new Date() });
  }

  // Register a new server with transport config
  registerServer(registration: IServerRegistration): void {
    const transport = createTransport(registration.transportConfig);
    const server = new Server(registration, transport);
    this.servers.set(registration.id, server);
  }
}

Server: The Central Broker

Each IServer instance is an isolated message domain. It holds:

Server types are typed as 'bas' (BizFirstGO Application Server) or 'chat', allowing different pipeline configurations per domain.

Pipeline Engine

The pipeline is the ordered execution engine. IncomingPipeline handles messages from the transport; OutgoingPipeline handles messages being sent. Both share the same hook execution model:

1

Create Pipeline Context

A new IPipelineContext is created for each message containing the envelope, metadata map, and abort/pause controls.

2

Sort Hooks by Priority

Hooks are sorted by their priority number (lower runs first). HookActivityLogger uses priority 5 to run before all others.

3

Execute Each Hook

Each hook receives the context and returns a HookResult. If continue: false, the pipeline aborts and no further hooks run.

4

Publish to Subscribers

After all hooks pass, the SubscriptionManager.publish() delivers the envelope to all matching subscribers.

Hook System

Hooks are the extension point of EdgeStream. Every hook implements IHook:

export interface IHook<TContext extends IPipelineContext = IPipelineContext> {
  readonly name: string;
  readonly priority: number;   // lower number = runs first
  execute(context: TContext): Promise<HookResult>;
}

export interface HookResult {
  continue: boolean;   // false = abort pipeline (message dropped)
  paused?: boolean;    // true = pipeline paused awaiting user input
  error?: string;      // optional error message for logging
}

The pipeline context allows hooks to transform the message body, set metadata, add attributes, or abort/pause processing:

export interface IPipelineContext<TBody = unknown> {
  readonly envelope: IEnvelope<TBody>;
  readonly serverId: string;
  body: TBody;                              // hooks mutate this
  metadata: Record<string, unknown>;       // shared between hooks
  abort(reason?: string): void;
  readonly isAborted: boolean;
  pause(request: IUserInputRequest): IPipelinePause;
  readonly isPaused: boolean;
}

Transport Abstraction

All transports implement ITransport — a uniform interface for connect/disconnect/send/receive regardless of the underlying protocol:

TransportType KeyDuplexAuto-ReconnectUse Case
SignalRTransport'signalr'YesYes (built-in)Browser apps, recommended default
RawWebSocketTransport'websocket'YesManualPerformance-critical, non-browser
SseTransport'sse'Server-onlyYes (EventSource)Read-only event streams, firewall fallback
HttpPollingTransport'http-polling'EmulatedYesRestricted environments, no WS support

Event System

The EdgeStream facade emits typed lifecycle events that applications can subscribe to:

const stream = createEdgeStream();

stream.on('stream:started', (event) => console.log('Started', event.timestamp));
stream.on('server:connected', (event) => console.log('Server connected', event.serverId));
stream.on('server:error', (event) => console.error('Server error', event.data?.error));
stream.on('pipeline:paused', (event) => console.log('Waiting for user input'));
stream.on('message:received', (event) => updateMessageCount());

Available events: stream:started, stream:stopped, stream:error, server:connected, server:disconnected, server:error, pipeline:paused, pipeline:resumed, message:received, message:sent