TypeScript-First Design
EdgeStream is built with strict TypeScript 5.3+ throughout. Generics flow from the envelope through hooks to subscribers — giving you compile-time safety at every step.
Strict Type Configuration
EdgeStream uses strict TypeScript settings across all packages. The tsconfig enforces no implicit any, strict null checks, and exact optional property types:
// tsconfig.base.json
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"exactOptionalPropertyTypes": true,
"noUncheckedIndexedAccess": true
}
}
Generic Envelope — Type Safety End to End
The IEnvelope<TBody> generic parameter flows from subscription registration all the way to the callback. Define your message type once; TypeScript enforces it everywhere.
// 1. Define your message shape
interface WorkflowNodeEvent {
nodeId: string;
eventType: 'started' | 'completed' | 'failed';
status: 'running' | 'success' | 'error';
output?: Record<string, unknown>;
error?: { message: string; stack?: string };
durationMs?: number;
}
// 2. Subscribe with typed envelope
const sub = edgeStream.subscribe<WorkflowNodeEvent>(
'bas',
'workflow.execution.*',
(envelope: IEnvelope<WorkflowNodeEvent>) => {
// body is typed as WorkflowNodeEvent
const { nodeId, eventType, output } = envelope.body; // ✅ fully typed
const topic = envelope.meta.topic; // ✅ string
const at = envelope.meta.receivedAt; // ✅ Date
}
);
Interface-First Design
Every major component in EdgeStream is defined as an interface first, with implementation classes depending on those interfaces. This enables clean testing and custom implementations:
// Core interfaces
IEdgeStream // top-level facade
IServer // single server/domain
ITransport // network layer
IHook // pipeline processor
IPipelineContext // hook execution context
ISubscription // subscription handle
ISubscriptionManager // pub/sub registry
IPipelineObserver // observability sink
Typed Hook Context
Hook implementations can extend IPipelineContext with domain-specific context types using TypeScript generics:
// Custom context for auth hooks
interface IAuthPipelineContext extends IPipelineContext {
readonly claims: JwtClaims;
readonly tenantId: string;
}
// Typed hook using custom context
class AuthorizationHook implements IHook<IAuthPipelineContext> {
readonly name = 'AuthorizationHook';
readonly priority = 30;
async execute(context: IAuthPipelineContext): Promise<HookResult> {
if (!context.claims.roles.includes('workflow.read')) {
context.abort('Insufficient permissions');
return { continue: false };
}
return { continue: true };
}
}
Discriminated Unions for Events
EdgeStream event types are discriminated unions — exhaustive switch handling with TypeScript's type narrowing:
type AgentStreamEvent =
| { eventType: 'token'; token: string }
| { eventType: 'tool-call'; toolName: string; args: Record<string, unknown> }
| { eventType: 'tool-result'; result: unknown }
| { eventType: 'error'; message: string }
| { eventType: 'done' };
edgeStream.subscribe<AgentStreamEvent>('bas', 'agent.chat.*', (envelope) => {
const event = envelope.body;
switch (event.eventType) {
case 'token':
appendToken(event.token); // event.token: string ✅
break;
case 'tool-call':
startTool(event.toolName); // event.toolName: string ✅
break;
case 'done':
markComplete();
break;
// TypeScript warns if you miss a case
}
});
Transport Status as Union Type
type TransportStatus = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';
type EdgeStreamStatus = 'idle' | 'starting' | 'running' | 'stopping' | 'error';
type TransportType = 'signalr' | 'http-polling' | 'sse' | 'websocket';
type ServerType = 'bas' | 'chat';
type EnvelopeProtocol = 'json' | 'didcomm-v2' | 'cloudevents' | 'custom';
Type-Only Imports
EdgeStream uses import type throughout to minimize compiled output and make tree-shaking more effective:
// Internal usage in EdgeStream.ts
import type {
IEdgeStream,
EdgeStreamConfig,
EdgeStreamStatus,
IServer,
ISubscription,
SubscriberCallback,
} from './types';
edge-stream-js/index.ts via export * from './types'. Import them with import type { IEnvelope, IHook } from 'edge-stream-js' for zero runtime cost.