import type { RuntimeStore } from '../runtime/store/index.js'; import type { RuntimeEventBus, RuntimeEventDomain } from '../runtime/events/index.js'; import type { ControlPlaneClientDescriptor, ControlPlaneServerConfig, ControlPlaneStreamClientKind, ControlPlaneSurfaceMessage } from './types.js'; import { type FeatureFlagReader } from '../runtime/feature-flags/index.js'; import { DEFAULT_DOMAINS, type ControlPlaneRecentEvent } from './gateway-utils.js'; export type { ControlPlaneRecentEvent } from './gateway-utils.js'; export interface ControlPlaneGatewayConfig { readonly runtimeBus?: RuntimeEventBus | null | undefined; readonly runtimeStore?: RuntimeStore | null | undefined; readonly server?: Partial | undefined; readonly featureFlags?: FeatureFlagReader | undefined; } export interface ControlPlaneEventStreamOptions { readonly clientId?: string | undefined; readonly clientKind?: ControlPlaneStreamClientKind; readonly transport?: 'local' | 'http' | 'sse' | 'ws' | 'webhook' | undefined; readonly label?: string | undefined; readonly domains?: readonly RuntimeEventDomain[] | undefined; readonly principalId?: string | undefined; readonly principalKind?: 'user' | 'bot' | 'service' | 'token' | undefined; readonly scopes?: readonly string[] | undefined; /** Admin token, scopes collapse; sees all channels. */ readonly admin?: boolean | undefined; readonly sessionId?: string | undefined; /** Deliver only `sessionId`'s frames; see {@link createScopedSessionDelivery}. */ readonly sessionScopedDelivery?: boolean | undefined; readonly routeId?: string | undefined; readonly surfaceId?: string | undefined; readonly remoteAddress?: string | undefined; readonly capabilities?: readonly string[] | undefined; /** SSE keep-alive interval (ms); defaults to SSE_HEARTBEAT_INTERVAL_MS. First heartbeat always fires on open. */ readonly heartbeatIntervalMs?: number | undefined; } interface LiveControlPlaneClient { readonly clientId: string; readonly kind: ControlPlaneStreamClientKind; readonly surfaceId?: string | undefined; readonly routeId?: string | undefined; /** Principal scopes (SSE/WS); `admin` collapses scopes (sees every channel). */ readonly scopes?: readonly string[] | undefined; readonly admin?: boolean | undefined; /** * Subscribed domains for the broadcast (`publishEvent`) fan-out. `null` = * deliver-all (client did not opt into narrowing); a non-null set narrows to * tagged events in the set. For WS this is a live ref to the subscription set. */ readonly domains: ReadonlySet | null; readonly send: (event: string, payload: unknown, id?: string) => void; } export declare class ControlPlaneGateway { private runtimeBus; private dispatch; private readonly serverConfig; private readonly featureFlags; private readonly clients; private readonly liveClients; private readonly websocketClients; private readonly recentMessages; private readonly _recentEventsRing; private _recentEventsHead; private _recentEventsCount; private readonly _recentEventsCapacity; /** Materialized newest-first view of the recent event ring buffer. */ private get recentEvents(); private requestCount; private errorCount; private lastRequestAt; private _syncScheduled; private _lastEventAt; constructor(config?: ControlPlaneGatewayConfig); private isEnabled; private requireEnabled; attachRuntime(config: { readonly runtimeBus?: RuntimeEventBus | null | undefined; readonly runtimeStore?: RuntimeStore | null | undefined; }): void; listClients(): ControlPlaneClientDescriptor[]; getSnapshot(): Record; listSurfaceMessages(limit?: number): ControlPlaneSurfaceMessage[]; listRecentEvents(limit?: number): ControlPlaneRecentEvent[]; publishSurfaceMessage(input: Omit): ControlPlaneSurfaceMessage; publishEvent(event: string, payload: unknown, filter?: { readonly clientKind?: LiveControlPlaneClient['kind'] | undefined; readonly clientId?: string | undefined; readonly routeId?: string | undefined; readonly surfaceId?: string | undefined; }): void; recordApiRequest(input: { readonly method: string; readonly path: string; readonly status: number; readonly clientKind?: ControlPlaneEventStreamOptions['clientKind'] | undefined; readonly error?: string | undefined; }): void; setServerState(patch: Partial): void; openWebSocketClient(options: ControlPlaneEventStreamOptions, send: (event: string, payload: unknown, id?: string) => void): { clientId: string; domains: readonly RuntimeEventDomain[]; }; touchWebSocketClient(clientId: string, metadata?: Record): void; authenticateClient(clientId: string, input: { readonly principalId: string; readonly principalKind?: 'user' | 'bot' | 'service' | 'token' | undefined; readonly scopes?: readonly string[] | undefined; readonly label?: string | undefined; readonly capabilities?: readonly string[] | undefined; }): void; subscribeWebSocketClient(clientId: string, domains: readonly RuntimeEventDomain[]): void; unsubscribeWebSocketClient(clientId: string, domains?: readonly RuntimeEventDomain[]): void; closeWebSocketClient(clientId: string, reason?: string): void; createEventStream(request: Request, options?: ControlPlaneEventStreamOptions): Response; renderWebUi(authTokenHint?: string): Response; private _scheduleControlPlaneSync; /** Retained replay/message entries (ring + surface messages), for MemoryGovernor visibility. */ retainedEventCount(): number; /** * MemoryGovernor trim hook, a REAL reclaim. `floor` halves the retained * replay history (keeps the newest half of the ring); `flush` clears the * replay ring and the surface-message buffer entirely. Replay after a flush * degrades honestly: reconnecting clients simply get no replayed backlog. */ trimRetainedEvents(level: 'floor' | 'flush'): void; private rememberEvent; } export { DEFAULT_DOMAINS as DEFAULT_DOMAINS_TEST_EXPORT }; //# sourceMappingURL=gateway.d.ts.map