/** * EventRouter implementation. * * Mirrors ConnectRPC's ConnectRouter pattern for event handlers. * Iterates service methods, resolves topics, creates entries. * * @module EventRouter */ import type { DescService } from "@bufbuild/protobuf"; import { resolveTopicName } from "./topic.ts"; import type { EventHandlerConfig, EventMiddleware, EventRouteEntry, EventRouter, ServiceEventHandlers, TypedEventHandler } from "./types.ts"; /** * EventRouter implementation that collects route entries. */ export class EventRouterImpl implements EventRouter { readonly entries: EventRouteEntry[] = []; readonly serviceNames: string[] = []; service(serviceDesc: S, handlers: ServiceEventHandlers): void { this.serviceNames.push(serviceDesc.typeName); for (const method of serviceDesc.methods) { const handlerOrConfig = (handlers as Record | EventHandlerConfig>)[method.localName]; if (!handlerOrConfig) { throw new Error(`Missing event handler for method "${method.localName}" in service "${serviceDesc.typeName}"`); } let handler: TypedEventHandler; let perHandlerMiddleware: EventMiddleware[] | undefined; if (typeof handlerOrConfig === "function") { handler = handlerOrConfig; } else { if (typeof handlerOrConfig.handler !== "function") { throw new Error(`Invalid event handler config for method "${method.localName}" in service "${serviceDesc.typeName}": "handler" must be a function`); } handler = handlerOrConfig.handler; perHandlerMiddleware = handlerOrConfig.middleware; } const topic = resolveTopicName(method); const entry: EventRouteEntry = perHandlerMiddleware !== undefined ? { topic, method, handler, middleware: perHandlerMiddleware } : { topic, method, handler }; this.entries.push(entry); } } }