@eventmsg/core
Version:
EventMsgV3 TypeScript library - Core protocol implementation with transport abstraction
1 lines • 35.1 kB
Source Map (JSON)
{"version":3,"file":"event-msg.cjs","names":["EventEmitter","DEFAULT_CONFIG","Protocol","getLogger","INTERNAL_EVENTS","ConnectionError","DisconnectionError","hexDump","SendError","internalHandler","pendingWait: PendingWait<TData>","WaitForTimeoutError","AddressValidationError","ValidationError","metadata: MessageMetadata","eventData: unknown","messageResult: MessageResult<unknown>","messageInfo: MessageInfo","TransportError"],"sources":["../src/event-msg.ts"],"sourcesContent":["import { EventEmitter } from \"eventemitter3\";\nimport { ValidationError } from \"./errors/protocol-error.js\";\nimport { WaitForTimeoutError } from \"./errors/timeout-error.js\";\nimport {\n ConnectionError,\n DisconnectionError,\n SendError,\n TransportError,\n} from \"./errors/transport-error.js\";\nimport { AddressValidationError } from \"./errors/validation-error.js\";\nimport { configureLogging, getLogger, hexDump } from \"./internal/logger.js\";\nimport { Protocol } from \"./protocol.js\";\nimport type { EventMsgConfig } from \"./types/config.js\";\nimport { DEFAULT_CONFIG } from \"./types/config.js\";\nimport {\n type ConnectionStats,\n INTERNAL_EVENTS,\n type MessageHandler,\n type MessageInfo,\n} from \"./types/events.js\";\nimport type {\n MessageMetadata,\n MessageResult,\n PendingWait,\n SendOptions,\n WaitForOptions,\n} from \"./types/message.js\";\nimport type { Transport } from \"./types/transport.js\";\n\n/**\n * EventMsg - Main class for EventMsgV3 protocol communication\n *\n * Provides type-safe messaging with per-method generics, async event handling,\n * and transport abstraction.\n */\nexport class EventMsg<TDevice = unknown> extends EventEmitter {\n private readonly transport: Transport<TDevice>;\n protocol: Protocol;\n private readonly logger: ReturnType<typeof getLogger>;\n messageCounter = 0;\n private readonly config: Required<Omit<EventMsgConfig<TDevice>, \"transport\">>;\n private connectionState = false;\n private connectTime: Date | undefined;\n private readonly pendingWaits: Map<string, PendingWait[]> = new Map();\n private readonly stats: ConnectionStats;\n\n // Track message handlers for proper cleanup\n private readonly messageHandlers = new Map<\n string | symbol,\n ((messageInfo: MessageInfo) => void)[]\n >();\n\n constructor(config: EventMsgConfig<TDevice>) {\n super();\n\n // Merge with defaults\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.transport = config.transport;\n\n // Configure logging BEFORE creating Protocol or getting any loggers\n configureLogging(this.config.logging);\n\n // Now create Protocol (which will use the configured logger)\n this.protocol = new Protocol({ ...this.config, transport: this.transport });\n\n // Get logger for this component\n this.logger = getLogger(\"CORE\");\n\n // Initialize stats\n this.stats = {\n messagesSent: 0,\n messagesReceived: 0,\n uptime: 0,\n connected: false,\n };\n\n // Bind transport events\n this.setupTransportHandlers();\n }\n\n /**\n * Connect to the transport layer\n */\n async connect(): Promise<void> {\n try {\n if (this.connectionState) {\n return; // Already connected\n }\n\n await this.transport.connect();\n this.connectionState = true;\n this.connectTime = new Date();\n this.stats.connected = true;\n\n this.emit(INTERNAL_EVENTS.CONNECT);\n\n this.logger.success(\"Connected to transport\", {\n localAddress: this.transport.getLocalAddress(),\n groupAddress: this.transport.getGroupAddress(),\n uptime: 0,\n });\n } catch (error) {\n this.logger.error(\"Failed to connect to transport\", {\n error: error instanceof Error ? error.message : String(error),\n localAddress: this.transport.getLocalAddress(),\n groupAddress: this.transport.getGroupAddress(),\n cause: error instanceof Error ? error.name : \"Unknown\",\n });\n\n const transportError = new ConnectionError(\n \"Failed to connect to transport\",\n {\n context: {\n localAddress: this.transport.getLocalAddress(),\n groupAddress: this.transport.getGroupAddress(),\n },\n cause: error instanceof Error ? error : new Error(String(error)),\n }\n );\n\n this.emit(INTERNAL_EVENTS.ERROR, transportError);\n throw transportError;\n }\n }\n\n /**\n * Disconnect from the transport layer\n */\n async disconnect(): Promise<void> {\n try {\n if (!this.connectionState) {\n return; // Already disconnected\n }\n\n // Clear all pending waits\n this.clearAllPendingWaits();\n\n // Clear all message handlers\n this.offMessage();\n\n await this.transport.disconnect();\n this.connectionState = false;\n\n this.stats.connected = false;\n\n this.emit(INTERNAL_EVENTS.DISCONNECT);\n\n this.logger.info(\"Disconnected from transport\", {\n uptime: this.connectTime ? Date.now() - this.connectTime.getTime() : 0,\n messagesSent: this.stats.messagesSent,\n messagesReceived: this.stats.messagesReceived,\n });\n } catch (error) {\n this.logger.error(\"Failed to disconnect from transport\", {\n error: error instanceof Error ? error.message : String(error),\n cause: error instanceof Error ? error.name : \"Unknown\",\n uptime: this.connectTime ? Date.now() - this.connectTime.getTime() : 0,\n });\n\n const transportError = new DisconnectionError(\n \"Failed to disconnect from transport\",\n {\n cause: error instanceof Error ? error : new Error(String(error)),\n }\n );\n\n this.emit(INTERNAL_EVENTS.ERROR, transportError);\n throw transportError;\n }\n }\n\n /**\n * Check if currently connected\n */\n isConnected(): boolean {\n return this.connectionState && this.transport.isConnected();\n }\n\n /**\n * Send a message with explicit receiver targeting\n */\n async send<TData = unknown>(\n event: string,\n data: TData,\n options: SendOptions\n ): Promise<void> {\n try {\n // Validate connection\n if (!this.isConnected()) {\n throw new ConnectionError(\"Not connected to transport\");\n }\n\n // Validate inputs\n this.validateSendOptions(options);\n\n // Create message header\n const header = this.createHeader(options);\n\n // TODO: Check if we need type specific handle for event data (JSON, ARRAY)\n const eventData = data as string;\n\n // Encode message\n const encodedMessage = this.protocol.encode(header, event, eventData);\n\n this.logger.debug(\"Message encoded\", {\n event,\n header,\n dataLength: eventData.length,\n encodedSize: encodedMessage.length,\n });\n\n // Log hex dump at trace level\n this.logger.trace(\"Encoded message hex dump\", {\n hex: hexDump(encodedMessage),\n });\n // Send through transport\n await this.transport.send(encodedMessage);\n\n // Update stats\n this.stats.messagesSent++;\n\n // Log successful send\n this.logger.info(\"Message sent\", {\n event,\n receiverId: options.receiverId,\n receiverGroupId: options.receiverGroupId,\n messageId: header.messageId,\n size: encodedMessage.length,\n totalSent: this.stats.messagesSent,\n });\n\n // Emit send event for debugging\n this.emit(INTERNAL_EVENTS.SEND, {\n event,\n data,\n options,\n header,\n messageSize: encodedMessage.length,\n });\n } catch (error) {\n this.logger.error(\"Failed to send message\", {\n error: error instanceof Error ? error.message : String(error),\n event,\n receiverId: options.receiverId,\n receiverGroupId: options.receiverGroupId,\n dataLength: JSON.stringify(data).length,\n cause: error instanceof Error ? error.name : \"Unknown\",\n });\n\n const sendError = new SendError(\"Failed to send message\", {\n context: {\n event,\n receiverId: options.receiverId,\n receiverGroupId: options.receiverGroupId,\n dataLength: JSON.stringify(data).length,\n },\n cause: error instanceof Error ? error : new Error(String(error)),\n });\n\n this.emit(INTERNAL_EVENTS.ERROR, sendError);\n throw sendError;\n }\n }\n\n /**\n * Send binary data with explicit receiver targeting\n */\n async sendBinary(\n event: string,\n data: Uint8Array,\n options: SendOptions\n ): Promise<void> {\n try {\n if (!this.isConnected()) {\n throw new ConnectionError(\"Not connected to transport\");\n }\n\n this.validateSendOptions(options);\n\n const header = this.createHeader(options);\n\n const encodedMessage = this.protocol.encodeBinary(header, event, data);\n\n this.logger.debug(\"Binary message encoded\", {\n event,\n header,\n dataLength: data.length,\n encodedSize: encodedMessage.length,\n });\n\n this.logger.trace(\"Encoded binary message hex dump\", {\n hex: hexDump(encodedMessage),\n });\n\n await this.transport.send(encodedMessage);\n\n this.stats.messagesSent++;\n\n this.logger.info(\"Binary message sent\", {\n event,\n receiverId: options.receiverId,\n receiverGroupId: options.receiverGroupId,\n messageId: header.messageId,\n size: encodedMessage.length,\n totalSent: this.stats.messagesSent,\n });\n\n this.emit(INTERNAL_EVENTS.SEND, {\n event,\n data,\n options,\n header,\n messageSize: encodedMessage.length,\n });\n } catch (error) {\n this.logger.error(\"Failed to send binary message\", {\n error: error instanceof Error ? error.message : String(error),\n event,\n receiverId: options.receiverId,\n receiverGroupId: options.receiverGroupId,\n dataLength: data.length,\n cause: error instanceof Error ? error.name : \"Unknown\",\n });\n\n const sendError = new SendError(\"Failed to send binary message\", {\n context: {\n event,\n receiverId: options.receiverId,\n receiverGroupId: options.receiverGroupId,\n dataLength: data.length,\n },\n cause: error instanceof Error ? error : new Error(String(error)),\n });\n\n this.emit(INTERNAL_EVENTS.ERROR, sendError);\n throw sendError;\n }\n }\n\n /**\n * Register a type-safe event handler\n */\n override on<TData = unknown>(\n event: string | symbol,\n handler: MessageHandler<TData>\n ): this {\n return super.on(event, handler);\n }\n\n /**\n * Register a one-time type-safe event handler\n */\n override once<TData = unknown>(\n event: string | symbol,\n handler: MessageHandler<TData>\n ): this {\n return super.once(event, handler);\n }\n\n /**\n * Remove a type-safe event handler\n */\n override off<TData = unknown>(\n event: string | symbol,\n handler?: MessageHandler<TData>\n ): this {\n if (handler) {\n return super.off(event, handler);\n }\n return super.removeAllListeners(event);\n }\n\n /**\n * Register a handler for all incoming user messages\n * @param handler - Function called for every incoming message\n * @returns Unsubscribe function to remove this specific handler\n * @example\n * ```typescript\n * const unsubscribe = eventMsg.onMessage((eventName, data, metadata) => {\n * console.log(`Received ${eventName} from device ${metadata.senderId}`);\n * });\n * // Later: unsubscribe();\n * ```\n */\n onMessage(\n handler: (\n eventName: string,\n data: unknown,\n metadata: MessageMetadata\n ) => void\n ): () => void;\n /**\n * Register a handler for a specific message event type\n * @param eventName - The specific event name to listen for\n * @param handler - Function called when the specific event is received\n * @returns Unsubscribe function to remove this specific handler\n * @example\n * ```typescript\n * const unsubscribe = eventMsg.onMessage('ping', (data, metadata) => {\n * console.log(`Ping from device ${metadata.senderId}: ${data}`);\n * });\n * // Later: unsubscribe();\n * ```\n */\n onMessage<TData = unknown>(\n eventName: string,\n handler: (data: TData, metadata: MessageMetadata) => void\n ): () => void;\n onMessage<TData = unknown>(\n eventNameOrHandler:\n | string\n | ((eventName: string, data: unknown, metadata: MessageMetadata) => void),\n handler?: (data: TData, metadata: MessageMetadata) => void\n ): () => void {\n if (typeof eventNameOrHandler === \"string\") {\n // Specific event subscription\n const targetEventName = eventNameOrHandler;\n const specificHandler = handler;\n\n const internalHandler = (messageInfo: MessageInfo) => {\n if (messageInfo.eventName === targetEventName && specificHandler) {\n // Type assertion is safe here because user controls TData generic\n specificHandler(messageInfo.data as TData, messageInfo.metadata);\n }\n };\n\n this.on(INTERNAL_EVENTS.MESSAGE, internalHandler);\n this.trackMessageHandler(targetEventName, internalHandler);\n\n return () => {\n this.off(INTERNAL_EVENTS.MESSAGE, internalHandler);\n const handlers = this.messageHandlers.get(targetEventName);\n if (handlers) {\n const index = handlers.indexOf(internalHandler);\n if (index > -1) {\n handlers.splice(index, 1);\n if (handlers.length === 0) {\n this.messageHandlers.delete(targetEventName);\n }\n }\n }\n };\n }\n // Catch-all subscription\n const catchAllHandler = eventNameOrHandler;\n const catchAllKey = Symbol(\"catch-all\");\n\n const internalHandler = (messageInfo: MessageInfo) => {\n catchAllHandler(\n messageInfo.eventName,\n messageInfo.data,\n messageInfo.metadata\n );\n };\n\n this.on(INTERNAL_EVENTS.MESSAGE, internalHandler);\n this.trackMessageHandler(catchAllKey, internalHandler);\n\n return () => {\n this.off(INTERNAL_EVENTS.MESSAGE, internalHandler);\n const handlers = this.messageHandlers.get(catchAllKey);\n if (handlers) {\n const index = handlers.indexOf(internalHandler);\n if (index > -1) {\n handlers.splice(index, 1);\n if (handlers.length === 0) {\n this.messageHandlers.delete(catchAllKey);\n }\n }\n }\n };\n }\n\n /**\n * Remove message handlers\n * @param eventName - The event name to stop listening for\n * @returns this instance for chaining\n * @warning When called without arguments, removes ALL message handlers from ALL events.\n * Prefer using the unsubscribe function returned by onMessage() for targeted cleanup.\n * @example\n * ```typescript\n * // Preferred: use unsubscribe function from onMessage()\n * const unsubscribe = eventMsg.onMessage('ping', handler);\n * unsubscribe(); // Removes only this handler\n *\n * // Remove all handlers for a specific event\n * eventMsg.offMessage('ping');\n *\n * // Remove ALL message handlers (use with caution)\n * eventMsg.offMessage();\n * ```\n */\n offMessage(eventName?: string): this {\n if (eventName) {\n // Remove specific event handlers\n const handlers = this.messageHandlers.get(eventName);\n if (handlers) {\n for (const handler of handlers) {\n this.off(INTERNAL_EVENTS.MESSAGE, handler);\n }\n this.messageHandlers.delete(eventName);\n }\n } else {\n // Remove all message handlers\n for (const [, handlers] of this.messageHandlers) {\n for (const handler of handlers) {\n this.off(INTERNAL_EVENTS.MESSAGE, handler);\n }\n }\n this.messageHandlers.clear();\n }\n\n return this;\n }\n\n /**\n * Track message handlers for proper cleanup\n */\n private trackMessageHandler(\n key: string | symbol,\n handler: (messageInfo: MessageInfo) => void\n ): void {\n if (!this.messageHandlers.has(key)) {\n this.messageHandlers.set(key, []);\n }\n this.messageHandlers.get(key)?.push(handler);\n }\n\n /**\n * Wait for a single event occurrence with timeout\n */\n waitFor<TData = unknown>(\n event: string,\n options: WaitForOptions = {}\n ): Promise<MessageResult<TData>> {\n return new Promise((resolve, reject) => {\n const timeout = options.timeout ?? this.config.messageTimeout;\n\n const pendingWait: PendingWait<TData> = {\n resolve,\n reject,\n timeout: setTimeout(() => {\n this.removePendingWait(event, pendingWait);\n reject(new WaitForTimeoutError(event, timeout));\n }, timeout),\n filter: options.filter ?? undefined,\n };\n\n this.addPendingWait(event, pendingWait);\n\n this.logger.debug(\"Waiting for event\", {\n event,\n timeout,\n hasFilter: !!options.filter,\n pendingWaits: this.pendingWaits.get(event)?.length ?? 0,\n });\n });\n }\n\n /**\n * Get local device address from transport\n */\n getLocalAddress(): number {\n return this.transport.getLocalAddress();\n }\n\n /**\n * Get local group address from transport\n */\n getGroupAddress(): number {\n return this.transport.getGroupAddress();\n }\n\n /**\n * Get connection statistics\n */\n getStats(): ConnectionStats {\n return {\n ...this.stats,\n uptime: this.connectTime ? Date.now() - this.connectTime.getTime() : 0,\n };\n }\n\n /**\n * Get the underlying transport instance\n */\n getTransport(): Transport<TDevice> {\n return this.transport;\n }\n\n /**\n * Get the connected device from transport\n */\n getDevice(): TDevice | null {\n return this.transport.getDevice();\n }\n\n /**\n * Create message header from send options\n */\n private createHeader(\n options: SendOptions\n ): import(\"./types/message.js\").MessageHeader {\n return {\n senderId: this.transport.getLocalAddress(),\n receiverId: options.receiverId,\n senderGroupId: this.transport.getGroupAddress(),\n receiverGroupId: options.receiverGroupId ?? 0x00,\n flags: options.flags ?? 0x00,\n messageId: ++this.messageCounter & 0xff_ff, // Wrap at 16-bit\n };\n }\n\n /**\n * Validate send options\n */\n private validateSendOptions(options: SendOptions): void {\n if (\n options.receiverId < 0 ||\n options.receiverId > 255 ||\n !Number.isInteger(options.receiverId)\n ) {\n throw new AddressValidationError(options.receiverId, \"receiverId\");\n }\n\n if (\n options.receiverGroupId !== undefined &&\n (options.receiverGroupId < 0 ||\n options.receiverGroupId > 255 ||\n !Number.isInteger(options.receiverGroupId))\n ) {\n throw new AddressValidationError(\n options.receiverGroupId,\n \"receiverGroupId\"\n );\n }\n\n if (\n options.flags !== undefined &&\n (options.flags < 0 ||\n options.flags > 255 ||\n !Number.isInteger(options.flags))\n ) {\n throw new ValidationError(\"flags must be 0-255\", {\n context: {\n field: \"flags\",\n value: options.flags,\n },\n });\n }\n }\n\n /**\n * Setup transport event handlers\n */\n private setupTransportHandlers(): void {\n this.transport.on(\"data\", this.handleIncomingData.bind(this));\n this.transport.on(\"error\", this.handleTransportError.bind(this));\n this.transport.on(\"disconnect\", this.handleTransportDisconnect.bind(this));\n }\n\n /**\n * Handle incoming transport data\n */\n private handleIncomingData(data: Uint8Array): void {\n try {\n // Decode message\n const decoded = this.protocol.decode(data);\n\n // Create metadata\n const metadata: MessageMetadata = {\n senderId: decoded.header.senderId,\n senderGroupId: decoded.header.senderGroupId,\n receiverId: decoded.header.receiverId,\n receiverGroupId: decoded.header.receiverGroupId,\n messageId: decoded.header.messageId,\n flags: decoded.header.flags,\n timestamp: new Date(),\n };\n\n // Parse event data\n let eventData: unknown;\n try {\n eventData = JSON.parse(decoded.eventData);\n } catch {\n eventData = decoded.eventData; // Fall back to string if not JSON\n }\n\n const messageResult: MessageResult<unknown> = {\n data: eventData,\n metadata,\n };\n\n // Update stats\n this.stats.messagesReceived++;\n\n // Log message received\n this.logger.info(\"Message received\", {\n event: decoded.eventName,\n senderId: metadata.senderId,\n senderGroupId: metadata.senderGroupId,\n messageId: metadata.messageId,\n size: data.length,\n totalReceived: this.stats.messagesReceived,\n });\n\n // Log hex dump at trace level\n this.logger.trace(\"Received message hex dump\", {\n hex: hexDump(data),\n });\n\n // Resolve pending waits\n this.resolvePendingWaits(decoded.eventName, messageResult);\n\n // Emit message event for onMessage handlers\n const messageInfo: MessageInfo = {\n eventName: decoded.eventName,\n data: eventData,\n metadata,\n messageSize: data.length,\n };\n\n this.emit(INTERNAL_EVENTS.MESSAGE, messageInfo);\n } catch (error) {\n this.logger.error(\"Failed to process incoming message\", {\n error: error instanceof Error ? error.message : String(error),\n messageLength: data.length,\n cause: error instanceof Error ? error.name : \"Unknown\",\n hex: hexDump(data, 64),\n });\n\n const protocolError = new TransportError(\n \"Failed to process incoming message\",\n {\n context: { messageLength: data.length },\n cause: error instanceof Error ? error : new Error(String(error)),\n }\n );\n\n this.emit(INTERNAL_EVENTS.ERROR, protocolError);\n }\n }\n\n /**\n * Handle transport errors\n */\n private handleTransportError(error: Error): void {\n this.logger.error(\"Transport error occurred\", {\n error: error.message,\n cause: error.name,\n connected: this.connectionState,\n uptime: this.connectTime ? Date.now() - this.connectTime.getTime() : 0,\n });\n\n const transportError = new TransportError(\"Transport error occurred\", {\n cause: error,\n });\n\n this.stats.lastError = new Date();\n this.emit(INTERNAL_EVENTS.ERROR, transportError);\n }\n\n /**\n * Handle transport disconnection\n */\n private handleTransportDisconnect(): void {\n const uptime = this.connectTime\n ? Date.now() - this.connectTime.getTime()\n : 0;\n\n this.logger.warn(\"Transport disconnected unexpectedly\", {\n uptime,\n messagesSent: this.stats.messagesSent,\n messagesReceived: this.stats.messagesReceived,\n pendingWaits: this.pendingWaits.size,\n });\n\n this.connectionState = false;\n this.connectTime = undefined;\n this.stats.connected = false;\n\n // Clear pending waits\n this.clearAllPendingWaits();\n\n this.emit(INTERNAL_EVENTS.DISCONNECT);\n }\n\n /**\n * Add a pending wait for an event\n */\n private addPendingWait<TData>(\n event: string,\n pendingWait: PendingWait<TData>\n ): void {\n if (!this.pendingWaits.has(event)) {\n this.pendingWaits.set(event, []);\n }\n this.pendingWaits.get(event)?.push(pendingWait as PendingWait<unknown>);\n }\n\n /**\n * Remove a pending wait\n */\n private removePendingWait<TData>(\n event: string,\n pendingWait: PendingWait<TData>\n ): void {\n const waits = this.pendingWaits.get(event);\n if (waits) {\n const index = waits.indexOf(pendingWait as PendingWait<unknown>);\n if (index !== -1) {\n clearTimeout(pendingWait.timeout);\n waits.splice(index, 1);\n\n if (waits.length === 0) {\n this.pendingWaits.delete(event);\n }\n }\n }\n }\n\n /**\n * Resolve pending waits for an event\n */\n private resolvePendingWaits(\n event: string,\n messageResult: MessageResult<unknown>\n ): void {\n const waits = this.pendingWaits.get(event);\n if (!waits || waits.length === 0) {\n return;\n }\n\n // Create a copy to iterate over, as we'll be modifying the original array\n const waitsToResolve = [...waits];\n\n for (const wait of waitsToResolve) {\n // Check filter condition\n if (wait.filter && !wait.filter(messageResult.metadata)) {\n continue; // Skip this wait, filter didn't match\n }\n\n // Remove from pending waits\n this.removePendingWait(event, wait);\n\n // Resolve the promise\n wait.resolve(messageResult);\n }\n }\n\n /**\n * Clear all pending waits (on disconnect)\n */\n private clearAllPendingWaits(): void {\n for (const [, waits] of this.pendingWaits.entries()) {\n for (const wait of waits) {\n clearTimeout(wait.timeout);\n wait.reject(\n new DisconnectionError(\"Connection lost while waiting for event\")\n );\n }\n }\n this.pendingWaits.clear();\n }\n}\n"],"mappings":"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"}