jmri-client 3.2.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,6 +13,7 @@ WebSocket client for [JMRI](http://jmri.sourceforge.net/) with real-time updates
13
13
  - ✅ **WebSocket-based** - Real-time bidirectional communication
14
14
  - ✅ **Event-driven** - Subscribe to power changes, throttle updates, and more
15
15
  - ✅ **Full Throttle Control** - Speed (0.0-1.0), direction, and functions (F0-F28)
16
+ - ✅ **Browser & Node.js** - Works in browsers and Node.js with auto-detection
16
17
  - ✅ **Mock Mode** - Test and demo without JMRI hardware
17
18
  - ✅ **Auto-reconnection** - Exponential backoff with jitter
18
19
  - ✅ **Heartbeat monitoring** - Automatic ping/pong keepalive
@@ -41,7 +42,9 @@ const client = new JmriClient({
41
42
  // Listen for events
42
43
  client.on('connected', () => console.log('Connected!'));
43
44
  client.on('power:changed', (state) => {
44
- console.log('Power:', state === PowerState.ON ? 'ON' : 'OFF');
45
+ const stateStr = state === PowerState.ON ? 'ON' :
46
+ state === PowerState.OFF ? 'OFF' : 'UNKNOWN';
47
+ console.log('Power:', stateStr);
45
48
  });
46
49
 
47
50
  // Control power
@@ -61,6 +64,7 @@ await client.disconnect();
61
64
  ## Documentation
62
65
 
63
66
  - **[API Reference](docs/API.md)** - Complete API documentation
67
+ - **[Browser Usage](docs/BROWSER.md)** - Using jmri-client in web browsers
64
68
  - **[Examples](docs/EXAMPLES.md)** - Common usage patterns
65
69
  - **[Mock Mode](docs/MOCK_MODE.md)** - Testing without hardware
66
70
  - **[Migration Guide](docs/MIGRATION.md)** - Upgrading from v2.x
@@ -601,11 +601,23 @@ var ReconnectionManager = class extends import_index.default {
601
601
 
602
602
  // src/types/jmri-messages.ts
603
603
  var PowerState = /* @__PURE__ */ ((PowerState2) => {
604
+ PowerState2[PowerState2["UNKNOWN"] = 0] = "UNKNOWN";
604
605
  PowerState2[PowerState2["ON"] = 2] = "ON";
605
606
  PowerState2[PowerState2["OFF"] = 4] = "OFF";
606
- PowerState2[PowerState2["UNKNOWN"] = 0] = "UNKNOWN";
607
607
  return PowerState2;
608
608
  })(PowerState || {});
609
+ function powerStateToString(state) {
610
+ switch (state) {
611
+ case 2 /* ON */:
612
+ return "ON";
613
+ case 4 /* OFF */:
614
+ return "OFF";
615
+ case 0 /* UNKNOWN */:
616
+ return "UNKNOWN";
617
+ default:
618
+ return "UNKNOWN";
619
+ }
620
+ }
609
621
 
610
622
  // src/mocks/mock-data.ts
611
623
  var mockData = {
@@ -1955,6 +1967,7 @@ export {
1955
1967
  isThrottleFunctionKey,
1956
1968
  isValidSpeed,
1957
1969
  mockData,
1958
- mockResponseManager
1970
+ mockResponseManager,
1971
+ powerStateToString
1959
1972
  };
1960
1973
  //# sourceMappingURL=jmri-client.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../node_modules/eventemitter3/index.js", "../../node_modules/ws/browser.js", "../../node_modules/eventemitter3/index.mjs", "../../src/core/websocket-adapter.ts", "../../src/types/events.ts", "../../src/utils/message-id.ts", "../../src/core/message-queue.ts", "../../src/core/connection-state-manager.ts", "../../src/core/heartbeat-manager.ts", "../../src/utils/exponential-backoff.ts", "../../src/core/reconnection-manager.ts", "../../src/types/jmri-messages.ts", "../../src/mocks/mock-data.ts", "../../src/mocks/mock-response-manager.ts", "../../src/core/websocket-client.ts", "../../src/managers/power-manager.ts", "../../src/managers/roster-manager.ts", "../../src/types/throttle.ts", "../../src/managers/throttle-manager.ts", "../../src/types/client-options.ts", "../../src/client.ts"],
4
- "sourcesContent": ["'use strict';\n\nvar has = Object.prototype.hasOwnProperty\n , prefix = '~';\n\n/**\n * Constructor to create a storage for our `EE` objects.\n * An `Events` instance is a plain object whose properties are event names.\n *\n * @constructor\n * @private\n */\nfunction Events() {}\n\n//\n// We try to not inherit from `Object.prototype`. In some engines creating an\n// instance in this way is faster than calling `Object.create(null)` directly.\n// If `Object.create(null)` is not supported we prefix the event names with a\n// character to make sure that the built-in object properties are not\n// overridden or used as an attack vector.\n//\nif (Object.create) {\n Events.prototype = Object.create(null);\n\n //\n // This hack is needed because the `__proto__` property is still inherited in\n // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.\n //\n if (!new Events().__proto__) prefix = false;\n}\n\n/**\n * Representation of a single event listener.\n *\n * @param {Function} fn The listener function.\n * @param {*} context The context to invoke the listener with.\n * @param {Boolean} [once=false] Specify if the listener is a one-time listener.\n * @constructor\n * @private\n */\nfunction EE(fn, context, once) {\n this.fn = fn;\n this.context = context;\n this.once = once || false;\n}\n\n/**\n * Add a listener for a given event.\n *\n * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} context The context to invoke the listener with.\n * @param {Boolean} once Specify if the listener is a one-time listener.\n * @returns {EventEmitter}\n * @private\n */\nfunction addListener(emitter, event, fn, context, once) {\n if (typeof fn !== 'function') {\n throw new TypeError('The listener must be a function');\n }\n\n var listener = new EE(fn, context || emitter, once)\n , evt = prefix ? prefix + event : event;\n\n if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;\n else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);\n else emitter._events[evt] = [emitter._events[evt], listener];\n\n return emitter;\n}\n\n/**\n * Clear event by name.\n *\n * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.\n * @param {(String|Symbol)} evt The Event name.\n * @private\n */\nfunction clearEvent(emitter, evt) {\n if (--emitter._eventsCount === 0) emitter._events = new Events();\n else delete emitter._events[evt];\n}\n\n/**\n * Minimal `EventEmitter` interface that is molded against the Node.js\n * `EventEmitter` interface.\n *\n * @constructor\n * @public\n */\nfunction EventEmitter() {\n this._events = new Events();\n this._eventsCount = 0;\n}\n\n/**\n * Return an array listing the events for which the emitter has registered\n * listeners.\n *\n * @returns {Array}\n * @public\n */\nEventEmitter.prototype.eventNames = function eventNames() {\n var names = []\n , events\n , name;\n\n if (this._eventsCount === 0) return names;\n\n for (name in (events = this._events)) {\n if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);\n }\n\n if (Object.getOwnPropertySymbols) {\n return names.concat(Object.getOwnPropertySymbols(events));\n }\n\n return names;\n};\n\n/**\n * Return the listeners registered for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Array} The registered listeners.\n * @public\n */\nEventEmitter.prototype.listeners = function listeners(event) {\n var evt = prefix ? prefix + event : event\n , handlers = this._events[evt];\n\n if (!handlers) return [];\n if (handlers.fn) return [handlers.fn];\n\n for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {\n ee[i] = handlers[i].fn;\n }\n\n return ee;\n};\n\n/**\n * Return the number of listeners listening to a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Number} The number of listeners.\n * @public\n */\nEventEmitter.prototype.listenerCount = function listenerCount(event) {\n var evt = prefix ? prefix + event : event\n , listeners = this._events[evt];\n\n if (!listeners) return 0;\n if (listeners.fn) return 1;\n return listeners.length;\n};\n\n/**\n * Calls each of the listeners registered for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Boolean} `true` if the event had listeners, else `false`.\n * @public\n */\nEventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {\n var evt = prefix ? prefix + event : event;\n\n if (!this._events[evt]) return false;\n\n var listeners = this._events[evt]\n , len = arguments.length\n , args\n , i;\n\n if (listeners.fn) {\n if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);\n\n switch (len) {\n case 1: return listeners.fn.call(listeners.context), true;\n case 2: return listeners.fn.call(listeners.context, a1), true;\n case 3: return listeners.fn.call(listeners.context, a1, a2), true;\n case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;\n case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;\n case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;\n }\n\n for (i = 1, args = new Array(len -1); i < len; i++) {\n args[i - 1] = arguments[i];\n }\n\n listeners.fn.apply(listeners.context, args);\n } else {\n var length = listeners.length\n , j;\n\n for (i = 0; i < length; i++) {\n if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);\n\n switch (len) {\n case 1: listeners[i].fn.call(listeners[i].context); break;\n case 2: listeners[i].fn.call(listeners[i].context, a1); break;\n case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;\n case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;\n default:\n if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {\n args[j - 1] = arguments[j];\n }\n\n listeners[i].fn.apply(listeners[i].context, args);\n }\n }\n }\n\n return true;\n};\n\n/**\n * Add a listener for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} [context=this] The context to invoke the listener with.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.on = function on(event, fn, context) {\n return addListener(this, event, fn, context, false);\n};\n\n/**\n * Add a one-time listener for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} [context=this] The context to invoke the listener with.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.once = function once(event, fn, context) {\n return addListener(this, event, fn, context, true);\n};\n\n/**\n * Remove the listeners of a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn Only remove the listeners that match this function.\n * @param {*} context Only remove the listeners that have this context.\n * @param {Boolean} once Only remove one-time listeners.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {\n var evt = prefix ? prefix + event : event;\n\n if (!this._events[evt]) return this;\n if (!fn) {\n clearEvent(this, evt);\n return this;\n }\n\n var listeners = this._events[evt];\n\n if (listeners.fn) {\n if (\n listeners.fn === fn &&\n (!once || listeners.once) &&\n (!context || listeners.context === context)\n ) {\n clearEvent(this, evt);\n }\n } else {\n for (var i = 0, events = [], length = listeners.length; i < length; i++) {\n if (\n listeners[i].fn !== fn ||\n (once && !listeners[i].once) ||\n (context && listeners[i].context !== context)\n ) {\n events.push(listeners[i]);\n }\n }\n\n //\n // Reset the array, or remove it completely if we have no more listeners.\n //\n if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;\n else clearEvent(this, evt);\n }\n\n return this;\n};\n\n/**\n * Remove all listeners, or those of the specified event.\n *\n * @param {(String|Symbol)} [event] The event name.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {\n var evt;\n\n if (event) {\n evt = prefix ? prefix + event : event;\n if (this._events[evt]) clearEvent(this, evt);\n } else {\n this._events = new Events();\n this._eventsCount = 0;\n }\n\n return this;\n};\n\n//\n// Alias methods names because people roll like that.\n//\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\nEventEmitter.prototype.addListener = EventEmitter.prototype.on;\n\n//\n// Expose the prefix.\n//\nEventEmitter.prefixed = prefix;\n\n//\n// Allow `EventEmitter` to be imported as module namespace.\n//\nEventEmitter.EventEmitter = EventEmitter;\n\n//\n// Expose the module.\n//\nif ('undefined' !== typeof module) {\n module.exports = EventEmitter;\n}\n", "'use strict';\n\nmodule.exports = function () {\n throw new Error(\n 'ws does not work in the browser. Browser clients must use the native ' +\n 'WebSocket object'\n );\n};\n", "import EventEmitter from './index.js'\n\nexport { EventEmitter }\nexport default EventEmitter\n", "/**\n * WebSocket Adapter\n * Provides a unified interface for WebSocket connections in both Node.js and browser environments\n */\n\nimport { EventEmitter } from 'eventemitter3';\n\n/**\n * WebSocket adapter interface\n */\nexport interface WebSocketAdapter extends EventEmitter {\n send(data: string): void;\n close(code?: number, reason?: string): void;\n readonly readyState: number;\n}\n\n/**\n * WebSocket ready states\n */\nexport enum ReadyState {\n CONNECTING = 0,\n OPEN = 1,\n CLOSING = 2,\n CLOSED = 3\n}\n\n/**\n * Create a WebSocket adapter for the current environment\n */\nexport async function createWebSocketAdapter(url: string, protocols?: string | string[]): Promise<WebSocketAdapter> {\n // Detect environment\n const isBrowser = typeof window !== 'undefined' && typeof window.WebSocket !== 'undefined';\n\n if (isBrowser) {\n return new BrowserWebSocketAdapter(url, protocols);\n } else {\n return await NodeWebSocketAdapter.create(url, protocols);\n }\n}\n\n/**\n * Browser WebSocket adapter\n * Wraps native browser WebSocket with EventEmitter interface\n */\nclass BrowserWebSocketAdapter extends EventEmitter implements WebSocketAdapter {\n private ws: WebSocket;\n\n constructor(url: string, protocols?: string | string[]) {\n super();\n\n this.ws = new WebSocket(url, protocols);\n\n this.ws.onopen = () => {\n this.emit('open');\n };\n\n this.ws.onmessage = (event: MessageEvent) => {\n this.emit('message', event.data);\n };\n\n this.ws.onerror = () => {\n this.emit('error', new Error('WebSocket error'));\n };\n\n this.ws.onclose = (event: CloseEvent) => {\n this.emit('close', event.code, event.reason);\n };\n }\n\n send(data: string): void {\n this.ws.send(data);\n }\n\n close(code?: number, reason?: string): void {\n this.ws.close(code, reason);\n }\n\n get readyState(): number {\n return this.ws.readyState;\n }\n}\n\n/**\n * Node.js WebSocket adapter\n * Wraps ws package with consistent interface\n */\nclass NodeWebSocketAdapter extends EventEmitter implements WebSocketAdapter {\n private ws: any;\n\n private constructor(ws: any) {\n super();\n this.ws = ws;\n\n this.ws.on('open', () => {\n this.emit('open');\n });\n\n this.ws.on('message', (data: any) => {\n // Convert Buffer to string if needed\n const message = typeof data === 'string' ? data : data.toString();\n this.emit('message', message);\n });\n\n this.ws.on('error', (error: Error) => {\n this.emit('error', error);\n });\n\n this.ws.on('close', (code: number, reason: string) => {\n this.emit('close', code, reason);\n });\n }\n\n static async create(url: string, protocols?: string | string[]): Promise<NodeWebSocketAdapter> {\n // Use dynamic import for ESM compatibility\n const { default: WebSocket } = await import('ws');\n const ws = new WebSocket(url, protocols);\n return new NodeWebSocketAdapter(ws);\n }\n\n send(data: string): void {\n this.ws.send(data);\n }\n\n close(code?: number, reason?: string): void {\n this.ws.close(code, reason);\n }\n\n get readyState(): number {\n return this.ws.readyState;\n }\n}\n", "/**\n * Event types for JmriClient EventEmitter\n */\n\nimport { PowerState } from './jmri-messages.js';\nimport { ThrottleData } from './jmri-messages.js';\n\n/**\n * Connection states\n */\nexport enum ConnectionState {\n DISCONNECTED = 'disconnected',\n CONNECTING = 'connecting',\n CONNECTED = 'connected',\n RECONNECTING = 'reconnecting'\n}\n\n/**\n * Event payload types\n */\nexport interface EventPayloads {\n // Connection events\n 'connected': void;\n 'disconnected': string; // reason\n 'reconnecting': [attempt: number, delay: number];\n 'reconnected': void;\n 'connectionStateChanged': ConnectionState;\n 'error': Error;\n\n // Power events\n 'power:changed': PowerState;\n\n // Throttle events\n 'throttle:acquired': string; // throttle ID\n 'throttle:updated': [throttleId: string, data: ThrottleData];\n 'throttle:released': string; // throttle ID\n 'throttle:lost': string; // throttle ID (server removed it)\n\n // Heartbeat events\n 'heartbeat:sent': void;\n 'heartbeat:timeout': void;\n\n // Message events\n 'message:sent': any;\n 'message:received': any;\n}\n\n/**\n * Event listener type\n */\nexport type EventListener<T> = (payload: T) => void;\n\n/**\n * Event map for type-safe event emitter\n */\nexport type EventMap = {\n [K in keyof EventPayloads]: EventPayloads[K] extends void\n ? () => void\n : EventPayloads[K] extends [infer A, infer B]\n ? (arg1: A, arg2: B) => void\n : (payload: EventPayloads[K]) => void;\n};\n", "/**\n * Message ID generator for request/response correlation\n */\n\n/**\n * Sequential message ID generator\n * Provides unique IDs for correlating requests and responses\n */\nexport class MessageIdGenerator {\n private currentId: number = 0;\n private readonly maxId: number = Number.MAX_SAFE_INTEGER;\n\n /**\n * Generate next sequential ID\n * Wraps around at MAX_SAFE_INTEGER\n */\n next(): number {\n this.currentId++;\n if (this.currentId >= this.maxId) {\n this.currentId = 1;\n }\n return this.currentId;\n }\n\n /**\n * Reset ID counter to 0\n */\n reset(): void {\n this.currentId = 0;\n }\n\n /**\n * Get current ID without incrementing\n */\n current(): number {\n return this.currentId;\n }\n}\n", "/**\n * Message queue for offline message handling\n */\n\nimport { JmriMessage } from '../types/jmri-messages.js';\n\n/**\n * Queue for storing messages when disconnected\n * Messages are sent when connection is restored\n */\nexport class MessageQueue {\n private queue: JmriMessage[] = [];\n private maxSize: number;\n\n constructor(maxSize: number = 100) {\n this.maxSize = maxSize;\n }\n\n /**\n * Add message to queue\n * If queue is full, oldest message is removed\n */\n enqueue(message: JmriMessage): void {\n if (this.queue.length >= this.maxSize) {\n this.queue.shift(); // Remove oldest\n }\n this.queue.push(message);\n }\n\n /**\n * Get all queued messages and clear queue\n */\n flush(): JmriMessage[] {\n const messages = [...this.queue];\n this.queue = [];\n return messages;\n }\n\n /**\n * Clear all queued messages without returning them\n */\n clear(): void {\n this.queue = [];\n }\n\n /**\n * Get number of queued messages\n */\n size(): number {\n return this.queue.length;\n }\n\n /**\n * Check if queue is empty\n */\n isEmpty(): boolean {\n return this.queue.length === 0;\n }\n\n /**\n * Check if queue is full\n */\n isFull(): boolean {\n return this.queue.length >= this.maxSize;\n }\n}\n", "/**\n * Connection state management with state machine\n */\n\nimport { EventEmitter } from 'eventemitter3';\nimport { ConnectionState } from '../types/events.js';\n\n/**\n * Valid state transitions\n */\nconst VALID_TRANSITIONS: Record<ConnectionState, ConnectionState[]> = {\n [ConnectionState.DISCONNECTED]: [ConnectionState.CONNECTING],\n [ConnectionState.CONNECTING]: [ConnectionState.CONNECTED, ConnectionState.DISCONNECTED],\n [ConnectionState.CONNECTED]: [ConnectionState.DISCONNECTED, ConnectionState.RECONNECTING],\n [ConnectionState.RECONNECTING]: [ConnectionState.CONNECTING, ConnectionState.CONNECTED, ConnectionState.DISCONNECTED]\n};\n\n/**\n * Manages connection state with validation\n */\nexport class ConnectionStateManager extends EventEmitter {\n private currentState: ConnectionState = ConnectionState.DISCONNECTED;\n\n /**\n * Get current connection state\n */\n getState(): ConnectionState {\n return this.currentState;\n }\n\n /**\n * Check if currently connected\n */\n isConnected(): boolean {\n return this.currentState === ConnectionState.CONNECTED;\n }\n\n /**\n * Check if currently connecting\n */\n isConnecting(): boolean {\n return this.currentState === ConnectionState.CONNECTING;\n }\n\n /**\n * Check if currently disconnected\n */\n isDisconnected(): boolean {\n return this.currentState === ConnectionState.DISCONNECTED;\n }\n\n /**\n * Check if currently reconnecting\n */\n isReconnecting(): boolean {\n return this.currentState === ConnectionState.RECONNECTING;\n }\n\n /**\n * Transition to new state\n * Validates transition and emits event\n */\n transition(newState: ConnectionState): void {\n const validTransitions = VALID_TRANSITIONS[this.currentState];\n\n if (!validTransitions.includes(newState)) {\n throw new Error(\n `Invalid state transition: ${this.currentState} -> ${newState}`\n );\n }\n\n const previousState = this.currentState;\n this.currentState = newState;\n\n this.emit('stateChanged', newState, previousState);\n }\n\n /**\n * Force state without validation (use with caution)\n */\n forceState(newState: ConnectionState): void {\n const previousState = this.currentState;\n this.currentState = newState;\n this.emit('stateChanged', newState, previousState);\n }\n\n /**\n * Reset to disconnected state\n */\n reset(): void {\n this.forceState(ConnectionState.DISCONNECTED);\n }\n}\n", "/**\n * Heartbeat (ping/pong) management\n */\n\nimport { EventEmitter } from 'eventemitter3';\nimport { HeartbeatOptions } from '../types/client-options.js';\n\n/**\n * Manages WebSocket heartbeat via ping/pong\n */\nexport class HeartbeatManager extends EventEmitter {\n private options: HeartbeatOptions;\n private pingInterval?: NodeJS.Timeout;\n private pongTimeout?: NodeJS.Timeout;\n private isRunning: boolean = false;\n\n constructor(options: HeartbeatOptions) {\n super();\n this.options = options;\n }\n\n /**\n * Start heartbeat monitoring\n * @param sendPing - Callback to send ping message\n */\n start(sendPing: () => void): void {\n if (!this.options.enabled || this.isRunning) {\n return;\n }\n\n this.isRunning = true;\n\n // Send ping at regular intervals\n this.pingInterval = setInterval(() => {\n sendPing();\n this.emit('pingSent');\n\n // Start pong timeout\n this.pongTimeout = setTimeout(() => {\n this.emit('timeout');\n }, this.options.timeout);\n }, this.options.interval);\n }\n\n /**\n * Stop heartbeat monitoring\n */\n stop(): void {\n this.isRunning = false;\n\n if (this.pingInterval) {\n clearInterval(this.pingInterval);\n this.pingInterval = undefined;\n }\n\n if (this.pongTimeout) {\n clearTimeout(this.pongTimeout);\n this.pongTimeout = undefined;\n }\n }\n\n /**\n * Handle pong received from server\n */\n receivedPong(): void {\n // Clear pong timeout\n if (this.pongTimeout) {\n clearTimeout(this.pongTimeout);\n this.pongTimeout = undefined;\n }\n this.emit('pongReceived');\n }\n\n /**\n * Check if heartbeat is running\n */\n running(): boolean {\n return this.isRunning;\n }\n\n /**\n * Update heartbeat options\n */\n updateOptions(options: Partial<HeartbeatOptions>): void {\n const wasRunning = this.isRunning;\n\n if (wasRunning) {\n this.stop();\n }\n\n this.options = { ...this.options, ...options };\n\n // Note: Caller must call start() again if needed\n }\n}\n", "/**\n * Exponential backoff calculator with jitter\n */\n\nimport { ReconnectionOptions } from '../types/client-options.js';\n\n/**\n * Calculate next reconnection delay using exponential backoff\n *\n * @param attempt - Current attempt number (1-indexed)\n * @param options - Reconnection options\n * @returns Delay in milliseconds\n */\nexport function calculateBackoffDelay(\n attempt: number,\n options: ReconnectionOptions\n): number {\n // Base delay calculation: initialDelay * (multiplier ^ (attempt - 1))\n const exponentialDelay = options.initialDelay * Math.pow(options.multiplier, attempt - 1);\n\n // Cap at maxDelay\n const cappedDelay = Math.min(exponentialDelay, options.maxDelay);\n\n // Add jitter if enabled (\u00B125%)\n if (options.jitter) {\n const jitterAmount = cappedDelay * 0.25;\n const jitter = (Math.random() * 2 - 1) * jitterAmount; // Random between -25% and +25%\n return Math.max(0, Math.round(cappedDelay + jitter));\n }\n\n return Math.round(cappedDelay);\n}\n\n/**\n * Check if should attempt reconnection\n *\n * @param attempt - Current attempt number (1-indexed)\n * @param maxAttempts - Maximum attempts (0 = infinite)\n * @returns True if should attempt reconnection\n */\nexport function shouldReconnect(attempt: number, maxAttempts: number): boolean {\n if (maxAttempts === 0) {\n return true; // Infinite attempts\n }\n return attempt <= maxAttempts;\n}\n", "/**\n * Automatic reconnection management with exponential backoff\n */\n\nimport { EventEmitter } from 'eventemitter3';\nimport { ReconnectionOptions } from '../types/client-options.js';\nimport { calculateBackoffDelay, shouldReconnect } from '../utils/exponential-backoff.js';\n\n/**\n * Manages automatic reconnection with exponential backoff\n */\nexport class ReconnectionManager extends EventEmitter {\n private options: ReconnectionOptions;\n private currentAttempt: number = 0;\n private reconnectTimeout?: NodeJS.Timeout;\n private isReconnecting: boolean = false;\n\n constructor(options: ReconnectionOptions) {\n super();\n this.options = options;\n }\n\n /**\n * Start reconnection process\n * @param reconnect - Callback to attempt reconnection\n */\n start(reconnect: () => Promise<void>): void {\n if (!this.options.enabled || this.isReconnecting) {\n return;\n }\n\n this.isReconnecting = true;\n this.currentAttempt = 0;\n this.scheduleNextAttempt(reconnect);\n }\n\n /**\n * Schedule next reconnection attempt\n */\n private scheduleNextAttempt(reconnect: () => Promise<void>): void {\n this.currentAttempt++;\n\n // Check if should continue trying\n if (!shouldReconnect(this.currentAttempt, this.options.maxAttempts)) {\n this.emit('maxAttemptsReached', this.currentAttempt - 1);\n this.stop();\n return;\n }\n\n // Calculate delay with backoff\n const delay = calculateBackoffDelay(this.currentAttempt, this.options);\n\n this.emit('attemptScheduled', this.currentAttempt, delay);\n\n // Schedule attempt\n this.reconnectTimeout = setTimeout(async () => {\n this.emit('attempting', this.currentAttempt);\n\n try {\n await reconnect();\n // Success - stop reconnection process\n this.stop();\n this.emit('success', this.currentAttempt);\n } catch (error) {\n // Failure - schedule next attempt\n this.emit('failed', this.currentAttempt, error);\n this.scheduleNextAttempt(reconnect);\n }\n }, delay);\n }\n\n /**\n * Stop reconnection process\n */\n stop(): void {\n this.isReconnecting = false;\n\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = undefined;\n }\n }\n\n /**\n * Reset attempt counter\n */\n reset(): void {\n this.stop();\n this.currentAttempt = 0;\n }\n\n /**\n * Check if currently reconnecting\n */\n reconnecting(): boolean {\n return this.isReconnecting;\n }\n\n /**\n * Get current attempt number\n */\n getAttempt(): number {\n return this.currentAttempt;\n }\n\n /**\n * Update reconnection options\n */\n updateOptions(options: Partial<ReconnectionOptions>): void {\n this.options = { ...this.options, ...options };\n }\n}\n", "/**\n * JMRI WebSocket Protocol Message Types\n * Based on JMRI JSON protocol specification\n */\n\n/**\n * Base message structure for JMRI WebSocket communication\n */\nexport interface JmriMessage {\n type: string;\n method?: 'get' | 'post' | 'put' | 'delete' | 'list';\n data?: any;\n id?: number;\n}\n\n/**\n * Power state values\n * ON = 2, OFF = 4 (JMRI constants)\n */\nexport enum PowerState {\n ON = 2,\n OFF = 4,\n UNKNOWN = 0\n}\n\n/**\n * Power message data\n */\nexport interface PowerData {\n state: PowerState;\n}\n\n/**\n * Power message\n */\nexport interface PowerMessage extends JmriMessage {\n type: 'power';\n data?: PowerData;\n}\n\n/**\n * Throttle data structure\n */\nexport interface ThrottleData {\n address?: number | string;\n throttle?: string;\n speed?: number;\n forward?: boolean;\n release?: null;\n status?: string;\n // Function keys F0-F28\n F0?: boolean;\n F1?: boolean;\n F2?: boolean;\n F3?: boolean;\n F4?: boolean;\n F5?: boolean;\n F6?: boolean;\n F7?: boolean;\n F8?: boolean;\n F9?: boolean;\n F10?: boolean;\n F11?: boolean;\n F12?: boolean;\n F13?: boolean;\n F14?: boolean;\n F15?: boolean;\n F16?: boolean;\n F17?: boolean;\n F18?: boolean;\n F19?: boolean;\n F20?: boolean;\n F21?: boolean;\n F22?: boolean;\n F23?: boolean;\n F24?: boolean;\n F25?: boolean;\n F26?: boolean;\n F27?: boolean;\n F28?: boolean;\n}\n\n/**\n * Throttle message\n */\nexport interface ThrottleMessage extends JmriMessage {\n type: 'throttle';\n data: ThrottleData;\n}\n\n/**\n * Roster entry\n */\nexport interface RosterEntry {\n name: string;\n address: string;\n isLongAddress: boolean;\n road?: string;\n number?: string;\n mfg?: string;\n model?: string;\n comment?: string;\n maxSpeed?: number;\n imageFilePath?: string;\n iconFilePath?: string;\n functionKeys?: { [key: string]: string };\n}\n\n/**\n * Roster data structure\n */\nexport interface RosterData {\n [key: string]: RosterEntry;\n}\n\n/**\n * Roster message\n */\nexport interface RosterMessage extends JmriMessage {\n type: 'roster';\n method: 'list';\n data?: RosterData;\n}\n\n/**\n * Ping message (heartbeat)\n */\nexport interface PingMessage extends JmriMessage {\n type: 'ping';\n}\n\n/**\n * Pong message (heartbeat response)\n */\nexport interface PongMessage extends JmriMessage {\n type: 'pong';\n}\n\n/**\n * Hello message (connection establishment)\n */\nexport interface HelloMessage extends JmriMessage {\n type: 'hello';\n data?: {\n JMRI?: string;\n JSON?: string;\n Railroad?: string;\n node?: string;\n activeProfile?: string;\n };\n}\n\n/**\n * Goodbye message (graceful disconnect)\n */\nexport interface GoodbyeMessage extends JmriMessage {\n type: 'goodbye';\n}\n\n/**\n * Error message from JMRI\n */\nexport interface ErrorMessage extends JmriMessage {\n type: 'error';\n data: {\n code: number;\n message: string;\n };\n}\n\n/**\n * Union type of all possible JMRI messages\n */\nexport type AnyJmriMessage =\n | PowerMessage\n | ThrottleMessage\n | RosterMessage\n | PingMessage\n | PongMessage\n | HelloMessage\n | GoodbyeMessage\n | ErrorMessage;\n", "/**\n * Mock data for JMRI responses\n * Used for testing and demo mode\n */\n\nexport const mockData = {\n \"hello\": {\n \"type\": \"hello\",\n \"data\": {\n \"JMRI\": \"5.9.2\",\n \"JSON\": \"5.0\",\n \"Railroad\": \"Demo Railroad\",\n \"node\": \"jmri-server\",\n \"activeProfile\": \"Demo Profile\"\n }\n },\n \"power\": {\n \"get\": {\n \"on\": {\n \"type\": \"power\",\n \"data\": {\n \"state\": 2\n }\n },\n \"off\": {\n \"type\": \"power\",\n \"data\": {\n \"state\": 4\n }\n }\n },\n \"post\": {\n \"success\": {\n \"type\": \"power\",\n \"data\": {\n \"state\": 2\n }\n }\n }\n },\n \"roster\": {\n \"list\": {\n \"type\": \"roster\",\n \"data\": {\n \"CSX754\": {\n \"name\": \"CSX754\",\n \"address\": \"754\",\n \"isLongAddress\": true,\n \"road\": \"CSX\",\n \"number\": \"754\",\n \"mfg\": \"Athearn\",\n \"model\": \"GP38-2\",\n \"comment\": \"Blue and yellow scheme\",\n \"maxSpeed\": 126,\n \"functionKeys\": {\n \"F0\": \"Headlight\",\n \"F1\": \"Bell\",\n \"F2\": \"Horn\",\n \"F3\": \"Air Release\",\n \"F4\": \"Dynamic Brake\"\n }\n },\n \"UP3985\": {\n \"name\": \"UP3985\",\n \"address\": \"3985\",\n \"isLongAddress\": true,\n \"road\": \"Union Pacific\",\n \"number\": \"3985\",\n \"mfg\": \"Rivarossi\",\n \"model\": \"Challenger 4-6-6-4\",\n \"comment\": \"Steam locomotive\",\n \"maxSpeed\": 126,\n \"functionKeys\": {\n \"F0\": \"Headlight\",\n \"F1\": \"Bell\",\n \"F2\": \"Whistle\",\n \"F3\": \"Steam\",\n \"F4\": \"Coupler\"\n }\n },\n \"BNSF5240\": {\n \"name\": \"BNSF5240\",\n \"address\": \"5240\",\n \"isLongAddress\": true,\n \"road\": \"BNSF\",\n \"number\": \"5240\",\n \"mfg\": \"Kato\",\n \"model\": \"SD40-2\",\n \"comment\": \"Heritage II paint\",\n \"maxSpeed\": 126,\n \"functionKeys\": {\n \"F0\": \"Headlight\",\n \"F1\": \"Bell\",\n \"F2\": \"Horn\",\n \"F3\": \"Dynamic Brake\",\n \"F4\": \"Mars Light\"\n }\n }\n }\n }\n },\n \"throttle\": {\n \"acquire\": {\n \"success\": {\n \"type\": \"throttle\",\n \"data\": {\n \"throttle\": \"{THROTTLE_ID}\",\n \"address\": \"{ADDRESS}\",\n \"speed\": 0,\n \"forward\": true,\n \"F0\": false,\n \"F1\": false,\n \"F2\": false,\n \"F3\": false,\n \"F4\": false\n }\n }\n },\n \"release\": {\n \"success\": {\n \"type\": \"throttle\",\n \"data\": {}\n }\n },\n \"control\": {\n \"speed\": {\n \"type\": \"throttle\",\n \"data\": {\n \"throttle\": \"{THROTTLE_ID}\",\n \"speed\": \"{SPEED}\"\n }\n },\n \"direction\": {\n \"type\": \"throttle\",\n \"data\": {\n \"throttle\": \"{THROTTLE_ID}\",\n \"forward\": \"{FORWARD}\"\n }\n },\n \"function\": {\n \"type\": \"throttle\",\n \"data\": {\n \"throttle\": \"{THROTTLE_ID}\",\n \"{FUNCTION}\": \"{VALUE}\"\n }\n }\n }\n },\n \"ping\": {\n \"type\": \"ping\"\n },\n \"pong\": {\n \"type\": \"pong\"\n },\n \"goodbye\": {\n \"type\": \"goodbye\"\n },\n \"error\": {\n \"throttleNotFound\": {\n \"type\": \"error\",\n \"data\": {\n \"code\": 404,\n \"message\": \"Throttle not found\"\n }\n },\n \"invalidSpeed\": {\n \"type\": \"error\",\n \"data\": {\n \"code\": 400,\n \"message\": \"Invalid speed value\"\n }\n },\n \"connectionError\": {\n \"type\": \"error\",\n \"data\": {\n \"code\": 500,\n \"message\": \"Connection error\"\n }\n }\n }\n} as const;\n", "/**\n * Mock Response Manager\n * Generates mock JMRI responses for testing and demo purposes\n */\n\nimport { JmriMessage, PowerState, PowerMessage, ThrottleMessage, RosterMessage, HelloMessage, PongMessage, GoodbyeMessage } from '../types/jmri-messages.js';\nimport { mockData } from './mock-data.js';\n\nexport interface MockResponseManagerOptions {\n /**\n * Delay in milliseconds before returning responses (simulates network latency)\n * Set to 0 for instant responses\n */\n responseDelay?: number;\n\n /**\n * Current power state (used to track state changes)\n */\n initialPowerState?: PowerState;\n}\n\n/**\n * Manages mock responses for JMRI protocol\n */\nexport class MockResponseManager {\n private responseDelay: number;\n private powerState: PowerState;\n private throttles: Map<string, any> = new Map();\n\n constructor(options: MockResponseManagerOptions = {}) {\n this.responseDelay = options.responseDelay ?? 50;\n this.powerState = options.initialPowerState ?? PowerState.OFF;\n }\n\n /**\n * Get a mock response for a given message\n */\n async getMockResponse(message: JmriMessage): Promise<JmriMessage | null> {\n // Simulate network delay\n if (this.responseDelay > 0) {\n await this.delay(this.responseDelay);\n }\n\n // Route to appropriate handler based on message type\n switch (message.type) {\n case 'hello':\n return this.getHelloResponse();\n\n case 'power':\n return this.getPowerResponse(message);\n\n case 'roster':\n return this.getRosterResponse(message);\n\n case 'throttle':\n return this.getThrottleResponse(message);\n\n case 'ping':\n return this.getPingResponse();\n\n case 'goodbye':\n return this.getGoodbyeResponse();\n\n default:\n return null;\n }\n }\n\n /**\n * Get hello response (connection establishment)\n */\n private getHelloResponse(): HelloMessage {\n return JSON.parse(JSON.stringify(mockData.hello));\n }\n\n /**\n * Get power response\n */\n private getPowerResponse(message: JmriMessage): PowerMessage {\n // Handle power state change\n if (message.data?.state !== undefined) {\n this.powerState = message.data.state;\n return {\n type: 'power',\n data: { state: this.powerState }\n };\n }\n\n // Return current power state\n return {\n type: 'power',\n data: { state: this.powerState }\n };\n }\n\n /**\n * Get roster response\n */\n private getRosterResponse(message: JmriMessage): RosterMessage {\n if (message.type === 'roster' && message.method === 'list') {\n return JSON.parse(JSON.stringify(mockData.roster.list));\n }\n\n return {\n type: 'roster',\n method: 'list',\n data: {}\n };\n }\n\n /**\n * Get throttle response\n */\n private getThrottleResponse(message: JmriMessage): ThrottleMessage {\n const data = message.data || {};\n\n // Acquire throttle\n if (data.address !== undefined && !data.throttle) {\n const throttleId = data.name || `MOCK-${data.address}`;\n const throttleState = {\n throttle: throttleId,\n address: data.address,\n speed: 0,\n forward: true,\n F0: false,\n F1: false,\n F2: false,\n F3: false,\n F4: false\n };\n\n this.throttles.set(throttleId, throttleState);\n\n return {\n type: 'throttle',\n data: { ...throttleState }\n };\n }\n\n // Release throttle\n if (data.release !== undefined && data.throttle) {\n this.throttles.delete(data.throttle);\n return {\n type: 'throttle',\n data: {}\n };\n }\n\n // Throttle control (speed, direction, functions)\n if (data.throttle) {\n const throttleState = this.throttles.get(data.throttle);\n\n if (!throttleState) {\n // Throttle not found - this shouldn't normally happen in mock mode\n // but we'll create it on the fly\n const newState = {\n throttle: data.throttle,\n address: 0,\n speed: 0,\n forward: true\n };\n this.throttles.set(data.throttle, newState);\n return {\n type: 'throttle',\n data: { ...newState }\n };\n }\n\n // Update throttle state\n if (data.speed !== undefined) {\n throttleState.speed = data.speed;\n }\n if (data.forward !== undefined) {\n throttleState.forward = data.forward;\n }\n\n // Update function keys\n for (let i = 0; i <= 28; i++) {\n const key = `F${i}`;\n if (data[key] !== undefined) {\n throttleState[key] = data[key];\n }\n }\n\n // Return updated state (no response for throttle control commands)\n return {\n type: 'throttle',\n data: {}\n };\n }\n\n return {\n type: 'throttle',\n data: {}\n };\n }\n\n /**\n * Get ping response (pong)\n */\n private getPingResponse(): PongMessage {\n return JSON.parse(JSON.stringify(mockData.pong));\n }\n\n /**\n * Get goodbye response\n */\n private getGoodbyeResponse(): GoodbyeMessage {\n return JSON.parse(JSON.stringify(mockData.goodbye));\n }\n\n /**\n * Get current power state\n */\n getPowerState(): PowerState {\n return this.powerState;\n }\n\n /**\n * Set power state (for testing)\n */\n setPowerState(state: PowerState): void {\n this.powerState = state;\n }\n\n /**\n * Get all throttles (for testing)\n */\n getThrottles(): Map<string, any> {\n return this.throttles;\n }\n\n /**\n * Reset all state (for testing)\n */\n reset(): void {\n this.powerState = PowerState.OFF;\n this.throttles.clear();\n }\n\n /**\n * Delay helper\n */\n private delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}\n\n/**\n * Singleton instance for shared use across tests\n */\nexport const mockResponseManager = new MockResponseManager({ responseDelay: 0 });\n", "/**\n * Core WebSocket client for JMRI communication\n */\n\nimport { EventEmitter } from 'eventemitter3';\nimport { createWebSocketAdapter, WebSocketAdapter } from './websocket-adapter.js';\nimport { JmriClientOptions } from '../types/client-options.js';\nimport { JmriMessage, AnyJmriMessage, GoodbyeMessage } from '../types/jmri-messages.js';\nimport { ConnectionState } from '../types/events.js';\nimport { MessageIdGenerator } from '../utils/message-id.js';\nimport { MessageQueue } from './message-queue.js';\nimport { ConnectionStateManager } from './connection-state-manager.js';\nimport { HeartbeatManager } from './heartbeat-manager.js';\nimport { ReconnectionManager } from './reconnection-manager.js';\nimport { MockResponseManager } from '../mocks/index.js';\n\n/**\n * Pending request tracking\n */\ninterface PendingRequest {\n resolve: (value: any) => void;\n reject: (error: Error) => void;\n timeout: NodeJS.Timeout;\n messageType?: string;\n matchKey?: string;\n}\n\n/**\n * Core WebSocket client\n */\nexport class WebSocketClient extends EventEmitter {\n private options: JmriClientOptions;\n private ws?: WebSocketAdapter;\n private url: string;\n\n // Sub-managers\n private messageIdGen: MessageIdGenerator;\n private messageQueue: MessageQueue;\n private stateManager: ConnectionStateManager;\n private heartbeatManager: HeartbeatManager;\n private reconnectionManager: ReconnectionManager;\n private mockManager?: MockResponseManager;\n\n // Request/response tracking\n private pendingRequests: Map<number, PendingRequest> = new Map();\n\n // Connection state\n private isManualDisconnect: boolean = false;\n\n constructor(options: JmriClientOptions) {\n super();\n this.options = options;\n this.url = `${options.protocol}://${options.host}:${options.port}/json/`;\n\n // Initialize sub-managers\n this.messageIdGen = new MessageIdGenerator();\n this.messageQueue = new MessageQueue(options.messageQueueSize);\n this.stateManager = new ConnectionStateManager();\n this.heartbeatManager = new HeartbeatManager(options.heartbeat);\n this.reconnectionManager = new ReconnectionManager(options.reconnection);\n\n // Initialize mock manager if mock mode is enabled\n if (options.mock.enabled) {\n this.mockManager = new MockResponseManager({\n responseDelay: options.mock.responseDelay\n });\n }\n\n // Wire up state manager events\n this.stateManager.on('stateChanged', (newState: ConnectionState, prevState: ConnectionState) => {\n this.emit('connectionStateChanged', newState, prevState);\n });\n\n // Wire up heartbeat events\n this.heartbeatManager.on('timeout', () => {\n this.emit('heartbeat:timeout');\n this.handleHeartbeatTimeout();\n });\n\n this.heartbeatManager.on('pingSent', () => {\n this.emit('heartbeat:sent');\n });\n\n // Wire up reconnection events\n this.reconnectionManager.on('attemptScheduled', (attempt: number, delay: number) => {\n this.emit('reconnecting', attempt, delay);\n });\n\n this.reconnectionManager.on('success', () => {\n this.emit('reconnected');\n });\n\n this.reconnectionManager.on('maxAttemptsReached', (attempts: number) => {\n this.emit('reconnectionFailed', attempts);\n });\n\n this.reconnectionManager.on('debug', (message: string) => {\n this.emit('debug', message);\n });\n }\n\n /**\n * Connect to JMRI WebSocket server (or mock)\n */\n async connect(): Promise<void> {\n if (this.stateManager.isConnected() || this.stateManager.isConnecting()) {\n return;\n }\n\n this.isManualDisconnect = false;\n this.stateManager.transition(ConnectionState.CONNECTING);\n\n // Mock mode - simulate connection\n if (this.mockManager) {\n return this.connectMock();\n }\n\n // Real WebSocket connection\n return new Promise(async (resolve, reject) => {\n try {\n this.ws = await createWebSocketAdapter(this.url);\n\n this.ws.on('open', () => {\n this.handleOpen();\n resolve();\n });\n\n this.ws.on('message', (data: string) => {\n this.handleMessage(data);\n });\n\n this.ws.on('close', (code: number, reason: string) => {\n // If close happens during connection attempt, treat as connection failure\n if (this.stateManager.isConnecting()) {\n // Transition to disconnected state so reconnection can proceed\n this.stateManager.transition(ConnectionState.DISCONNECTED);\n const error = new Error(`WebSocket connection failed (code: ${code}${reason ? ', reason: ' + reason : ''})`);\n this.emit('error', error);\n reject(error);\n // Still need to handle close to trigger reconnection\n this.handleClose(code, reason);\n } else {\n this.handleClose(code, reason);\n }\n });\n\n this.ws.on('error', (error: Error) => {\n this.emit('error', error);\n if (this.stateManager.isConnecting()) {\n this.stateManager.transition(ConnectionState.DISCONNECTED);\n reject(error);\n }\n });\n } catch (error) {\n this.stateManager.transition(ConnectionState.DISCONNECTED);\n reject(error);\n }\n });\n }\n\n /**\n * Simulate connection in mock mode\n */\n private async connectMock(): Promise<void> {\n // Simulate connection delay\n await this.delay(10);\n\n // Transition to connected state\n this.handleOpen();\n\n // Send hello message in mock mode\n const helloResponse = await this.mockManager!.getMockResponse({ type: 'hello' });\n if (helloResponse) {\n this.emit('message:received', helloResponse);\n }\n }\n\n /**\n * Disconnect from JMRI WebSocket server\n */\n async disconnect(): Promise<void> {\n // Already disconnected, nothing to do\n if (this.stateManager.isDisconnected()) {\n return;\n }\n\n this.isManualDisconnect = true;\n this.reconnectionManager.stop();\n this.heartbeatManager.stop();\n\n // Send goodbye message\n if (this.stateManager.isConnected()) {\n try {\n await this.sendGoodbye();\n } catch (error) {\n // Ignore errors during goodbye\n }\n }\n\n // Close WebSocket\n if (this.ws) {\n this.ws.close();\n this.ws = undefined;\n }\n\n // Reject all pending requests\n this.rejectAllPendingRequests(new Error('Client disconnected'));\n\n if (!this.stateManager.isDisconnected()) {\n this.stateManager.transition(ConnectionState.DISCONNECTED);\n }\n }\n\n /**\n * Send message to JMRI (or mock)\n */\n send(message: JmriMessage): void {\n if (!this.stateManager.isConnected()) {\n // Queue message for later\n this.messageQueue.enqueue(message);\n return;\n }\n\n // Mock mode - send doesn't need to do anything\n // Responses are generated in request()\n if (this.mockManager) {\n this.emit('message:sent', message);\n return;\n }\n\n if (!this.ws) {\n throw new Error('WebSocket not initialized');\n }\n\n const json = JSON.stringify(message);\n this.ws.send(json);\n this.emit('message:sent', message);\n }\n\n /**\n * Send request and wait for response (or get mock response)\n */\n async request<T = any>(message: JmriMessage, timeout?: number): Promise<T> {\n // Mock mode - get response from mock manager\n if (this.mockManager) {\n const response = await this.mockManager.getMockResponse(message);\n this.emit('message:sent', message);\n if (response) {\n this.emit('message:received', response);\n }\n return response as T;\n }\n\n // Real mode - send request and wait for response\n // Assign message ID\n const id = this.messageIdGen.next();\n message.id = id;\n\n return new Promise((resolve, reject) => {\n // Set up timeout\n const timeoutMs = timeout || this.options.requestTimeout;\n const timeoutHandle = setTimeout(() => {\n this.pendingRequests.delete(id);\n reject(new Error(`Request timeout after ${timeoutMs}ms`));\n }, timeoutMs);\n\n // Track pending request with metadata for matching responses without IDs\n const pendingRequest: PendingRequest = {\n resolve,\n reject,\n timeout: timeoutHandle,\n messageType: message.type\n };\n\n // For throttle requests, store the throttle name for matching\n if (message.type === 'throttle' && message.data && 'name' in message.data) {\n pendingRequest.matchKey = (message.data as any).name;\n }\n\n this.pendingRequests.set(id, pendingRequest);\n\n // Send message\n try {\n this.send(message);\n } catch (error) {\n this.pendingRequests.delete(id);\n clearTimeout(timeoutHandle);\n reject(error);\n }\n });\n }\n\n /**\n * Get current connection state\n */\n getState(): ConnectionState {\n return this.stateManager.getState();\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.stateManager.isConnected();\n }\n\n /**\n * Handle WebSocket open event\n */\n private handleOpen(): void {\n this.stateManager.transition(ConnectionState.CONNECTED);\n this.emit('connected');\n\n // Start heartbeat\n if (this.options.heartbeat.enabled) {\n this.heartbeatManager.start(() => this.sendPing());\n }\n\n // Flush queued messages\n const queuedMessages = this.messageQueue.flush();\n for (const message of queuedMessages) {\n this.send(message);\n }\n }\n\n /**\n * Handle WebSocket message event\n */\n private handleMessage(data: string): void {\n try {\n const message: AnyJmriMessage = JSON.parse(data);\n this.emit('message:received', message);\n\n // Handle pong\n if (message.type === 'pong') {\n this.heartbeatManager.receivedPong();\n return;\n }\n\n // Handle hello\n if (message.type === 'hello') {\n this.emit('hello', message.data);\n return;\n }\n\n // Handle response to request\n if (message.id !== undefined) {\n const pending = this.pendingRequests.get(message.id);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pendingRequests.delete(message.id);\n pending.resolve(message);\n return;\n }\n }\n\n // Handle responses without ID (like throttle responses from JMRI)\n // Match by message type and data\n if (message.id === undefined) {\n for (const [id, pending] of this.pendingRequests.entries()) {\n // Match by type\n if (pending.messageType === message.type) {\n // For throttle messages, also match by throttle name\n if (message.type === 'throttle' && pending.matchKey) {\n const throttleName = (message.data as any)?.throttle || (message.data as any)?.name;\n if (throttleName === pending.matchKey) {\n clearTimeout(pending.timeout);\n this.pendingRequests.delete(id);\n pending.resolve(message);\n return;\n }\n } else {\n // For other message types, just match by type\n clearTimeout(pending.timeout);\n this.pendingRequests.delete(id);\n pending.resolve(message);\n return;\n }\n }\n }\n }\n\n // Handle unsolicited updates (auto-subscriptions)\n this.emit('update', message);\n } catch (error) {\n this.emit('error', new Error(`Failed to parse message: ${error}`));\n }\n }\n\n /**\n * Handle WebSocket close event\n */\n private handleClose(code: number, reason: string): void {\n this.heartbeatManager.stop();\n\n const wasConnected = this.stateManager.isConnected();\n const isReconnecting = this.reconnectionManager.reconnecting();\n\n if (this.stateManager.isConnected() || this.stateManager.isConnecting()) {\n this.stateManager.transition(ConnectionState.DISCONNECTED);\n }\n\n this.emit('disconnected', reason || `Connection closed (code: ${code})`);\n\n // Reject all pending requests\n this.rejectAllPendingRequests(new Error('Connection closed'));\n\n // Attempt reconnection if not manual disconnect\n // Continue reconnecting if we were connected OR reconnection manager is already active\n if (!this.isManualDisconnect && (wasConnected || isReconnecting) && this.options.reconnection.enabled) {\n this.stateManager.forceState(ConnectionState.RECONNECTING);\n this.reconnectionManager.start(() => this.connect());\n }\n }\n\n /**\n * Handle heartbeat timeout\n */\n private handleHeartbeatTimeout(): void {\n // Connection appears dead, force reconnect\n if (this.ws) {\n this.ws.close();\n }\n }\n\n /**\n * Send ping message\n */\n private sendPing(): void {\n this.send({ type: 'ping' });\n }\n\n /**\n * Send goodbye message\n */\n private async sendGoodbye(): Promise<void> {\n const message: GoodbyeMessage = { type: 'goodbye' };\n this.send(message);\n // Give it a moment to send\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n\n /**\n * Reject all pending requests\n */\n private rejectAllPendingRequests(error: Error): void {\n for (const pending of this.pendingRequests.values()) {\n clearTimeout(pending.timeout);\n pending.reject(error);\n }\n this.pendingRequests.clear();\n }\n\n /**\n * Delay helper\n */\n private delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}\n", "/**\n * Power control manager\n */\n\nimport { EventEmitter } from 'eventemitter3';\nimport { WebSocketClient } from '../core/websocket-client.js';\nimport { PowerState, PowerMessage } from '../types/jmri-messages.js';\n\n/**\n * Manages track power control\n */\nexport class PowerManager extends EventEmitter {\n private client: WebSocketClient;\n private currentState: PowerState = PowerState.UNKNOWN;\n\n constructor(client: WebSocketClient) {\n super();\n this.client = client;\n\n // Listen for power updates\n this.client.on('update', (message: any) => {\n if (message.type === 'power') {\n this.handlePowerUpdate(message);\n }\n });\n }\n\n /**\n * Get current track power state\n */\n async getPower(): Promise<PowerState> {\n const message: PowerMessage = {\n type: 'power'\n };\n\n const response = await this.client.request<PowerMessage>(message);\n\n if (response.data?.state !== undefined) {\n this.currentState = response.data.state;\n }\n\n return this.currentState;\n }\n\n /**\n * Set track power state\n */\n async setPower(state: PowerState): Promise<void> {\n const message: PowerMessage = {\n type: 'power',\n method: 'post',\n data: { state }\n };\n\n await this.client.request<PowerMessage>(message);\n\n const oldState = this.currentState;\n this.currentState = state;\n\n if (oldState !== this.currentState) {\n this.emit('power:changed', this.currentState);\n }\n }\n\n /**\n * Turn track power on\n */\n async powerOn(): Promise<void> {\n await this.setPower(PowerState.ON);\n }\n\n /**\n * Turn track power off\n */\n async powerOff(): Promise<void> {\n await this.setPower(PowerState.OFF);\n }\n\n /**\n * Get cached power state (no network request)\n */\n getCachedState(): PowerState {\n return this.currentState;\n }\n\n /**\n * Handle unsolicited power updates from JMRI\n */\n private handlePowerUpdate(message: PowerMessage): void {\n if (message.data?.state !== undefined) {\n const oldState = this.currentState;\n this.currentState = message.data.state;\n\n if (oldState !== this.currentState) {\n this.emit('power:changed', this.currentState);\n }\n }\n }\n}\n", "/**\n * Roster management\n */\n\nimport { WebSocketClient } from '../core/websocket-client.js';\nimport { RosterMessage, RosterEntry, RosterData } from '../types/jmri-messages.js';\n\n/**\n * Manages locomotive roster\n */\nexport class RosterManager {\n private client: WebSocketClient;\n private rosterCache: Map<string, RosterEntry> = new Map();\n\n constructor(client: WebSocketClient) {\n this.client = client;\n }\n\n /**\n * Get all roster entries\n */\n async getRoster(): Promise<RosterEntry[]> {\n const message: RosterMessage = {\n type: 'roster',\n method: 'list'\n };\n\n const response = await this.client.request<RosterMessage>(message);\n\n // Parse roster data\n if (response.data) {\n this.updateCache(response.data);\n }\n\n return Array.from(this.rosterCache.values());\n }\n\n /**\n * Get roster entry by name\n */\n async getRosterEntryByName(name: string): Promise<RosterEntry | undefined> {\n // Check cache first\n if (this.rosterCache.has(name)) {\n return this.rosterCache.get(name);\n }\n\n // Refresh roster\n await this.getRoster();\n return this.rosterCache.get(name);\n }\n\n /**\n * Get roster entry by address\n */\n async getRosterEntryByAddress(address: string | number): Promise<RosterEntry | undefined> {\n // Ensure roster is loaded\n if (this.rosterCache.size === 0) {\n await this.getRoster();\n }\n\n const addressStr = address.toString();\n\n for (const entry of this.rosterCache.values()) {\n if (entry.address === addressStr) {\n return entry;\n }\n }\n\n return undefined;\n }\n\n /**\n * Search roster by partial name match\n */\n async searchRoster(query: string): Promise<RosterEntry[]> {\n // Ensure roster is loaded\n if (this.rosterCache.size === 0) {\n await this.getRoster();\n }\n\n const lowerQuery = query.toLowerCase();\n const results: RosterEntry[] = [];\n\n for (const entry of this.rosterCache.values()) {\n if (\n entry.name.toLowerCase().includes(lowerQuery) ||\n entry.address.includes(query) ||\n entry.road?.toLowerCase().includes(lowerQuery) ||\n entry.number?.includes(query)\n ) {\n results.push(entry);\n }\n }\n\n return results;\n }\n\n /**\n * Get cached roster (no network request)\n */\n getCachedRoster(): RosterEntry[] {\n return Array.from(this.rosterCache.values());\n }\n\n /**\n * Clear roster cache\n */\n clearCache(): void {\n this.rosterCache.clear();\n }\n\n /**\n * Update internal cache from roster data\n */\n private updateCache(rosterData: RosterData): void {\n this.rosterCache.clear();\n\n for (const [name, entry] of Object.entries(rosterData)) {\n this.rosterCache.set(name, entry);\n }\n }\n}\n", "/**\n * Throttle-specific types\n */\n\n/**\n * Options for acquiring a throttle\n */\nexport interface ThrottleAcquireOptions {\n /**\n * DCC address of the locomotive\n */\n address: number;\n\n /**\n * Whether this is a long address (default: true for addresses > 127)\n */\n isLongAddress?: boolean;\n}\n\n/**\n * Throttle function key (F0-F28)\n */\nexport type ThrottleFunctionKey =\n | 'F0' | 'F1' | 'F2' | 'F3' | 'F4' | 'F5' | 'F6' | 'F7' | 'F8' | 'F9'\n | 'F10' | 'F11' | 'F12' | 'F13' | 'F14' | 'F15' | 'F16' | 'F17' | 'F18' | 'F19'\n | 'F20' | 'F21' | 'F22' | 'F23' | 'F24' | 'F25' | 'F26' | 'F27' | 'F28';\n\n/**\n * Throttle state tracking\n */\nexport interface ThrottleState {\n /**\n * Throttle ID assigned by JMRI\n */\n id: string;\n\n /**\n * DCC address\n */\n address: number;\n\n /**\n * Current speed (0.0 to 1.0)\n */\n speed: number;\n\n /**\n * Direction (true = forward, false = reverse)\n */\n forward: boolean;\n\n /**\n * Function states (F0-F28)\n */\n functions: Map<ThrottleFunctionKey, boolean>;\n\n /**\n * Whether throttle is currently acquired\n */\n acquired: boolean;\n}\n\n/**\n * Validates that a value is a valid throttle function key\n */\nexport function isThrottleFunctionKey(key: string): key is ThrottleFunctionKey {\n return /^F([0-9]|1[0-9]|2[0-8])$/.test(key);\n}\n\n/**\n * Validates that speed is in valid range (0.0 to 1.0)\n */\nexport function isValidSpeed(speed: number): boolean {\n return typeof speed === 'number' && speed >= 0 && speed <= 1;\n}\n", "/**\n * Throttle control manager\n */\n\nimport { EventEmitter } from 'eventemitter3';\nimport { WebSocketClient } from '../core/websocket-client.js';\nimport { ThrottleMessage, ThrottleData } from '../types/jmri-messages.js';\nimport {\n ThrottleAcquireOptions,\n ThrottleFunctionKey,\n ThrottleState,\n isThrottleFunctionKey,\n isValidSpeed\n} from '../types/throttle.js';\n\n/**\n * Manages multiple throttles\n */\nexport class ThrottleManager extends EventEmitter {\n private client: WebSocketClient;\n private throttles: Map<string, ThrottleState> = new Map();\n private clientId: string;\n\n constructor(client: WebSocketClient) {\n super();\n this.client = client;\n // Generate a unique client ID\n this.clientId = `jmri-client-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n\n // Listen for throttle updates\n this.client.on('update', (message: any) => {\n if (message.type === 'throttle') {\n this.handleThrottleUpdate(message);\n }\n });\n\n // Clean up throttles on disconnect\n this.client.on('disconnected', () => {\n this.handleDisconnect();\n });\n }\n\n /**\n * Acquire a throttle for a locomotive\n */\n async acquireThrottle(options: ThrottleAcquireOptions): Promise<string> {\n // Generate a unique throttle name using client ID and address\n const throttleName = `${this.clientId}-${options.address}`;\n\n const message: any = {\n type: 'throttle',\n data: {\n name: throttleName,\n address: options.address\n }\n };\n\n const response = await this.client.request<ThrottleMessage>(message);\n\n // JMRI returns the throttle ID in the \"throttle\" field, or we can use our name\n const throttleId = response.data?.throttle || throttleName;\n\n if (!throttleId) {\n throw new Error('Failed to acquire throttle: no throttle ID returned');\n }\n\n // Initialize throttle state\n const state: ThrottleState = {\n id: throttleId,\n address: options.address,\n speed: 0,\n forward: true,\n functions: new Map(),\n acquired: true\n };\n\n this.throttles.set(throttleId, state);\n this.emit('throttle:acquired', throttleId);\n\n return throttleId;\n }\n\n /**\n * Release a throttle\n */\n async releaseThrottle(throttleId: string): Promise<void> {\n const state = this.throttles.get(throttleId);\n if (!state) {\n throw new Error(`Throttle not found: ${throttleId}`);\n }\n\n const message: ThrottleMessage = {\n type: 'throttle',\n data: {\n throttle: throttleId,\n release: null\n }\n };\n\n await this.client.request<ThrottleMessage>(message);\n\n this.throttles.delete(throttleId);\n this.emit('throttle:released', throttleId);\n }\n\n /**\n * Set throttle speed (0.0 to 1.0)\n */\n async setSpeed(throttleId: string, speed: number): Promise<void> {\n const state = this.throttles.get(throttleId);\n if (!state) {\n throw new Error(`Throttle not found: ${throttleId}`);\n }\n\n if (!isValidSpeed(speed)) {\n throw new Error(`Invalid speed: ${speed}. Must be between 0.0 and 1.0`);\n }\n\n const message: ThrottleMessage = {\n type: 'throttle',\n data: {\n throttle: throttleId,\n speed\n }\n };\n\n // JMRI doesn't send responses for throttle control commands, just send\n this.client.send(message);\n\n state.speed = speed;\n this.emit('throttle:updated', throttleId, { speed });\n }\n\n /**\n * Set throttle direction\n */\n async setDirection(throttleId: string, forward: boolean): Promise<void> {\n const state = this.throttles.get(throttleId);\n if (!state) {\n throw new Error(`Throttle not found: ${throttleId}`);\n }\n\n const message: ThrottleMessage = {\n type: 'throttle',\n data: {\n throttle: throttleId,\n forward\n }\n };\n\n // JMRI doesn't send responses for throttle control commands, just send\n this.client.send(message);\n\n state.forward = forward;\n this.emit('throttle:updated', throttleId, { forward });\n }\n\n /**\n * Set throttle function (F0-F28)\n */\n async setFunction(throttleId: string, functionKey: ThrottleFunctionKey, value: boolean): Promise<void> {\n const state = this.throttles.get(throttleId);\n if (!state) {\n throw new Error(`Throttle not found: ${throttleId}`);\n }\n\n if (!isThrottleFunctionKey(functionKey)) {\n throw new Error(`Invalid function key: ${functionKey}`);\n }\n\n const data: ThrottleData = {\n throttle: throttleId,\n [functionKey]: value\n };\n\n const message: ThrottleMessage = {\n type: 'throttle',\n data\n };\n\n // JMRI doesn't send responses for throttle control commands, just send\n this.client.send(message);\n\n state.functions.set(functionKey, value);\n this.emit('throttle:updated', throttleId, { [functionKey]: value });\n }\n\n /**\n * Emergency stop for a throttle (speed to 0)\n */\n async emergencyStop(throttleId: string): Promise<void> {\n await this.setSpeed(throttleId, 0);\n }\n\n /**\n * Set throttle to idle (speed to 0, maintain direction)\n */\n async idle(throttleId: string): Promise<void> {\n await this.setSpeed(throttleId, 0);\n }\n\n /**\n * Get throttle state\n */\n getThrottleState(throttleId: string): ThrottleState | undefined {\n return this.throttles.get(throttleId);\n }\n\n /**\n * Get all throttle IDs\n */\n getThrottleIds(): string[] {\n return Array.from(this.throttles.keys());\n }\n\n /**\n * Get all throttle states\n */\n getAllThrottles(): ThrottleState[] {\n return Array.from(this.throttles.values());\n }\n\n /**\n * Release all throttles\n */\n async releaseAllThrottles(): Promise<void> {\n const throttleIds = this.getThrottleIds();\n\n for (const throttleId of throttleIds) {\n try {\n await this.releaseThrottle(throttleId);\n } catch (error) {\n // Continue releasing others even if one fails\n this.emit('error', error);\n }\n }\n }\n\n /**\n * Handle unsolicited throttle updates from JMRI\n */\n private handleThrottleUpdate(message: ThrottleMessage): void {\n const throttleId = message.data?.throttle;\n if (!throttleId) {\n return;\n }\n\n const state = this.throttles.get(throttleId);\n if (!state) {\n // Unknown throttle, possibly lost\n this.emit('throttle:lost', throttleId);\n return;\n }\n\n // Update state from message\n if (message.data.speed !== undefined) {\n state.speed = message.data.speed;\n }\n\n if (message.data.forward !== undefined) {\n state.forward = message.data.forward;\n }\n\n // Update functions\n for (let i = 0; i <= 28; i++) {\n const key = `F${i}` as ThrottleFunctionKey;\n if (message.data[key] !== undefined) {\n state.functions.set(key, message.data[key]!);\n }\n }\n\n this.emit('throttle:updated', throttleId, message.data);\n }\n\n /**\n * Handle disconnect - mark all throttles as not acquired\n */\n private handleDisconnect(): void {\n for (const state of this.throttles.values()) {\n state.acquired = false;\n }\n }\n}\n", "/**\n * Client configuration options\n */\n\n/**\n * Reconnection strategy options\n */\nexport interface ReconnectionOptions {\n /**\n * Enable automatic reconnection (default: true)\n */\n enabled: boolean;\n\n /**\n * Maximum number of reconnection attempts (0 = infinite, default: 0)\n */\n maxAttempts: number;\n\n /**\n * Initial delay in milliseconds (default: 1000)\n */\n initialDelay: number;\n\n /**\n * Maximum delay in milliseconds (default: 30000)\n */\n maxDelay: number;\n\n /**\n * Backoff multiplier (default: 1.5)\n */\n multiplier: number;\n\n /**\n * Add jitter to prevent thundering herd (default: true)\n * Jitter is \u00B125% of calculated delay\n */\n jitter: boolean;\n}\n\n/**\n * Heartbeat (ping/pong) options\n */\nexport interface HeartbeatOptions {\n /**\n * Enable heartbeat (default: true)\n */\n enabled: boolean;\n\n /**\n * Interval between pings in milliseconds (default: 30000)\n */\n interval: number;\n\n /**\n * Timeout waiting for pong in milliseconds (default: 5000)\n */\n timeout: number;\n}\n\n/**\n * Mock mode options\n */\nexport interface MockOptions {\n /**\n * Enable mock mode (default: false)\n * When enabled, all responses are generated from mock data instead of a real JMRI server\n */\n enabled: boolean;\n\n /**\n * Delay in milliseconds before returning mock responses (default: 50)\n * Simulates network latency. Set to 0 for instant responses.\n */\n responseDelay: number;\n}\n\n/**\n * JMRI client configuration options\n */\nexport interface JmriClientOptions {\n /**\n * JMRI server hostname or IP address (default: 'localhost')\n */\n host: string;\n\n /**\n * JMRI server WebSocket port (default: 12080)\n */\n port: number;\n\n /**\n * WebSocket protocol (default: 'ws', use 'wss' for secure)\n */\n protocol: 'ws' | 'wss';\n\n /**\n * Automatically connect on instantiation (default: true)\n */\n autoConnect: boolean;\n\n /**\n * Reconnection strategy\n */\n reconnection: ReconnectionOptions;\n\n /**\n * Heartbeat/ping configuration\n */\n heartbeat: HeartbeatOptions;\n\n /**\n * Maximum number of messages to queue when disconnected (default: 100)\n */\n messageQueueSize: number;\n\n /**\n * Default timeout for request/response in milliseconds (default: 10000)\n */\n requestTimeout: number;\n\n /**\n * Mock mode configuration (default: disabled)\n * Use mock responses instead of a real JMRI server\n */\n mock: MockOptions;\n}\n\n/**\n * Default client options\n */\nexport const DEFAULT_CLIENT_OPTIONS: JmriClientOptions = {\n host: 'localhost',\n port: 12080,\n protocol: 'ws',\n autoConnect: true,\n reconnection: {\n enabled: true,\n maxAttempts: 0, // infinite\n initialDelay: 1000,\n maxDelay: 30000,\n multiplier: 1.5,\n jitter: true\n },\n heartbeat: {\n enabled: true,\n interval: 30000,\n timeout: 5000\n },\n messageQueueSize: 100,\n requestTimeout: 10000,\n mock: {\n enabled: false,\n responseDelay: 50\n }\n};\n\n/**\n * Partial client options for user input (all fields optional)\n */\nexport type PartialClientOptions = Partial<{\n host: string;\n port: number;\n protocol: 'ws' | 'wss';\n autoConnect: boolean;\n reconnection: Partial<ReconnectionOptions>;\n heartbeat: Partial<HeartbeatOptions>;\n messageQueueSize: number;\n requestTimeout: number;\n mock: Partial<MockOptions>;\n}>;\n\n/**\n * Merge user options with defaults\n */\nexport function mergeOptions(userOptions?: PartialClientOptions): JmriClientOptions {\n const options = { ...DEFAULT_CLIENT_OPTIONS };\n\n if (!userOptions) {\n return options;\n }\n\n if (userOptions.host !== undefined) options.host = userOptions.host;\n if (userOptions.port !== undefined) options.port = userOptions.port;\n if (userOptions.protocol !== undefined) options.protocol = userOptions.protocol;\n if (userOptions.autoConnect !== undefined) options.autoConnect = userOptions.autoConnect;\n if (userOptions.messageQueueSize !== undefined) options.messageQueueSize = userOptions.messageQueueSize;\n if (userOptions.requestTimeout !== undefined) options.requestTimeout = userOptions.requestTimeout;\n\n if (userOptions.reconnection) {\n options.reconnection = { ...DEFAULT_CLIENT_OPTIONS.reconnection, ...userOptions.reconnection };\n }\n\n if (userOptions.heartbeat) {\n options.heartbeat = { ...DEFAULT_CLIENT_OPTIONS.heartbeat, ...userOptions.heartbeat };\n }\n\n if (userOptions.mock) {\n options.mock = { ...DEFAULT_CLIENT_OPTIONS.mock, ...userOptions.mock };\n }\n\n return options;\n}\n", "/**\n * Main JMRI client class\n */\n\nimport { EventEmitter } from 'eventemitter3';\nimport { WebSocketClient } from './core/websocket-client.js';\nimport { PowerManager } from './managers/power-manager.js';\nimport { RosterManager } from './managers/roster-manager.js';\nimport { ThrottleManager } from './managers/throttle-manager.js';\nimport { JmriClientOptions, PartialClientOptions, mergeOptions } from './types/client-options.js';\nimport { PowerState, RosterEntry } from './types/jmri-messages.js';\nimport { ConnectionState } from './types/events.js';\nimport { ThrottleAcquireOptions, ThrottleFunctionKey, ThrottleState } from './types/throttle.js';\n\n/**\n * JMRI WebSocket Client\n * Provides event-driven interface to JMRI with throttle control\n */\nexport class JmriClient extends EventEmitter {\n private options: JmriClientOptions;\n private wsClient: WebSocketClient;\n private powerManager: PowerManager;\n private rosterManager: RosterManager;\n private throttleManager: ThrottleManager;\n\n /**\n * Create a new JMRI client\n *\n * @param options - Client configuration options\n *\n * @example\n * ```typescript\n * const client = new JmriClient({\n * host: 'jmri.local',\n * port: 12080\n * });\n *\n * client.on('connected', () => console.log('Connected!'));\n * client.on('power:changed', (state) => console.log('Power:', state));\n * ```\n */\n constructor(options?: PartialClientOptions) {\n super();\n\n // Merge options with defaults\n this.options = mergeOptions(options);\n\n // Create WebSocket client\n this.wsClient = new WebSocketClient(this.options);\n\n // Create managers\n this.powerManager = new PowerManager(this.wsClient);\n this.rosterManager = new RosterManager(this.wsClient);\n this.throttleManager = new ThrottleManager(this.wsClient);\n\n // Forward events from WebSocket client\n this.wsClient.on('connected', () => this.emit('connected'));\n this.wsClient.on('disconnected', (reason: string) => this.emit('disconnected', reason));\n this.wsClient.on('reconnecting', (attempt: number, delay: number) =>\n this.emit('reconnecting', attempt, delay)\n );\n this.wsClient.on('reconnected', () => this.emit('reconnected'));\n this.wsClient.on('reconnectionFailed', (attempts: number) =>\n this.emit('reconnectionFailed', attempts)\n );\n this.wsClient.on('connectionStateChanged', (state: ConnectionState) =>\n this.emit('connectionStateChanged', state)\n );\n this.wsClient.on('error', (error: Error) => this.emit('error', error));\n this.wsClient.on('heartbeat:sent', () => this.emit('heartbeat:sent'));\n this.wsClient.on('heartbeat:timeout', () => this.emit('heartbeat:timeout'));\n\n // Forward events from managers\n this.powerManager.on('power:changed', (state: PowerState) =>\n this.emit('power:changed', state)\n );\n this.throttleManager.on('throttle:acquired', (id: string) =>\n this.emit('throttle:acquired', id)\n );\n this.throttleManager.on('throttle:updated', (id: string, data: any) =>\n this.emit('throttle:updated', id, data)\n );\n this.throttleManager.on('throttle:released', (id: string) =>\n this.emit('throttle:released', id)\n );\n this.throttleManager.on('throttle:lost', (id: string) =>\n this.emit('throttle:lost', id)\n );\n\n // Auto-connect if enabled\n if (this.options.autoConnect) {\n this.connect().catch((error) => {\n this.emit('error', error);\n });\n }\n }\n\n /**\n * Connect to JMRI server\n */\n async connect(): Promise<void> {\n return this.wsClient.connect();\n }\n\n /**\n * Disconnect from JMRI server\n * Releases all throttles and closes connection\n */\n async disconnect(): Promise<void> {\n // Release all throttles first\n await this.throttleManager.releaseAllThrottles();\n\n // Disconnect WebSocket\n return this.wsClient.disconnect();\n }\n\n /**\n * Get current connection state\n */\n getConnectionState(): ConnectionState {\n return this.wsClient.getState();\n }\n\n /**\n * Check if connected to JMRI\n */\n isConnected(): boolean {\n return this.wsClient.isConnected();\n }\n\n // ============================================================================\n // Power Control\n // ============================================================================\n\n /**\n * Get current track power state\n */\n async getPower(): Promise<PowerState> {\n return this.powerManager.getPower();\n }\n\n /**\n * Set track power state\n */\n async setPower(state: PowerState): Promise<void> {\n return this.powerManager.setPower(state);\n }\n\n /**\n * Turn track power on\n */\n async powerOn(): Promise<void> {\n return this.powerManager.powerOn();\n }\n\n /**\n * Turn track power off\n */\n async powerOff(): Promise<void> {\n return this.powerManager.powerOff();\n }\n\n // ============================================================================\n // Roster Management\n // ============================================================================\n\n /**\n * Get all roster entries\n */\n async getRoster(): Promise<RosterEntry[]> {\n return this.rosterManager.getRoster();\n }\n\n /**\n * Get roster entry by name\n */\n async getRosterEntryByName(name: string): Promise<RosterEntry | undefined> {\n return this.rosterManager.getRosterEntryByName(name);\n }\n\n /**\n * Get roster entry by address\n */\n async getRosterEntryByAddress(address: string | number): Promise<RosterEntry | undefined> {\n return this.rosterManager.getRosterEntryByAddress(address);\n }\n\n /**\n * Search roster by partial name match\n */\n async searchRoster(query: string): Promise<RosterEntry[]> {\n return this.rosterManager.searchRoster(query);\n }\n\n // ============================================================================\n // Throttle Control\n // ============================================================================\n\n /**\n * Acquire a throttle for a locomotive\n *\n * @param options - Throttle acquisition options\n * @returns Throttle ID for use in other throttle methods\n *\n * @example\n * ```typescript\n * const throttleId = await client.acquireThrottle({ address: 3 });\n * await client.setThrottleSpeed(throttleId, 0.5); // Half speed\n * ```\n */\n async acquireThrottle(options: ThrottleAcquireOptions): Promise<string> {\n return this.throttleManager.acquireThrottle(options);\n }\n\n /**\n * Release a throttle\n */\n async releaseThrottle(throttleId: string): Promise<void> {\n return this.throttleManager.releaseThrottle(throttleId);\n }\n\n /**\n * Set throttle speed (0.0 to 1.0)\n *\n * @param throttleId - Throttle ID from acquireThrottle\n * @param speed - Speed value between 0.0 (stopped) and 1.0 (full speed)\n */\n async setThrottleSpeed(throttleId: string, speed: number): Promise<void> {\n return this.throttleManager.setSpeed(throttleId, speed);\n }\n\n /**\n * Set throttle direction\n *\n * @param throttleId - Throttle ID from acquireThrottle\n * @param forward - True for forward, false for reverse\n */\n async setThrottleDirection(throttleId: string, forward: boolean): Promise<void> {\n return this.throttleManager.setDirection(throttleId, forward);\n }\n\n /**\n * Set throttle function (F0-F28)\n *\n * @param throttleId - Throttle ID from acquireThrottle\n * @param functionKey - Function key (F0-F28)\n * @param value - True to activate, false to deactivate\n *\n * @example\n * ```typescript\n * await client.setThrottleFunction(throttleId, 'F0', true); // Headlight on\n * await client.setThrottleFunction(throttleId, 'F2', true); // Horn\n * ```\n */\n async setThrottleFunction(\n throttleId: string,\n functionKey: ThrottleFunctionKey,\n value: boolean\n ): Promise<void> {\n return this.throttleManager.setFunction(throttleId, functionKey, value);\n }\n\n /**\n * Emergency stop for a throttle (speed to 0)\n */\n async emergencyStop(throttleId: string): Promise<void> {\n return this.throttleManager.emergencyStop(throttleId);\n }\n\n /**\n * Set throttle to idle (speed to 0, maintain direction)\n */\n async idleThrottle(throttleId: string): Promise<void> {\n return this.throttleManager.idle(throttleId);\n }\n\n /**\n * Get throttle state\n */\n getThrottleState(throttleId: string): ThrottleState | undefined {\n return this.throttleManager.getThrottleState(throttleId);\n }\n\n /**\n * Get all throttle IDs\n */\n getThrottleIds(): string[] {\n return this.throttleManager.getThrottleIds();\n }\n\n /**\n * Get all throttle states\n */\n getAllThrottles(): ThrottleState[] {\n return this.throttleManager.getAllThrottles();\n }\n\n /**\n * Release all throttles\n */\n async releaseAllThrottles(): Promise<void> {\n return this.throttleManager.releaseAllThrottles();\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["'use strict';\n\nvar has = Object.prototype.hasOwnProperty\n , prefix = '~';\n\n/**\n * Constructor to create a storage for our `EE` objects.\n * An `Events` instance is a plain object whose properties are event names.\n *\n * @constructor\n * @private\n */\nfunction Events() {}\n\n//\n// We try to not inherit from `Object.prototype`. In some engines creating an\n// instance in this way is faster than calling `Object.create(null)` directly.\n// If `Object.create(null)` is not supported we prefix the event names with a\n// character to make sure that the built-in object properties are not\n// overridden or used as an attack vector.\n//\nif (Object.create) {\n Events.prototype = Object.create(null);\n\n //\n // This hack is needed because the `__proto__` property is still inherited in\n // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.\n //\n if (!new Events().__proto__) prefix = false;\n}\n\n/**\n * Representation of a single event listener.\n *\n * @param {Function} fn The listener function.\n * @param {*} context The context to invoke the listener with.\n * @param {Boolean} [once=false] Specify if the listener is a one-time listener.\n * @constructor\n * @private\n */\nfunction EE(fn, context, once) {\n this.fn = fn;\n this.context = context;\n this.once = once || false;\n}\n\n/**\n * Add a listener for a given event.\n *\n * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} context The context to invoke the listener with.\n * @param {Boolean} once Specify if the listener is a one-time listener.\n * @returns {EventEmitter}\n * @private\n */\nfunction addListener(emitter, event, fn, context, once) {\n if (typeof fn !== 'function') {\n throw new TypeError('The listener must be a function');\n }\n\n var listener = new EE(fn, context || emitter, once)\n , evt = prefix ? prefix + event : event;\n\n if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;\n else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);\n else emitter._events[evt] = [emitter._events[evt], listener];\n\n return emitter;\n}\n\n/**\n * Clear event by name.\n *\n * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.\n * @param {(String|Symbol)} evt The Event name.\n * @private\n */\nfunction clearEvent(emitter, evt) {\n if (--emitter._eventsCount === 0) emitter._events = new Events();\n else delete emitter._events[evt];\n}\n\n/**\n * Minimal `EventEmitter` interface that is molded against the Node.js\n * `EventEmitter` interface.\n *\n * @constructor\n * @public\n */\nfunction EventEmitter() {\n this._events = new Events();\n this._eventsCount = 0;\n}\n\n/**\n * Return an array listing the events for which the emitter has registered\n * listeners.\n *\n * @returns {Array}\n * @public\n */\nEventEmitter.prototype.eventNames = function eventNames() {\n var names = []\n , events\n , name;\n\n if (this._eventsCount === 0) return names;\n\n for (name in (events = this._events)) {\n if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);\n }\n\n if (Object.getOwnPropertySymbols) {\n return names.concat(Object.getOwnPropertySymbols(events));\n }\n\n return names;\n};\n\n/**\n * Return the listeners registered for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Array} The registered listeners.\n * @public\n */\nEventEmitter.prototype.listeners = function listeners(event) {\n var evt = prefix ? prefix + event : event\n , handlers = this._events[evt];\n\n if (!handlers) return [];\n if (handlers.fn) return [handlers.fn];\n\n for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {\n ee[i] = handlers[i].fn;\n }\n\n return ee;\n};\n\n/**\n * Return the number of listeners listening to a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Number} The number of listeners.\n * @public\n */\nEventEmitter.prototype.listenerCount = function listenerCount(event) {\n var evt = prefix ? prefix + event : event\n , listeners = this._events[evt];\n\n if (!listeners) return 0;\n if (listeners.fn) return 1;\n return listeners.length;\n};\n\n/**\n * Calls each of the listeners registered for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Boolean} `true` if the event had listeners, else `false`.\n * @public\n */\nEventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {\n var evt = prefix ? prefix + event : event;\n\n if (!this._events[evt]) return false;\n\n var listeners = this._events[evt]\n , len = arguments.length\n , args\n , i;\n\n if (listeners.fn) {\n if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);\n\n switch (len) {\n case 1: return listeners.fn.call(listeners.context), true;\n case 2: return listeners.fn.call(listeners.context, a1), true;\n case 3: return listeners.fn.call(listeners.context, a1, a2), true;\n case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;\n case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;\n case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;\n }\n\n for (i = 1, args = new Array(len -1); i < len; i++) {\n args[i - 1] = arguments[i];\n }\n\n listeners.fn.apply(listeners.context, args);\n } else {\n var length = listeners.length\n , j;\n\n for (i = 0; i < length; i++) {\n if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);\n\n switch (len) {\n case 1: listeners[i].fn.call(listeners[i].context); break;\n case 2: listeners[i].fn.call(listeners[i].context, a1); break;\n case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;\n case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;\n default:\n if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {\n args[j - 1] = arguments[j];\n }\n\n listeners[i].fn.apply(listeners[i].context, args);\n }\n }\n }\n\n return true;\n};\n\n/**\n * Add a listener for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} [context=this] The context to invoke the listener with.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.on = function on(event, fn, context) {\n return addListener(this, event, fn, context, false);\n};\n\n/**\n * Add a one-time listener for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} [context=this] The context to invoke the listener with.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.once = function once(event, fn, context) {\n return addListener(this, event, fn, context, true);\n};\n\n/**\n * Remove the listeners of a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn Only remove the listeners that match this function.\n * @param {*} context Only remove the listeners that have this context.\n * @param {Boolean} once Only remove one-time listeners.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {\n var evt = prefix ? prefix + event : event;\n\n if (!this._events[evt]) return this;\n if (!fn) {\n clearEvent(this, evt);\n return this;\n }\n\n var listeners = this._events[evt];\n\n if (listeners.fn) {\n if (\n listeners.fn === fn &&\n (!once || listeners.once) &&\n (!context || listeners.context === context)\n ) {\n clearEvent(this, evt);\n }\n } else {\n for (var i = 0, events = [], length = listeners.length; i < length; i++) {\n if (\n listeners[i].fn !== fn ||\n (once && !listeners[i].once) ||\n (context && listeners[i].context !== context)\n ) {\n events.push(listeners[i]);\n }\n }\n\n //\n // Reset the array, or remove it completely if we have no more listeners.\n //\n if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;\n else clearEvent(this, evt);\n }\n\n return this;\n};\n\n/**\n * Remove all listeners, or those of the specified event.\n *\n * @param {(String|Symbol)} [event] The event name.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {\n var evt;\n\n if (event) {\n evt = prefix ? prefix + event : event;\n if (this._events[evt]) clearEvent(this, evt);\n } else {\n this._events = new Events();\n this._eventsCount = 0;\n }\n\n return this;\n};\n\n//\n// Alias methods names because people roll like that.\n//\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\nEventEmitter.prototype.addListener = EventEmitter.prototype.on;\n\n//\n// Expose the prefix.\n//\nEventEmitter.prefixed = prefix;\n\n//\n// Allow `EventEmitter` to be imported as module namespace.\n//\nEventEmitter.EventEmitter = EventEmitter;\n\n//\n// Expose the module.\n//\nif ('undefined' !== typeof module) {\n module.exports = EventEmitter;\n}\n", "'use strict';\n\nmodule.exports = function () {\n throw new Error(\n 'ws does not work in the browser. Browser clients must use the native ' +\n 'WebSocket object'\n );\n};\n", "import EventEmitter from './index.js'\n\nexport { EventEmitter }\nexport default EventEmitter\n", "/**\n * WebSocket Adapter\n * Provides a unified interface for WebSocket connections in both Node.js and browser environments\n */\n\nimport { EventEmitter } from 'eventemitter3';\n\n/**\n * WebSocket adapter interface\n */\nexport interface WebSocketAdapter extends EventEmitter {\n send(data: string): void;\n close(code?: number, reason?: string): void;\n readonly readyState: number;\n}\n\n/**\n * WebSocket ready states\n */\nexport enum ReadyState {\n CONNECTING = 0,\n OPEN = 1,\n CLOSING = 2,\n CLOSED = 3\n}\n\n/**\n * Create a WebSocket adapter for the current environment\n */\nexport async function createWebSocketAdapter(url: string, protocols?: string | string[]): Promise<WebSocketAdapter> {\n // Detect environment\n const isBrowser = typeof window !== 'undefined' && typeof window.WebSocket !== 'undefined';\n\n if (isBrowser) {\n return new BrowserWebSocketAdapter(url, protocols);\n } else {\n return await NodeWebSocketAdapter.create(url, protocols);\n }\n}\n\n/**\n * Browser WebSocket adapter\n * Wraps native browser WebSocket with EventEmitter interface\n */\nclass BrowserWebSocketAdapter extends EventEmitter implements WebSocketAdapter {\n private ws: WebSocket;\n\n constructor(url: string, protocols?: string | string[]) {\n super();\n\n this.ws = new WebSocket(url, protocols);\n\n this.ws.onopen = () => {\n this.emit('open');\n };\n\n this.ws.onmessage = (event: MessageEvent) => {\n this.emit('message', event.data);\n };\n\n this.ws.onerror = () => {\n this.emit('error', new Error('WebSocket error'));\n };\n\n this.ws.onclose = (event: CloseEvent) => {\n this.emit('close', event.code, event.reason);\n };\n }\n\n send(data: string): void {\n this.ws.send(data);\n }\n\n close(code?: number, reason?: string): void {\n this.ws.close(code, reason);\n }\n\n get readyState(): number {\n return this.ws.readyState;\n }\n}\n\n/**\n * Node.js WebSocket adapter\n * Wraps ws package with consistent interface\n */\nclass NodeWebSocketAdapter extends EventEmitter implements WebSocketAdapter {\n private ws: any;\n\n private constructor(ws: any) {\n super();\n this.ws = ws;\n\n this.ws.on('open', () => {\n this.emit('open');\n });\n\n this.ws.on('message', (data: any) => {\n // Convert Buffer to string if needed\n const message = typeof data === 'string' ? data : data.toString();\n this.emit('message', message);\n });\n\n this.ws.on('error', (error: Error) => {\n this.emit('error', error);\n });\n\n this.ws.on('close', (code: number, reason: string) => {\n this.emit('close', code, reason);\n });\n }\n\n static async create(url: string, protocols?: string | string[]): Promise<NodeWebSocketAdapter> {\n // Use dynamic import for ESM compatibility\n const { default: WebSocket } = await import('ws');\n const ws = new WebSocket(url, protocols);\n return new NodeWebSocketAdapter(ws);\n }\n\n send(data: string): void {\n this.ws.send(data);\n }\n\n close(code?: number, reason?: string): void {\n this.ws.close(code, reason);\n }\n\n get readyState(): number {\n return this.ws.readyState;\n }\n}\n", "/**\n * Event types for JmriClient EventEmitter\n */\n\nimport { PowerState } from './jmri-messages.js';\nimport { ThrottleData } from './jmri-messages.js';\n\n/**\n * Connection states\n */\nexport enum ConnectionState {\n DISCONNECTED = 'disconnected',\n CONNECTING = 'connecting',\n CONNECTED = 'connected',\n RECONNECTING = 'reconnecting'\n}\n\n/**\n * Event payload types\n */\nexport interface EventPayloads {\n // Connection events\n 'connected': void;\n 'disconnected': string; // reason\n 'reconnecting': [attempt: number, delay: number];\n 'reconnected': void;\n 'connectionStateChanged': ConnectionState;\n 'error': Error;\n\n // Power events\n 'power:changed': PowerState;\n\n // Throttle events\n 'throttle:acquired': string; // throttle ID\n 'throttle:updated': [throttleId: string, data: ThrottleData];\n 'throttle:released': string; // throttle ID\n 'throttle:lost': string; // throttle ID (server removed it)\n\n // Heartbeat events\n 'heartbeat:sent': void;\n 'heartbeat:timeout': void;\n\n // Message events\n 'message:sent': any;\n 'message:received': any;\n}\n\n/**\n * Event listener type\n */\nexport type EventListener<T> = (payload: T) => void;\n\n/**\n * Event map for type-safe event emitter\n */\nexport type EventMap = {\n [K in keyof EventPayloads]: EventPayloads[K] extends void\n ? () => void\n : EventPayloads[K] extends [infer A, infer B]\n ? (arg1: A, arg2: B) => void\n : (payload: EventPayloads[K]) => void;\n};\n", "/**\n * Message ID generator for request/response correlation\n */\n\n/**\n * Sequential message ID generator\n * Provides unique IDs for correlating requests and responses\n */\nexport class MessageIdGenerator {\n private currentId: number = 0;\n private readonly maxId: number = Number.MAX_SAFE_INTEGER;\n\n /**\n * Generate next sequential ID\n * Wraps around at MAX_SAFE_INTEGER\n */\n next(): number {\n this.currentId++;\n if (this.currentId >= this.maxId) {\n this.currentId = 1;\n }\n return this.currentId;\n }\n\n /**\n * Reset ID counter to 0\n */\n reset(): void {\n this.currentId = 0;\n }\n\n /**\n * Get current ID without incrementing\n */\n current(): number {\n return this.currentId;\n }\n}\n", "/**\n * Message queue for offline message handling\n */\n\nimport { JmriMessage } from '../types/jmri-messages.js';\n\n/**\n * Queue for storing messages when disconnected\n * Messages are sent when connection is restored\n */\nexport class MessageQueue {\n private queue: JmriMessage[] = [];\n private maxSize: number;\n\n constructor(maxSize: number = 100) {\n this.maxSize = maxSize;\n }\n\n /**\n * Add message to queue\n * If queue is full, oldest message is removed\n */\n enqueue(message: JmriMessage): void {\n if (this.queue.length >= this.maxSize) {\n this.queue.shift(); // Remove oldest\n }\n this.queue.push(message);\n }\n\n /**\n * Get all queued messages and clear queue\n */\n flush(): JmriMessage[] {\n const messages = [...this.queue];\n this.queue = [];\n return messages;\n }\n\n /**\n * Clear all queued messages without returning them\n */\n clear(): void {\n this.queue = [];\n }\n\n /**\n * Get number of queued messages\n */\n size(): number {\n return this.queue.length;\n }\n\n /**\n * Check if queue is empty\n */\n isEmpty(): boolean {\n return this.queue.length === 0;\n }\n\n /**\n * Check if queue is full\n */\n isFull(): boolean {\n return this.queue.length >= this.maxSize;\n }\n}\n", "/**\n * Connection state management with state machine\n */\n\nimport { EventEmitter } from 'eventemitter3';\nimport { ConnectionState } from '../types/events.js';\n\n/**\n * Valid state transitions\n */\nconst VALID_TRANSITIONS: Record<ConnectionState, ConnectionState[]> = {\n [ConnectionState.DISCONNECTED]: [ConnectionState.CONNECTING],\n [ConnectionState.CONNECTING]: [ConnectionState.CONNECTED, ConnectionState.DISCONNECTED],\n [ConnectionState.CONNECTED]: [ConnectionState.DISCONNECTED, ConnectionState.RECONNECTING],\n [ConnectionState.RECONNECTING]: [ConnectionState.CONNECTING, ConnectionState.CONNECTED, ConnectionState.DISCONNECTED]\n};\n\n/**\n * Manages connection state with validation\n */\nexport class ConnectionStateManager extends EventEmitter {\n private currentState: ConnectionState = ConnectionState.DISCONNECTED;\n\n /**\n * Get current connection state\n */\n getState(): ConnectionState {\n return this.currentState;\n }\n\n /**\n * Check if currently connected\n */\n isConnected(): boolean {\n return this.currentState === ConnectionState.CONNECTED;\n }\n\n /**\n * Check if currently connecting\n */\n isConnecting(): boolean {\n return this.currentState === ConnectionState.CONNECTING;\n }\n\n /**\n * Check if currently disconnected\n */\n isDisconnected(): boolean {\n return this.currentState === ConnectionState.DISCONNECTED;\n }\n\n /**\n * Check if currently reconnecting\n */\n isReconnecting(): boolean {\n return this.currentState === ConnectionState.RECONNECTING;\n }\n\n /**\n * Transition to new state\n * Validates transition and emits event\n */\n transition(newState: ConnectionState): void {\n const validTransitions = VALID_TRANSITIONS[this.currentState];\n\n if (!validTransitions.includes(newState)) {\n throw new Error(\n `Invalid state transition: ${this.currentState} -> ${newState}`\n );\n }\n\n const previousState = this.currentState;\n this.currentState = newState;\n\n this.emit('stateChanged', newState, previousState);\n }\n\n /**\n * Force state without validation (use with caution)\n */\n forceState(newState: ConnectionState): void {\n const previousState = this.currentState;\n this.currentState = newState;\n this.emit('stateChanged', newState, previousState);\n }\n\n /**\n * Reset to disconnected state\n */\n reset(): void {\n this.forceState(ConnectionState.DISCONNECTED);\n }\n}\n", "/**\n * Heartbeat (ping/pong) management\n */\n\nimport { EventEmitter } from 'eventemitter3';\nimport { HeartbeatOptions } from '../types/client-options.js';\n\n/**\n * Manages WebSocket heartbeat via ping/pong\n */\nexport class HeartbeatManager extends EventEmitter {\n private options: HeartbeatOptions;\n private pingInterval?: NodeJS.Timeout;\n private pongTimeout?: NodeJS.Timeout;\n private isRunning: boolean = false;\n\n constructor(options: HeartbeatOptions) {\n super();\n this.options = options;\n }\n\n /**\n * Start heartbeat monitoring\n * @param sendPing - Callback to send ping message\n */\n start(sendPing: () => void): void {\n if (!this.options.enabled || this.isRunning) {\n return;\n }\n\n this.isRunning = true;\n\n // Send ping at regular intervals\n this.pingInterval = setInterval(() => {\n sendPing();\n this.emit('pingSent');\n\n // Start pong timeout\n this.pongTimeout = setTimeout(() => {\n this.emit('timeout');\n }, this.options.timeout);\n }, this.options.interval);\n }\n\n /**\n * Stop heartbeat monitoring\n */\n stop(): void {\n this.isRunning = false;\n\n if (this.pingInterval) {\n clearInterval(this.pingInterval);\n this.pingInterval = undefined;\n }\n\n if (this.pongTimeout) {\n clearTimeout(this.pongTimeout);\n this.pongTimeout = undefined;\n }\n }\n\n /**\n * Handle pong received from server\n */\n receivedPong(): void {\n // Clear pong timeout\n if (this.pongTimeout) {\n clearTimeout(this.pongTimeout);\n this.pongTimeout = undefined;\n }\n this.emit('pongReceived');\n }\n\n /**\n * Check if heartbeat is running\n */\n running(): boolean {\n return this.isRunning;\n }\n\n /**\n * Update heartbeat options\n */\n updateOptions(options: Partial<HeartbeatOptions>): void {\n const wasRunning = this.isRunning;\n\n if (wasRunning) {\n this.stop();\n }\n\n this.options = { ...this.options, ...options };\n\n // Note: Caller must call start() again if needed\n }\n}\n", "/**\n * Exponential backoff calculator with jitter\n */\n\nimport { ReconnectionOptions } from '../types/client-options.js';\n\n/**\n * Calculate next reconnection delay using exponential backoff\n *\n * @param attempt - Current attempt number (1-indexed)\n * @param options - Reconnection options\n * @returns Delay in milliseconds\n */\nexport function calculateBackoffDelay(\n attempt: number,\n options: ReconnectionOptions\n): number {\n // Base delay calculation: initialDelay * (multiplier ^ (attempt - 1))\n const exponentialDelay = options.initialDelay * Math.pow(options.multiplier, attempt - 1);\n\n // Cap at maxDelay\n const cappedDelay = Math.min(exponentialDelay, options.maxDelay);\n\n // Add jitter if enabled (\u00B125%)\n if (options.jitter) {\n const jitterAmount = cappedDelay * 0.25;\n const jitter = (Math.random() * 2 - 1) * jitterAmount; // Random between -25% and +25%\n return Math.max(0, Math.round(cappedDelay + jitter));\n }\n\n return Math.round(cappedDelay);\n}\n\n/**\n * Check if should attempt reconnection\n *\n * @param attempt - Current attempt number (1-indexed)\n * @param maxAttempts - Maximum attempts (0 = infinite)\n * @returns True if should attempt reconnection\n */\nexport function shouldReconnect(attempt: number, maxAttempts: number): boolean {\n if (maxAttempts === 0) {\n return true; // Infinite attempts\n }\n return attempt <= maxAttempts;\n}\n", "/**\n * Automatic reconnection management with exponential backoff\n */\n\nimport { EventEmitter } from 'eventemitter3';\nimport { ReconnectionOptions } from '../types/client-options.js';\nimport { calculateBackoffDelay, shouldReconnect } from '../utils/exponential-backoff.js';\n\n/**\n * Manages automatic reconnection with exponential backoff\n */\nexport class ReconnectionManager extends EventEmitter {\n private options: ReconnectionOptions;\n private currentAttempt: number = 0;\n private reconnectTimeout?: NodeJS.Timeout;\n private isReconnecting: boolean = false;\n\n constructor(options: ReconnectionOptions) {\n super();\n this.options = options;\n }\n\n /**\n * Start reconnection process\n * @param reconnect - Callback to attempt reconnection\n */\n start(reconnect: () => Promise<void>): void {\n if (!this.options.enabled || this.isReconnecting) {\n return;\n }\n\n this.isReconnecting = true;\n this.currentAttempt = 0;\n this.scheduleNextAttempt(reconnect);\n }\n\n /**\n * Schedule next reconnection attempt\n */\n private scheduleNextAttempt(reconnect: () => Promise<void>): void {\n this.currentAttempt++;\n\n // Check if should continue trying\n if (!shouldReconnect(this.currentAttempt, this.options.maxAttempts)) {\n this.emit('maxAttemptsReached', this.currentAttempt - 1);\n this.stop();\n return;\n }\n\n // Calculate delay with backoff\n const delay = calculateBackoffDelay(this.currentAttempt, this.options);\n\n this.emit('attemptScheduled', this.currentAttempt, delay);\n\n // Schedule attempt\n this.reconnectTimeout = setTimeout(async () => {\n this.emit('attempting', this.currentAttempt);\n\n try {\n await reconnect();\n // Success - stop reconnection process\n this.stop();\n this.emit('success', this.currentAttempt);\n } catch (error) {\n // Failure - schedule next attempt\n this.emit('failed', this.currentAttempt, error);\n this.scheduleNextAttempt(reconnect);\n }\n }, delay);\n }\n\n /**\n * Stop reconnection process\n */\n stop(): void {\n this.isReconnecting = false;\n\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = undefined;\n }\n }\n\n /**\n * Reset attempt counter\n */\n reset(): void {\n this.stop();\n this.currentAttempt = 0;\n }\n\n /**\n * Check if currently reconnecting\n */\n reconnecting(): boolean {\n return this.isReconnecting;\n }\n\n /**\n * Get current attempt number\n */\n getAttempt(): number {\n return this.currentAttempt;\n }\n\n /**\n * Update reconnection options\n */\n updateOptions(options: Partial<ReconnectionOptions>): void {\n this.options = { ...this.options, ...options };\n }\n}\n", "/**\n * JMRI WebSocket Protocol Message Types\n * Based on JMRI JSON protocol specification\n */\n\n/**\n * Base message structure for JMRI WebSocket communication\n */\nexport interface JmriMessage {\n type: string;\n method?: 'get' | 'post' | 'put' | 'delete' | 'list';\n data?: any;\n id?: number;\n}\n\n/**\n * Power state values (from JMRI JSON protocol constants)\n * UNKNOWN = 0 (state cannot be determined)\n * ON = 2 (power is on)\n * OFF = 4 (power is off)\n */\nexport enum PowerState {\n UNKNOWN = 0,\n ON = 2,\n OFF = 4\n}\n\n/**\n * Convert PowerState enum to human-readable string\n * @param state - The power state\n * @returns 'ON', 'OFF', or 'UNKNOWN'\n */\nexport function powerStateToString(state: PowerState): string {\n switch (state) {\n case PowerState.ON:\n return 'ON';\n case PowerState.OFF:\n return 'OFF';\n case PowerState.UNKNOWN:\n return 'UNKNOWN';\n default:\n return 'UNKNOWN';\n }\n}\n\n/**\n * Power message data\n */\nexport interface PowerData {\n state: PowerState;\n}\n\n/**\n * Power message\n */\nexport interface PowerMessage extends JmriMessage {\n type: 'power';\n data?: PowerData;\n}\n\n/**\n * Throttle data structure\n */\nexport interface ThrottleData {\n address?: number | string;\n throttle?: string;\n speed?: number;\n forward?: boolean;\n release?: null;\n status?: string;\n // Function keys F0-F28\n F0?: boolean;\n F1?: boolean;\n F2?: boolean;\n F3?: boolean;\n F4?: boolean;\n F5?: boolean;\n F6?: boolean;\n F7?: boolean;\n F8?: boolean;\n F9?: boolean;\n F10?: boolean;\n F11?: boolean;\n F12?: boolean;\n F13?: boolean;\n F14?: boolean;\n F15?: boolean;\n F16?: boolean;\n F17?: boolean;\n F18?: boolean;\n F19?: boolean;\n F20?: boolean;\n F21?: boolean;\n F22?: boolean;\n F23?: boolean;\n F24?: boolean;\n F25?: boolean;\n F26?: boolean;\n F27?: boolean;\n F28?: boolean;\n}\n\n/**\n * Throttle message\n */\nexport interface ThrottleMessage extends JmriMessage {\n type: 'throttle';\n data: ThrottleData;\n}\n\n/**\n * Roster entry\n */\nexport interface RosterEntry {\n name: string;\n address: string;\n isLongAddress: boolean;\n road?: string;\n number?: string;\n mfg?: string;\n model?: string;\n comment?: string;\n maxSpeed?: number;\n imageFilePath?: string;\n iconFilePath?: string;\n functionKeys?: { [key: string]: string };\n}\n\n/**\n * Roster data structure\n */\nexport interface RosterData {\n [key: string]: RosterEntry;\n}\n\n/**\n * Roster message\n */\nexport interface RosterMessage extends JmriMessage {\n type: 'roster';\n method: 'list';\n data?: RosterData;\n}\n\n/**\n * Ping message (heartbeat)\n */\nexport interface PingMessage extends JmriMessage {\n type: 'ping';\n}\n\n/**\n * Pong message (heartbeat response)\n */\nexport interface PongMessage extends JmriMessage {\n type: 'pong';\n}\n\n/**\n * Hello message (connection establishment)\n */\nexport interface HelloMessage extends JmriMessage {\n type: 'hello';\n data?: {\n JMRI?: string;\n JSON?: string;\n Railroad?: string;\n node?: string;\n activeProfile?: string;\n };\n}\n\n/**\n * Goodbye message (graceful disconnect)\n */\nexport interface GoodbyeMessage extends JmriMessage {\n type: 'goodbye';\n}\n\n/**\n * Error message from JMRI\n */\nexport interface ErrorMessage extends JmriMessage {\n type: 'error';\n data: {\n code: number;\n message: string;\n };\n}\n\n/**\n * Union type of all possible JMRI messages\n */\nexport type AnyJmriMessage =\n | PowerMessage\n | ThrottleMessage\n | RosterMessage\n | PingMessage\n | PongMessage\n | HelloMessage\n | GoodbyeMessage\n | ErrorMessage;\n", "/**\n * Mock data for JMRI responses\n * Used for testing and demo mode\n */\n\nexport const mockData = {\n \"hello\": {\n \"type\": \"hello\",\n \"data\": {\n \"JMRI\": \"5.9.2\",\n \"JSON\": \"5.0\",\n \"Railroad\": \"Demo Railroad\",\n \"node\": \"jmri-server\",\n \"activeProfile\": \"Demo Profile\"\n }\n },\n \"power\": {\n \"get\": {\n \"on\": {\n \"type\": \"power\",\n \"data\": {\n \"state\": 2\n }\n },\n \"off\": {\n \"type\": \"power\",\n \"data\": {\n \"state\": 4\n }\n }\n },\n \"post\": {\n \"success\": {\n \"type\": \"power\",\n \"data\": {\n \"state\": 2\n }\n }\n }\n },\n \"roster\": {\n \"list\": {\n \"type\": \"roster\",\n \"data\": {\n \"CSX754\": {\n \"name\": \"CSX754\",\n \"address\": \"754\",\n \"isLongAddress\": true,\n \"road\": \"CSX\",\n \"number\": \"754\",\n \"mfg\": \"Athearn\",\n \"model\": \"GP38-2\",\n \"comment\": \"Blue and yellow scheme\",\n \"maxSpeed\": 126,\n \"functionKeys\": {\n \"F0\": \"Headlight\",\n \"F1\": \"Bell\",\n \"F2\": \"Horn\",\n \"F3\": \"Air Release\",\n \"F4\": \"Dynamic Brake\"\n }\n },\n \"UP3985\": {\n \"name\": \"UP3985\",\n \"address\": \"3985\",\n \"isLongAddress\": true,\n \"road\": \"Union Pacific\",\n \"number\": \"3985\",\n \"mfg\": \"Rivarossi\",\n \"model\": \"Challenger 4-6-6-4\",\n \"comment\": \"Steam locomotive\",\n \"maxSpeed\": 126,\n \"functionKeys\": {\n \"F0\": \"Headlight\",\n \"F1\": \"Bell\",\n \"F2\": \"Whistle\",\n \"F3\": \"Steam\",\n \"F4\": \"Coupler\"\n }\n },\n \"BNSF5240\": {\n \"name\": \"BNSF5240\",\n \"address\": \"5240\",\n \"isLongAddress\": true,\n \"road\": \"BNSF\",\n \"number\": \"5240\",\n \"mfg\": \"Kato\",\n \"model\": \"SD40-2\",\n \"comment\": \"Heritage II paint\",\n \"maxSpeed\": 126,\n \"functionKeys\": {\n \"F0\": \"Headlight\",\n \"F1\": \"Bell\",\n \"F2\": \"Horn\",\n \"F3\": \"Dynamic Brake\",\n \"F4\": \"Mars Light\"\n }\n }\n }\n }\n },\n \"throttle\": {\n \"acquire\": {\n \"success\": {\n \"type\": \"throttle\",\n \"data\": {\n \"throttle\": \"{THROTTLE_ID}\",\n \"address\": \"{ADDRESS}\",\n \"speed\": 0,\n \"forward\": true,\n \"F0\": false,\n \"F1\": false,\n \"F2\": false,\n \"F3\": false,\n \"F4\": false\n }\n }\n },\n \"release\": {\n \"success\": {\n \"type\": \"throttle\",\n \"data\": {}\n }\n },\n \"control\": {\n \"speed\": {\n \"type\": \"throttle\",\n \"data\": {\n \"throttle\": \"{THROTTLE_ID}\",\n \"speed\": \"{SPEED}\"\n }\n },\n \"direction\": {\n \"type\": \"throttle\",\n \"data\": {\n \"throttle\": \"{THROTTLE_ID}\",\n \"forward\": \"{FORWARD}\"\n }\n },\n \"function\": {\n \"type\": \"throttle\",\n \"data\": {\n \"throttle\": \"{THROTTLE_ID}\",\n \"{FUNCTION}\": \"{VALUE}\"\n }\n }\n }\n },\n \"ping\": {\n \"type\": \"ping\"\n },\n \"pong\": {\n \"type\": \"pong\"\n },\n \"goodbye\": {\n \"type\": \"goodbye\"\n },\n \"error\": {\n \"throttleNotFound\": {\n \"type\": \"error\",\n \"data\": {\n \"code\": 404,\n \"message\": \"Throttle not found\"\n }\n },\n \"invalidSpeed\": {\n \"type\": \"error\",\n \"data\": {\n \"code\": 400,\n \"message\": \"Invalid speed value\"\n }\n },\n \"connectionError\": {\n \"type\": \"error\",\n \"data\": {\n \"code\": 500,\n \"message\": \"Connection error\"\n }\n }\n }\n} as const;\n", "/**\n * Mock Response Manager\n * Generates mock JMRI responses for testing and demo purposes\n */\n\nimport { JmriMessage, PowerState, PowerMessage, ThrottleMessage, RosterMessage, HelloMessage, PongMessage, GoodbyeMessage } from '../types/jmri-messages.js';\nimport { mockData } from './mock-data.js';\n\nexport interface MockResponseManagerOptions {\n /**\n * Delay in milliseconds before returning responses (simulates network latency)\n * Set to 0 for instant responses\n */\n responseDelay?: number;\n\n /**\n * Current power state (used to track state changes)\n */\n initialPowerState?: PowerState;\n}\n\n/**\n * Manages mock responses for JMRI protocol\n */\nexport class MockResponseManager {\n private responseDelay: number;\n private powerState: PowerState;\n private throttles: Map<string, any> = new Map();\n\n constructor(options: MockResponseManagerOptions = {}) {\n this.responseDelay = options.responseDelay ?? 50;\n this.powerState = options.initialPowerState ?? PowerState.OFF;\n }\n\n /**\n * Get a mock response for a given message\n */\n async getMockResponse(message: JmriMessage): Promise<JmriMessage | null> {\n // Simulate network delay\n if (this.responseDelay > 0) {\n await this.delay(this.responseDelay);\n }\n\n // Route to appropriate handler based on message type\n switch (message.type) {\n case 'hello':\n return this.getHelloResponse();\n\n case 'power':\n return this.getPowerResponse(message);\n\n case 'roster':\n return this.getRosterResponse(message);\n\n case 'throttle':\n return this.getThrottleResponse(message);\n\n case 'ping':\n return this.getPingResponse();\n\n case 'goodbye':\n return this.getGoodbyeResponse();\n\n default:\n return null;\n }\n }\n\n /**\n * Get hello response (connection establishment)\n */\n private getHelloResponse(): HelloMessage {\n return JSON.parse(JSON.stringify(mockData.hello));\n }\n\n /**\n * Get power response\n */\n private getPowerResponse(message: JmriMessage): PowerMessage {\n // Handle power state change\n if (message.data?.state !== undefined) {\n this.powerState = message.data.state;\n return {\n type: 'power',\n data: { state: this.powerState }\n };\n }\n\n // Return current power state\n return {\n type: 'power',\n data: { state: this.powerState }\n };\n }\n\n /**\n * Get roster response\n */\n private getRosterResponse(message: JmriMessage): RosterMessage {\n if (message.type === 'roster' && message.method === 'list') {\n return JSON.parse(JSON.stringify(mockData.roster.list));\n }\n\n return {\n type: 'roster',\n method: 'list',\n data: {}\n };\n }\n\n /**\n * Get throttle response\n */\n private getThrottleResponse(message: JmriMessage): ThrottleMessage {\n const data = message.data || {};\n\n // Acquire throttle\n if (data.address !== undefined && !data.throttle) {\n const throttleId = data.name || `MOCK-${data.address}`;\n const throttleState = {\n throttle: throttleId,\n address: data.address,\n speed: 0,\n forward: true,\n F0: false,\n F1: false,\n F2: false,\n F3: false,\n F4: false\n };\n\n this.throttles.set(throttleId, throttleState);\n\n return {\n type: 'throttle',\n data: { ...throttleState }\n };\n }\n\n // Release throttle\n if (data.release !== undefined && data.throttle) {\n this.throttles.delete(data.throttle);\n return {\n type: 'throttle',\n data: {}\n };\n }\n\n // Throttle control (speed, direction, functions)\n if (data.throttle) {\n const throttleState = this.throttles.get(data.throttle);\n\n if (!throttleState) {\n // Throttle not found - this shouldn't normally happen in mock mode\n // but we'll create it on the fly\n const newState = {\n throttle: data.throttle,\n address: 0,\n speed: 0,\n forward: true\n };\n this.throttles.set(data.throttle, newState);\n return {\n type: 'throttle',\n data: { ...newState }\n };\n }\n\n // Update throttle state\n if (data.speed !== undefined) {\n throttleState.speed = data.speed;\n }\n if (data.forward !== undefined) {\n throttleState.forward = data.forward;\n }\n\n // Update function keys\n for (let i = 0; i <= 28; i++) {\n const key = `F${i}`;\n if (data[key] !== undefined) {\n throttleState[key] = data[key];\n }\n }\n\n // Return updated state (no response for throttle control commands)\n return {\n type: 'throttle',\n data: {}\n };\n }\n\n return {\n type: 'throttle',\n data: {}\n };\n }\n\n /**\n * Get ping response (pong)\n */\n private getPingResponse(): PongMessage {\n return JSON.parse(JSON.stringify(mockData.pong));\n }\n\n /**\n * Get goodbye response\n */\n private getGoodbyeResponse(): GoodbyeMessage {\n return JSON.parse(JSON.stringify(mockData.goodbye));\n }\n\n /**\n * Get current power state\n */\n getPowerState(): PowerState {\n return this.powerState;\n }\n\n /**\n * Set power state (for testing)\n */\n setPowerState(state: PowerState): void {\n this.powerState = state;\n }\n\n /**\n * Get all throttles (for testing)\n */\n getThrottles(): Map<string, any> {\n return this.throttles;\n }\n\n /**\n * Reset all state (for testing)\n */\n reset(): void {\n this.powerState = PowerState.OFF;\n this.throttles.clear();\n }\n\n /**\n * Delay helper\n */\n private delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}\n\n/**\n * Singleton instance for shared use across tests\n */\nexport const mockResponseManager = new MockResponseManager({ responseDelay: 0 });\n", "/**\n * Core WebSocket client for JMRI communication\n */\n\nimport { EventEmitter } from 'eventemitter3';\nimport { createWebSocketAdapter, WebSocketAdapter } from './websocket-adapter.js';\nimport { JmriClientOptions } from '../types/client-options.js';\nimport { JmriMessage, AnyJmriMessage, GoodbyeMessage } from '../types/jmri-messages.js';\nimport { ConnectionState } from '../types/events.js';\nimport { MessageIdGenerator } from '../utils/message-id.js';\nimport { MessageQueue } from './message-queue.js';\nimport { ConnectionStateManager } from './connection-state-manager.js';\nimport { HeartbeatManager } from './heartbeat-manager.js';\nimport { ReconnectionManager } from './reconnection-manager.js';\nimport { MockResponseManager } from '../mocks/index.js';\n\n/**\n * Pending request tracking\n */\ninterface PendingRequest {\n resolve: (value: any) => void;\n reject: (error: Error) => void;\n timeout: NodeJS.Timeout;\n messageType?: string;\n matchKey?: string;\n}\n\n/**\n * Core WebSocket client\n */\nexport class WebSocketClient extends EventEmitter {\n private options: JmriClientOptions;\n private ws?: WebSocketAdapter;\n private url: string;\n\n // Sub-managers\n private messageIdGen: MessageIdGenerator;\n private messageQueue: MessageQueue;\n private stateManager: ConnectionStateManager;\n private heartbeatManager: HeartbeatManager;\n private reconnectionManager: ReconnectionManager;\n private mockManager?: MockResponseManager;\n\n // Request/response tracking\n private pendingRequests: Map<number, PendingRequest> = new Map();\n\n // Connection state\n private isManualDisconnect: boolean = false;\n\n constructor(options: JmriClientOptions) {\n super();\n this.options = options;\n this.url = `${options.protocol}://${options.host}:${options.port}/json/`;\n\n // Initialize sub-managers\n this.messageIdGen = new MessageIdGenerator();\n this.messageQueue = new MessageQueue(options.messageQueueSize);\n this.stateManager = new ConnectionStateManager();\n this.heartbeatManager = new HeartbeatManager(options.heartbeat);\n this.reconnectionManager = new ReconnectionManager(options.reconnection);\n\n // Initialize mock manager if mock mode is enabled\n if (options.mock.enabled) {\n this.mockManager = new MockResponseManager({\n responseDelay: options.mock.responseDelay\n });\n }\n\n // Wire up state manager events\n this.stateManager.on('stateChanged', (newState: ConnectionState, prevState: ConnectionState) => {\n this.emit('connectionStateChanged', newState, prevState);\n });\n\n // Wire up heartbeat events\n this.heartbeatManager.on('timeout', () => {\n this.emit('heartbeat:timeout');\n this.handleHeartbeatTimeout();\n });\n\n this.heartbeatManager.on('pingSent', () => {\n this.emit('heartbeat:sent');\n });\n\n // Wire up reconnection events\n this.reconnectionManager.on('attemptScheduled', (attempt: number, delay: number) => {\n this.emit('reconnecting', attempt, delay);\n });\n\n this.reconnectionManager.on('success', () => {\n this.emit('reconnected');\n });\n\n this.reconnectionManager.on('maxAttemptsReached', (attempts: number) => {\n this.emit('reconnectionFailed', attempts);\n });\n\n this.reconnectionManager.on('debug', (message: string) => {\n this.emit('debug', message);\n });\n }\n\n /**\n * Connect to JMRI WebSocket server (or mock)\n */\n async connect(): Promise<void> {\n if (this.stateManager.isConnected() || this.stateManager.isConnecting()) {\n return;\n }\n\n this.isManualDisconnect = false;\n this.stateManager.transition(ConnectionState.CONNECTING);\n\n // Mock mode - simulate connection\n if (this.mockManager) {\n return this.connectMock();\n }\n\n // Real WebSocket connection\n return new Promise(async (resolve, reject) => {\n try {\n this.ws = await createWebSocketAdapter(this.url);\n\n this.ws.on('open', () => {\n this.handleOpen();\n resolve();\n });\n\n this.ws.on('message', (data: string) => {\n this.handleMessage(data);\n });\n\n this.ws.on('close', (code: number, reason: string) => {\n // If close happens during connection attempt, treat as connection failure\n if (this.stateManager.isConnecting()) {\n // Transition to disconnected state so reconnection can proceed\n this.stateManager.transition(ConnectionState.DISCONNECTED);\n const error = new Error(`WebSocket connection failed (code: ${code}${reason ? ', reason: ' + reason : ''})`);\n this.emit('error', error);\n reject(error);\n // Still need to handle close to trigger reconnection\n this.handleClose(code, reason);\n } else {\n this.handleClose(code, reason);\n }\n });\n\n this.ws.on('error', (error: Error) => {\n this.emit('error', error);\n if (this.stateManager.isConnecting()) {\n this.stateManager.transition(ConnectionState.DISCONNECTED);\n reject(error);\n }\n });\n } catch (error) {\n this.stateManager.transition(ConnectionState.DISCONNECTED);\n reject(error);\n }\n });\n }\n\n /**\n * Simulate connection in mock mode\n */\n private async connectMock(): Promise<void> {\n // Simulate connection delay\n await this.delay(10);\n\n // Transition to connected state\n this.handleOpen();\n\n // Send hello message in mock mode\n const helloResponse = await this.mockManager!.getMockResponse({ type: 'hello' });\n if (helloResponse) {\n this.emit('message:received', helloResponse);\n }\n }\n\n /**\n * Disconnect from JMRI WebSocket server\n */\n async disconnect(): Promise<void> {\n // Already disconnected, nothing to do\n if (this.stateManager.isDisconnected()) {\n return;\n }\n\n this.isManualDisconnect = true;\n this.reconnectionManager.stop();\n this.heartbeatManager.stop();\n\n // Send goodbye message\n if (this.stateManager.isConnected()) {\n try {\n await this.sendGoodbye();\n } catch (error) {\n // Ignore errors during goodbye\n }\n }\n\n // Close WebSocket\n if (this.ws) {\n this.ws.close();\n this.ws = undefined;\n }\n\n // Reject all pending requests\n this.rejectAllPendingRequests(new Error('Client disconnected'));\n\n if (!this.stateManager.isDisconnected()) {\n this.stateManager.transition(ConnectionState.DISCONNECTED);\n }\n }\n\n /**\n * Send message to JMRI (or mock)\n */\n send(message: JmriMessage): void {\n if (!this.stateManager.isConnected()) {\n // Queue message for later\n this.messageQueue.enqueue(message);\n return;\n }\n\n // Mock mode - send doesn't need to do anything\n // Responses are generated in request()\n if (this.mockManager) {\n this.emit('message:sent', message);\n return;\n }\n\n if (!this.ws) {\n throw new Error('WebSocket not initialized');\n }\n\n const json = JSON.stringify(message);\n this.ws.send(json);\n this.emit('message:sent', message);\n }\n\n /**\n * Send request and wait for response (or get mock response)\n */\n async request<T = any>(message: JmriMessage, timeout?: number): Promise<T> {\n // Mock mode - get response from mock manager\n if (this.mockManager) {\n const response = await this.mockManager.getMockResponse(message);\n this.emit('message:sent', message);\n if (response) {\n this.emit('message:received', response);\n }\n return response as T;\n }\n\n // Real mode - send request and wait for response\n // Assign message ID\n const id = this.messageIdGen.next();\n message.id = id;\n\n return new Promise((resolve, reject) => {\n // Set up timeout\n const timeoutMs = timeout || this.options.requestTimeout;\n const timeoutHandle = setTimeout(() => {\n this.pendingRequests.delete(id);\n reject(new Error(`Request timeout after ${timeoutMs}ms`));\n }, timeoutMs);\n\n // Track pending request with metadata for matching responses without IDs\n const pendingRequest: PendingRequest = {\n resolve,\n reject,\n timeout: timeoutHandle,\n messageType: message.type\n };\n\n // For throttle requests, store the throttle name for matching\n if (message.type === 'throttle' && message.data && 'name' in message.data) {\n pendingRequest.matchKey = (message.data as any).name;\n }\n\n this.pendingRequests.set(id, pendingRequest);\n\n // Send message\n try {\n this.send(message);\n } catch (error) {\n this.pendingRequests.delete(id);\n clearTimeout(timeoutHandle);\n reject(error);\n }\n });\n }\n\n /**\n * Get current connection state\n */\n getState(): ConnectionState {\n return this.stateManager.getState();\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.stateManager.isConnected();\n }\n\n /**\n * Handle WebSocket open event\n */\n private handleOpen(): void {\n this.stateManager.transition(ConnectionState.CONNECTED);\n this.emit('connected');\n\n // Start heartbeat\n if (this.options.heartbeat.enabled) {\n this.heartbeatManager.start(() => this.sendPing());\n }\n\n // Flush queued messages\n const queuedMessages = this.messageQueue.flush();\n for (const message of queuedMessages) {\n this.send(message);\n }\n }\n\n /**\n * Handle WebSocket message event\n */\n private handleMessage(data: string): void {\n try {\n const message: AnyJmriMessage = JSON.parse(data);\n this.emit('message:received', message);\n\n // Handle pong\n if (message.type === 'pong') {\n this.heartbeatManager.receivedPong();\n return;\n }\n\n // Handle hello\n if (message.type === 'hello') {\n this.emit('hello', message.data);\n return;\n }\n\n // Handle response to request\n if (message.id !== undefined) {\n const pending = this.pendingRequests.get(message.id);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pendingRequests.delete(message.id);\n pending.resolve(message);\n return;\n }\n }\n\n // Handle responses without ID (like throttle responses from JMRI)\n // Match by message type and data\n if (message.id === undefined) {\n for (const [id, pending] of this.pendingRequests.entries()) {\n // Match by type\n if (pending.messageType === message.type) {\n // For throttle messages, also match by throttle name\n if (message.type === 'throttle' && pending.matchKey) {\n const throttleName = (message.data as any)?.throttle || (message.data as any)?.name;\n if (throttleName === pending.matchKey) {\n clearTimeout(pending.timeout);\n this.pendingRequests.delete(id);\n pending.resolve(message);\n return;\n }\n } else {\n // For other message types, just match by type\n clearTimeout(pending.timeout);\n this.pendingRequests.delete(id);\n pending.resolve(message);\n return;\n }\n }\n }\n }\n\n // Handle unsolicited updates (auto-subscriptions)\n this.emit('update', message);\n } catch (error) {\n this.emit('error', new Error(`Failed to parse message: ${error}`));\n }\n }\n\n /**\n * Handle WebSocket close event\n */\n private handleClose(code: number, reason: string): void {\n this.heartbeatManager.stop();\n\n const wasConnected = this.stateManager.isConnected();\n const isReconnecting = this.reconnectionManager.reconnecting();\n\n if (this.stateManager.isConnected() || this.stateManager.isConnecting()) {\n this.stateManager.transition(ConnectionState.DISCONNECTED);\n }\n\n this.emit('disconnected', reason || `Connection closed (code: ${code})`);\n\n // Reject all pending requests\n this.rejectAllPendingRequests(new Error('Connection closed'));\n\n // Attempt reconnection if not manual disconnect\n // Continue reconnecting if we were connected OR reconnection manager is already active\n if (!this.isManualDisconnect && (wasConnected || isReconnecting) && this.options.reconnection.enabled) {\n this.stateManager.forceState(ConnectionState.RECONNECTING);\n this.reconnectionManager.start(() => this.connect());\n }\n }\n\n /**\n * Handle heartbeat timeout\n */\n private handleHeartbeatTimeout(): void {\n // Connection appears dead, force reconnect\n if (this.ws) {\n this.ws.close();\n }\n }\n\n /**\n * Send ping message\n */\n private sendPing(): void {\n this.send({ type: 'ping' });\n }\n\n /**\n * Send goodbye message\n */\n private async sendGoodbye(): Promise<void> {\n const message: GoodbyeMessage = { type: 'goodbye' };\n this.send(message);\n // Give it a moment to send\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n\n /**\n * Reject all pending requests\n */\n private rejectAllPendingRequests(error: Error): void {\n for (const pending of this.pendingRequests.values()) {\n clearTimeout(pending.timeout);\n pending.reject(error);\n }\n this.pendingRequests.clear();\n }\n\n /**\n * Delay helper\n */\n private delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}\n", "/**\n * Power control manager\n */\n\nimport { EventEmitter } from 'eventemitter3';\nimport { WebSocketClient } from '../core/websocket-client.js';\nimport { PowerState, PowerMessage } from '../types/jmri-messages.js';\n\n/**\n * Manages track power control\n */\nexport class PowerManager extends EventEmitter {\n private client: WebSocketClient;\n private currentState: PowerState = PowerState.UNKNOWN;\n\n constructor(client: WebSocketClient) {\n super();\n this.client = client;\n\n // Listen for power updates\n this.client.on('update', (message: any) => {\n if (message.type === 'power') {\n this.handlePowerUpdate(message);\n }\n });\n }\n\n /**\n * Get current track power state\n */\n async getPower(): Promise<PowerState> {\n const message: PowerMessage = {\n type: 'power'\n };\n\n const response = await this.client.request<PowerMessage>(message);\n\n if (response.data?.state !== undefined) {\n this.currentState = response.data.state;\n }\n\n return this.currentState;\n }\n\n /**\n * Set track power state\n */\n async setPower(state: PowerState): Promise<void> {\n const message: PowerMessage = {\n type: 'power',\n method: 'post',\n data: { state }\n };\n\n await this.client.request<PowerMessage>(message);\n\n const oldState = this.currentState;\n this.currentState = state;\n\n if (oldState !== this.currentState) {\n this.emit('power:changed', this.currentState);\n }\n }\n\n /**\n * Turn track power on\n */\n async powerOn(): Promise<void> {\n await this.setPower(PowerState.ON);\n }\n\n /**\n * Turn track power off\n */\n async powerOff(): Promise<void> {\n await this.setPower(PowerState.OFF);\n }\n\n /**\n * Get cached power state (no network request)\n */\n getCachedState(): PowerState {\n return this.currentState;\n }\n\n /**\n * Handle unsolicited power updates from JMRI\n */\n private handlePowerUpdate(message: PowerMessage): void {\n if (message.data?.state !== undefined) {\n const oldState = this.currentState;\n this.currentState = message.data.state;\n\n if (oldState !== this.currentState) {\n this.emit('power:changed', this.currentState);\n }\n }\n }\n}\n", "/**\n * Roster management\n */\n\nimport { WebSocketClient } from '../core/websocket-client.js';\nimport { RosterMessage, RosterEntry, RosterData } from '../types/jmri-messages.js';\n\n/**\n * Manages locomotive roster\n */\nexport class RosterManager {\n private client: WebSocketClient;\n private rosterCache: Map<string, RosterEntry> = new Map();\n\n constructor(client: WebSocketClient) {\n this.client = client;\n }\n\n /**\n * Get all roster entries\n */\n async getRoster(): Promise<RosterEntry[]> {\n const message: RosterMessage = {\n type: 'roster',\n method: 'list'\n };\n\n const response = await this.client.request<RosterMessage>(message);\n\n // Parse roster data\n if (response.data) {\n this.updateCache(response.data);\n }\n\n return Array.from(this.rosterCache.values());\n }\n\n /**\n * Get roster entry by name\n */\n async getRosterEntryByName(name: string): Promise<RosterEntry | undefined> {\n // Check cache first\n if (this.rosterCache.has(name)) {\n return this.rosterCache.get(name);\n }\n\n // Refresh roster\n await this.getRoster();\n return this.rosterCache.get(name);\n }\n\n /**\n * Get roster entry by address\n */\n async getRosterEntryByAddress(address: string | number): Promise<RosterEntry | undefined> {\n // Ensure roster is loaded\n if (this.rosterCache.size === 0) {\n await this.getRoster();\n }\n\n const addressStr = address.toString();\n\n for (const entry of this.rosterCache.values()) {\n if (entry.address === addressStr) {\n return entry;\n }\n }\n\n return undefined;\n }\n\n /**\n * Search roster by partial name match\n */\n async searchRoster(query: string): Promise<RosterEntry[]> {\n // Ensure roster is loaded\n if (this.rosterCache.size === 0) {\n await this.getRoster();\n }\n\n const lowerQuery = query.toLowerCase();\n const results: RosterEntry[] = [];\n\n for (const entry of this.rosterCache.values()) {\n if (\n entry.name.toLowerCase().includes(lowerQuery) ||\n entry.address.includes(query) ||\n entry.road?.toLowerCase().includes(lowerQuery) ||\n entry.number?.includes(query)\n ) {\n results.push(entry);\n }\n }\n\n return results;\n }\n\n /**\n * Get cached roster (no network request)\n */\n getCachedRoster(): RosterEntry[] {\n return Array.from(this.rosterCache.values());\n }\n\n /**\n * Clear roster cache\n */\n clearCache(): void {\n this.rosterCache.clear();\n }\n\n /**\n * Update internal cache from roster data\n */\n private updateCache(rosterData: RosterData): void {\n this.rosterCache.clear();\n\n for (const [name, entry] of Object.entries(rosterData)) {\n this.rosterCache.set(name, entry);\n }\n }\n}\n", "/**\n * Throttle-specific types\n */\n\n/**\n * Options for acquiring a throttle\n */\nexport interface ThrottleAcquireOptions {\n /**\n * DCC address of the locomotive\n */\n address: number;\n\n /**\n * Whether this is a long address (default: true for addresses > 127)\n */\n isLongAddress?: boolean;\n}\n\n/**\n * Throttle function key (F0-F28)\n */\nexport type ThrottleFunctionKey =\n | 'F0' | 'F1' | 'F2' | 'F3' | 'F4' | 'F5' | 'F6' | 'F7' | 'F8' | 'F9'\n | 'F10' | 'F11' | 'F12' | 'F13' | 'F14' | 'F15' | 'F16' | 'F17' | 'F18' | 'F19'\n | 'F20' | 'F21' | 'F22' | 'F23' | 'F24' | 'F25' | 'F26' | 'F27' | 'F28';\n\n/**\n * Throttle state tracking\n */\nexport interface ThrottleState {\n /**\n * Throttle ID assigned by JMRI\n */\n id: string;\n\n /**\n * DCC address\n */\n address: number;\n\n /**\n * Current speed (0.0 to 1.0)\n */\n speed: number;\n\n /**\n * Direction (true = forward, false = reverse)\n */\n forward: boolean;\n\n /**\n * Function states (F0-F28)\n */\n functions: Map<ThrottleFunctionKey, boolean>;\n\n /**\n * Whether throttle is currently acquired\n */\n acquired: boolean;\n}\n\n/**\n * Validates that a value is a valid throttle function key\n */\nexport function isThrottleFunctionKey(key: string): key is ThrottleFunctionKey {\n return /^F([0-9]|1[0-9]|2[0-8])$/.test(key);\n}\n\n/**\n * Validates that speed is in valid range (0.0 to 1.0)\n */\nexport function isValidSpeed(speed: number): boolean {\n return typeof speed === 'number' && speed >= 0 && speed <= 1;\n}\n", "/**\n * Throttle control manager\n */\n\nimport { EventEmitter } from 'eventemitter3';\nimport { WebSocketClient } from '../core/websocket-client.js';\nimport { ThrottleMessage, ThrottleData } from '../types/jmri-messages.js';\nimport {\n ThrottleAcquireOptions,\n ThrottleFunctionKey,\n ThrottleState,\n isThrottleFunctionKey,\n isValidSpeed\n} from '../types/throttle.js';\n\n/**\n * Manages multiple throttles\n */\nexport class ThrottleManager extends EventEmitter {\n private client: WebSocketClient;\n private throttles: Map<string, ThrottleState> = new Map();\n private clientId: string;\n\n constructor(client: WebSocketClient) {\n super();\n this.client = client;\n // Generate a unique client ID\n this.clientId = `jmri-client-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n\n // Listen for throttle updates\n this.client.on('update', (message: any) => {\n if (message.type === 'throttle') {\n this.handleThrottleUpdate(message);\n }\n });\n\n // Clean up throttles on disconnect\n this.client.on('disconnected', () => {\n this.handleDisconnect();\n });\n }\n\n /**\n * Acquire a throttle for a locomotive\n */\n async acquireThrottle(options: ThrottleAcquireOptions): Promise<string> {\n // Generate a unique throttle name using client ID and address\n const throttleName = `${this.clientId}-${options.address}`;\n\n const message: any = {\n type: 'throttle',\n data: {\n name: throttleName,\n address: options.address\n }\n };\n\n const response = await this.client.request<ThrottleMessage>(message);\n\n // JMRI returns the throttle ID in the \"throttle\" field, or we can use our name\n const throttleId = response.data?.throttle || throttleName;\n\n if (!throttleId) {\n throw new Error('Failed to acquire throttle: no throttle ID returned');\n }\n\n // Initialize throttle state\n const state: ThrottleState = {\n id: throttleId,\n address: options.address,\n speed: 0,\n forward: true,\n functions: new Map(),\n acquired: true\n };\n\n this.throttles.set(throttleId, state);\n this.emit('throttle:acquired', throttleId);\n\n return throttleId;\n }\n\n /**\n * Release a throttle\n */\n async releaseThrottle(throttleId: string): Promise<void> {\n const state = this.throttles.get(throttleId);\n if (!state) {\n throw new Error(`Throttle not found: ${throttleId}`);\n }\n\n const message: ThrottleMessage = {\n type: 'throttle',\n data: {\n throttle: throttleId,\n release: null\n }\n };\n\n await this.client.request<ThrottleMessage>(message);\n\n this.throttles.delete(throttleId);\n this.emit('throttle:released', throttleId);\n }\n\n /**\n * Set throttle speed (0.0 to 1.0)\n */\n async setSpeed(throttleId: string, speed: number): Promise<void> {\n const state = this.throttles.get(throttleId);\n if (!state) {\n throw new Error(`Throttle not found: ${throttleId}`);\n }\n\n if (!isValidSpeed(speed)) {\n throw new Error(`Invalid speed: ${speed}. Must be between 0.0 and 1.0`);\n }\n\n const message: ThrottleMessage = {\n type: 'throttle',\n data: {\n throttle: throttleId,\n speed\n }\n };\n\n // JMRI doesn't send responses for throttle control commands, just send\n this.client.send(message);\n\n state.speed = speed;\n this.emit('throttle:updated', throttleId, { speed });\n }\n\n /**\n * Set throttle direction\n */\n async setDirection(throttleId: string, forward: boolean): Promise<void> {\n const state = this.throttles.get(throttleId);\n if (!state) {\n throw new Error(`Throttle not found: ${throttleId}`);\n }\n\n const message: ThrottleMessage = {\n type: 'throttle',\n data: {\n throttle: throttleId,\n forward\n }\n };\n\n // JMRI doesn't send responses for throttle control commands, just send\n this.client.send(message);\n\n state.forward = forward;\n this.emit('throttle:updated', throttleId, { forward });\n }\n\n /**\n * Set throttle function (F0-F28)\n */\n async setFunction(throttleId: string, functionKey: ThrottleFunctionKey, value: boolean): Promise<void> {\n const state = this.throttles.get(throttleId);\n if (!state) {\n throw new Error(`Throttle not found: ${throttleId}`);\n }\n\n if (!isThrottleFunctionKey(functionKey)) {\n throw new Error(`Invalid function key: ${functionKey}`);\n }\n\n const data: ThrottleData = {\n throttle: throttleId,\n [functionKey]: value\n };\n\n const message: ThrottleMessage = {\n type: 'throttle',\n data\n };\n\n // JMRI doesn't send responses for throttle control commands, just send\n this.client.send(message);\n\n state.functions.set(functionKey, value);\n this.emit('throttle:updated', throttleId, { [functionKey]: value });\n }\n\n /**\n * Emergency stop for a throttle (speed to 0)\n */\n async emergencyStop(throttleId: string): Promise<void> {\n await this.setSpeed(throttleId, 0);\n }\n\n /**\n * Set throttle to idle (speed to 0, maintain direction)\n */\n async idle(throttleId: string): Promise<void> {\n await this.setSpeed(throttleId, 0);\n }\n\n /**\n * Get throttle state\n */\n getThrottleState(throttleId: string): ThrottleState | undefined {\n return this.throttles.get(throttleId);\n }\n\n /**\n * Get all throttle IDs\n */\n getThrottleIds(): string[] {\n return Array.from(this.throttles.keys());\n }\n\n /**\n * Get all throttle states\n */\n getAllThrottles(): ThrottleState[] {\n return Array.from(this.throttles.values());\n }\n\n /**\n * Release all throttles\n */\n async releaseAllThrottles(): Promise<void> {\n const throttleIds = this.getThrottleIds();\n\n for (const throttleId of throttleIds) {\n try {\n await this.releaseThrottle(throttleId);\n } catch (error) {\n // Continue releasing others even if one fails\n this.emit('error', error);\n }\n }\n }\n\n /**\n * Handle unsolicited throttle updates from JMRI\n */\n private handleThrottleUpdate(message: ThrottleMessage): void {\n const throttleId = message.data?.throttle;\n if (!throttleId) {\n return;\n }\n\n const state = this.throttles.get(throttleId);\n if (!state) {\n // Unknown throttle, possibly lost\n this.emit('throttle:lost', throttleId);\n return;\n }\n\n // Update state from message\n if (message.data.speed !== undefined) {\n state.speed = message.data.speed;\n }\n\n if (message.data.forward !== undefined) {\n state.forward = message.data.forward;\n }\n\n // Update functions\n for (let i = 0; i <= 28; i++) {\n const key = `F${i}` as ThrottleFunctionKey;\n if (message.data[key] !== undefined) {\n state.functions.set(key, message.data[key]!);\n }\n }\n\n this.emit('throttle:updated', throttleId, message.data);\n }\n\n /**\n * Handle disconnect - mark all throttles as not acquired\n */\n private handleDisconnect(): void {\n for (const state of this.throttles.values()) {\n state.acquired = false;\n }\n }\n}\n", "/**\n * Client configuration options\n */\n\n/**\n * Reconnection strategy options\n */\nexport interface ReconnectionOptions {\n /**\n * Enable automatic reconnection (default: true)\n */\n enabled: boolean;\n\n /**\n * Maximum number of reconnection attempts (0 = infinite, default: 0)\n */\n maxAttempts: number;\n\n /**\n * Initial delay in milliseconds (default: 1000)\n */\n initialDelay: number;\n\n /**\n * Maximum delay in milliseconds (default: 30000)\n */\n maxDelay: number;\n\n /**\n * Backoff multiplier (default: 1.5)\n */\n multiplier: number;\n\n /**\n * Add jitter to prevent thundering herd (default: true)\n * Jitter is \u00B125% of calculated delay\n */\n jitter: boolean;\n}\n\n/**\n * Heartbeat (ping/pong) options\n */\nexport interface HeartbeatOptions {\n /**\n * Enable heartbeat (default: true)\n */\n enabled: boolean;\n\n /**\n * Interval between pings in milliseconds (default: 30000)\n */\n interval: number;\n\n /**\n * Timeout waiting for pong in milliseconds (default: 5000)\n */\n timeout: number;\n}\n\n/**\n * Mock mode options\n */\nexport interface MockOptions {\n /**\n * Enable mock mode (default: false)\n * When enabled, all responses are generated from mock data instead of a real JMRI server\n */\n enabled: boolean;\n\n /**\n * Delay in milliseconds before returning mock responses (default: 50)\n * Simulates network latency. Set to 0 for instant responses.\n */\n responseDelay: number;\n}\n\n/**\n * JMRI client configuration options\n */\nexport interface JmriClientOptions {\n /**\n * JMRI server hostname or IP address (default: 'localhost')\n */\n host: string;\n\n /**\n * JMRI server WebSocket port (default: 12080)\n */\n port: number;\n\n /**\n * WebSocket protocol (default: 'ws', use 'wss' for secure)\n */\n protocol: 'ws' | 'wss';\n\n /**\n * Automatically connect on instantiation (default: true)\n */\n autoConnect: boolean;\n\n /**\n * Reconnection strategy\n */\n reconnection: ReconnectionOptions;\n\n /**\n * Heartbeat/ping configuration\n */\n heartbeat: HeartbeatOptions;\n\n /**\n * Maximum number of messages to queue when disconnected (default: 100)\n */\n messageQueueSize: number;\n\n /**\n * Default timeout for request/response in milliseconds (default: 10000)\n */\n requestTimeout: number;\n\n /**\n * Mock mode configuration (default: disabled)\n * Use mock responses instead of a real JMRI server\n */\n mock: MockOptions;\n}\n\n/**\n * Default client options\n */\nexport const DEFAULT_CLIENT_OPTIONS: JmriClientOptions = {\n host: 'localhost',\n port: 12080,\n protocol: 'ws',\n autoConnect: true,\n reconnection: {\n enabled: true,\n maxAttempts: 0, // infinite\n initialDelay: 1000,\n maxDelay: 30000,\n multiplier: 1.5,\n jitter: true\n },\n heartbeat: {\n enabled: true,\n interval: 30000,\n timeout: 5000\n },\n messageQueueSize: 100,\n requestTimeout: 10000,\n mock: {\n enabled: false,\n responseDelay: 50\n }\n};\n\n/**\n * Partial client options for user input (all fields optional)\n */\nexport type PartialClientOptions = Partial<{\n host: string;\n port: number;\n protocol: 'ws' | 'wss';\n autoConnect: boolean;\n reconnection: Partial<ReconnectionOptions>;\n heartbeat: Partial<HeartbeatOptions>;\n messageQueueSize: number;\n requestTimeout: number;\n mock: Partial<MockOptions>;\n}>;\n\n/**\n * Merge user options with defaults\n */\nexport function mergeOptions(userOptions?: PartialClientOptions): JmriClientOptions {\n const options = { ...DEFAULT_CLIENT_OPTIONS };\n\n if (!userOptions) {\n return options;\n }\n\n if (userOptions.host !== undefined) options.host = userOptions.host;\n if (userOptions.port !== undefined) options.port = userOptions.port;\n if (userOptions.protocol !== undefined) options.protocol = userOptions.protocol;\n if (userOptions.autoConnect !== undefined) options.autoConnect = userOptions.autoConnect;\n if (userOptions.messageQueueSize !== undefined) options.messageQueueSize = userOptions.messageQueueSize;\n if (userOptions.requestTimeout !== undefined) options.requestTimeout = userOptions.requestTimeout;\n\n if (userOptions.reconnection) {\n options.reconnection = { ...DEFAULT_CLIENT_OPTIONS.reconnection, ...userOptions.reconnection };\n }\n\n if (userOptions.heartbeat) {\n options.heartbeat = { ...DEFAULT_CLIENT_OPTIONS.heartbeat, ...userOptions.heartbeat };\n }\n\n if (userOptions.mock) {\n options.mock = { ...DEFAULT_CLIENT_OPTIONS.mock, ...userOptions.mock };\n }\n\n return options;\n}\n", "/**\n * Main JMRI client class\n */\n\nimport { EventEmitter } from 'eventemitter3';\nimport { WebSocketClient } from './core/websocket-client.js';\nimport { PowerManager } from './managers/power-manager.js';\nimport { RosterManager } from './managers/roster-manager.js';\nimport { ThrottleManager } from './managers/throttle-manager.js';\nimport { JmriClientOptions, PartialClientOptions, mergeOptions } from './types/client-options.js';\nimport { PowerState, RosterEntry } from './types/jmri-messages.js';\nimport { ConnectionState } from './types/events.js';\nimport { ThrottleAcquireOptions, ThrottleFunctionKey, ThrottleState } from './types/throttle.js';\n\n/**\n * JMRI WebSocket Client\n * Provides event-driven interface to JMRI with throttle control\n */\nexport class JmriClient extends EventEmitter {\n private options: JmriClientOptions;\n private wsClient: WebSocketClient;\n private powerManager: PowerManager;\n private rosterManager: RosterManager;\n private throttleManager: ThrottleManager;\n\n /**\n * Create a new JMRI client\n *\n * @param options - Client configuration options\n *\n * @example\n * ```typescript\n * const client = new JmriClient({\n * host: 'jmri.local',\n * port: 12080\n * });\n *\n * client.on('connected', () => console.log('Connected!'));\n * client.on('power:changed', (state) => console.log('Power:', state));\n * ```\n */\n constructor(options?: PartialClientOptions) {\n super();\n\n // Merge options with defaults\n this.options = mergeOptions(options);\n\n // Create WebSocket client\n this.wsClient = new WebSocketClient(this.options);\n\n // Create managers\n this.powerManager = new PowerManager(this.wsClient);\n this.rosterManager = new RosterManager(this.wsClient);\n this.throttleManager = new ThrottleManager(this.wsClient);\n\n // Forward events from WebSocket client\n this.wsClient.on('connected', () => this.emit('connected'));\n this.wsClient.on('disconnected', (reason: string) => this.emit('disconnected', reason));\n this.wsClient.on('reconnecting', (attempt: number, delay: number) =>\n this.emit('reconnecting', attempt, delay)\n );\n this.wsClient.on('reconnected', () => this.emit('reconnected'));\n this.wsClient.on('reconnectionFailed', (attempts: number) =>\n this.emit('reconnectionFailed', attempts)\n );\n this.wsClient.on('connectionStateChanged', (state: ConnectionState) =>\n this.emit('connectionStateChanged', state)\n );\n this.wsClient.on('error', (error: Error) => this.emit('error', error));\n this.wsClient.on('heartbeat:sent', () => this.emit('heartbeat:sent'));\n this.wsClient.on('heartbeat:timeout', () => this.emit('heartbeat:timeout'));\n\n // Forward events from managers\n this.powerManager.on('power:changed', (state: PowerState) =>\n this.emit('power:changed', state)\n );\n this.throttleManager.on('throttle:acquired', (id: string) =>\n this.emit('throttle:acquired', id)\n );\n this.throttleManager.on('throttle:updated', (id: string, data: any) =>\n this.emit('throttle:updated', id, data)\n );\n this.throttleManager.on('throttle:released', (id: string) =>\n this.emit('throttle:released', id)\n );\n this.throttleManager.on('throttle:lost', (id: string) =>\n this.emit('throttle:lost', id)\n );\n\n // Auto-connect if enabled\n if (this.options.autoConnect) {\n this.connect().catch((error) => {\n this.emit('error', error);\n });\n }\n }\n\n /**\n * Connect to JMRI server\n */\n async connect(): Promise<void> {\n return this.wsClient.connect();\n }\n\n /**\n * Disconnect from JMRI server\n * Releases all throttles and closes connection\n */\n async disconnect(): Promise<void> {\n // Release all throttles first\n await this.throttleManager.releaseAllThrottles();\n\n // Disconnect WebSocket\n return this.wsClient.disconnect();\n }\n\n /**\n * Get current connection state\n */\n getConnectionState(): ConnectionState {\n return this.wsClient.getState();\n }\n\n /**\n * Check if connected to JMRI\n */\n isConnected(): boolean {\n return this.wsClient.isConnected();\n }\n\n // ============================================================================\n // Power Control\n // ============================================================================\n\n /**\n * Get current track power state\n */\n async getPower(): Promise<PowerState> {\n return this.powerManager.getPower();\n }\n\n /**\n * Set track power state\n */\n async setPower(state: PowerState): Promise<void> {\n return this.powerManager.setPower(state);\n }\n\n /**\n * Turn track power on\n */\n async powerOn(): Promise<void> {\n return this.powerManager.powerOn();\n }\n\n /**\n * Turn track power off\n */\n async powerOff(): Promise<void> {\n return this.powerManager.powerOff();\n }\n\n // ============================================================================\n // Roster Management\n // ============================================================================\n\n /**\n * Get all roster entries\n */\n async getRoster(): Promise<RosterEntry[]> {\n return this.rosterManager.getRoster();\n }\n\n /**\n * Get roster entry by name\n */\n async getRosterEntryByName(name: string): Promise<RosterEntry | undefined> {\n return this.rosterManager.getRosterEntryByName(name);\n }\n\n /**\n * Get roster entry by address\n */\n async getRosterEntryByAddress(address: string | number): Promise<RosterEntry | undefined> {\n return this.rosterManager.getRosterEntryByAddress(address);\n }\n\n /**\n * Search roster by partial name match\n */\n async searchRoster(query: string): Promise<RosterEntry[]> {\n return this.rosterManager.searchRoster(query);\n }\n\n // ============================================================================\n // Throttle Control\n // ============================================================================\n\n /**\n * Acquire a throttle for a locomotive\n *\n * @param options - Throttle acquisition options\n * @returns Throttle ID for use in other throttle methods\n *\n * @example\n * ```typescript\n * const throttleId = await client.acquireThrottle({ address: 3 });\n * await client.setThrottleSpeed(throttleId, 0.5); // Half speed\n * ```\n */\n async acquireThrottle(options: ThrottleAcquireOptions): Promise<string> {\n return this.throttleManager.acquireThrottle(options);\n }\n\n /**\n * Release a throttle\n */\n async releaseThrottle(throttleId: string): Promise<void> {\n return this.throttleManager.releaseThrottle(throttleId);\n }\n\n /**\n * Set throttle speed (0.0 to 1.0)\n *\n * @param throttleId - Throttle ID from acquireThrottle\n * @param speed - Speed value between 0.0 (stopped) and 1.0 (full speed)\n */\n async setThrottleSpeed(throttleId: string, speed: number): Promise<void> {\n return this.throttleManager.setSpeed(throttleId, speed);\n }\n\n /**\n * Set throttle direction\n *\n * @param throttleId - Throttle ID from acquireThrottle\n * @param forward - True for forward, false for reverse\n */\n async setThrottleDirection(throttleId: string, forward: boolean): Promise<void> {\n return this.throttleManager.setDirection(throttleId, forward);\n }\n\n /**\n * Set throttle function (F0-F28)\n *\n * @param throttleId - Throttle ID from acquireThrottle\n * @param functionKey - Function key (F0-F28)\n * @param value - True to activate, false to deactivate\n *\n * @example\n * ```typescript\n * await client.setThrottleFunction(throttleId, 'F0', true); // Headlight on\n * await client.setThrottleFunction(throttleId, 'F2', true); // Horn\n * ```\n */\n async setThrottleFunction(\n throttleId: string,\n functionKey: ThrottleFunctionKey,\n value: boolean\n ): Promise<void> {\n return this.throttleManager.setFunction(throttleId, functionKey, value);\n }\n\n /**\n * Emergency stop for a throttle (speed to 0)\n */\n async emergencyStop(throttleId: string): Promise<void> {\n return this.throttleManager.emergencyStop(throttleId);\n }\n\n /**\n * Set throttle to idle (speed to 0, maintain direction)\n */\n async idleThrottle(throttleId: string): Promise<void> {\n return this.throttleManager.idle(throttleId);\n }\n\n /**\n * Get throttle state\n */\n getThrottleState(throttleId: string): ThrottleState | undefined {\n return this.throttleManager.getThrottleState(throttleId);\n }\n\n /**\n * Get all throttle IDs\n */\n getThrottleIds(): string[] {\n return this.throttleManager.getThrottleIds();\n }\n\n /**\n * Get all throttle states\n */\n getAllThrottles(): ThrottleState[] {\n return this.throttleManager.getAllThrottles();\n }\n\n /**\n * Release all throttles\n */\n async releaseAllThrottles(): Promise<void> {\n return this.throttleManager.releaseAllThrottles();\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["EventEmitter", "EventEmitter", "WebSocket", "ConnectionState", "EventEmitter", "EventEmitter", "EventEmitter", "PowerState", "EventEmitter", "EventEmitter", "EventEmitter", "EventEmitter"]
7
7
  }
package/dist/cjs/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * WebSocket client for JMRI with real-time updates and throttle control
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.mockData = exports.mockResponseManager = exports.MockResponseManager = exports.isValidSpeed = exports.isThrottleFunctionKey = exports.ConnectionState = exports.PowerState = exports.JmriClient = void 0;
7
+ exports.mockData = exports.mockResponseManager = exports.MockResponseManager = exports.powerStateToString = exports.isValidSpeed = exports.isThrottleFunctionKey = exports.ConnectionState = exports.PowerState = exports.JmriClient = void 0;
8
8
  var client_js_1 = require("./client.js");
9
9
  Object.defineProperty(exports, "JmriClient", { enumerable: true, get: function () { return client_js_1.JmriClient; } });
10
10
  // Export types
@@ -13,10 +13,12 @@ var index_js_1 = require("./types/index.js");
13
13
  Object.defineProperty(exports, "PowerState", { enumerable: true, get: function () { return index_js_1.PowerState; } });
14
14
  // Event types
15
15
  Object.defineProperty(exports, "ConnectionState", { enumerable: true, get: function () { return index_js_1.ConnectionState; } });
16
- // Export utility functions if needed
16
+ // Export utility functions
17
17
  var throttle_js_1 = require("./types/throttle.js");
18
18
  Object.defineProperty(exports, "isThrottleFunctionKey", { enumerable: true, get: function () { return throttle_js_1.isThrottleFunctionKey; } });
19
19
  Object.defineProperty(exports, "isValidSpeed", { enumerable: true, get: function () { return throttle_js_1.isValidSpeed; } });
20
+ var jmri_messages_js_1 = require("./types/jmri-messages.js");
21
+ Object.defineProperty(exports, "powerStateToString", { enumerable: true, get: function () { return jmri_messages_js_1.powerStateToString; } });
20
22
  // Export mock system for testing and demo purposes
21
23
  var index_js_2 = require("./mocks/index.js");
22
24
  Object.defineProperty(exports, "MockResponseManager", { enumerable: true, get: function () { return index_js_2.MockResponseManager; } });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,yCAAyC;AAAhC,uGAAA,UAAU,OAAA;AAEnB,eAAe;AACf,6CAwB0B;AAhBxB,qBAAqB;AACrB,sGAAA,UAAU,OAAA;AAOV,cAAc;AACd,2GAAA,eAAe,OAAA;AASjB,qCAAqC;AACrC,mDAA0E;AAAjE,oHAAA,qBAAqB,OAAA;AAAE,2GAAA,YAAY,OAAA;AAE5C,mDAAmD;AACnD,6CAAsF;AAA7E,+GAAA,mBAAmB,OAAA;AAAE,+GAAA,mBAAmB,OAAA;AAAE,oGAAA,QAAQ,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,yCAAyC;AAAhC,uGAAA,UAAU,OAAA;AAEnB,eAAe;AACf,6CAwB0B;AAhBxB,qBAAqB;AACrB,sGAAA,UAAU,OAAA;AAOV,cAAc;AACd,2GAAA,eAAe,OAAA;AASjB,2BAA2B;AAC3B,mDAA0E;AAAjE,oHAAA,qBAAqB,OAAA;AAAE,2GAAA,YAAY,OAAA;AAC5C,6DAA8D;AAArD,sHAAA,kBAAkB,OAAA;AAE3B,mDAAmD;AACnD,6CAAsF;AAA7E,+GAAA,mBAAmB,OAAA;AAAE,+GAAA,mBAAmB,OAAA;AAAE,oGAAA,QAAQ,OAAA"}
@@ -5,14 +5,34 @@
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.PowerState = void 0;
8
+ exports.powerStateToString = powerStateToString;
8
9
  /**
9
- * Power state values
10
- * ON = 2, OFF = 4 (JMRI constants)
10
+ * Power state values (from JMRI JSON protocol constants)
11
+ * UNKNOWN = 0 (state cannot be determined)
12
+ * ON = 2 (power is on)
13
+ * OFF = 4 (power is off)
11
14
  */
12
15
  var PowerState;
13
16
  (function (PowerState) {
17
+ PowerState[PowerState["UNKNOWN"] = 0] = "UNKNOWN";
14
18
  PowerState[PowerState["ON"] = 2] = "ON";
15
19
  PowerState[PowerState["OFF"] = 4] = "OFF";
16
- PowerState[PowerState["UNKNOWN"] = 0] = "UNKNOWN";
17
20
  })(PowerState || (exports.PowerState = PowerState = {}));
21
+ /**
22
+ * Convert PowerState enum to human-readable string
23
+ * @param state - The power state
24
+ * @returns 'ON', 'OFF', or 'UNKNOWN'
25
+ */
26
+ function powerStateToString(state) {
27
+ switch (state) {
28
+ case PowerState.ON:
29
+ return 'ON';
30
+ case PowerState.OFF:
31
+ return 'OFF';
32
+ case PowerState.UNKNOWN:
33
+ return 'UNKNOWN';
34
+ default:
35
+ return 'UNKNOWN';
36
+ }
37
+ }
18
38
  //# sourceMappingURL=jmri-messages.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"jmri-messages.js","sourceRoot":"","sources":["../../../src/types/jmri-messages.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAYH;;;GAGG;AACH,IAAY,UAIX;AAJD,WAAY,UAAU;IACpB,uCAAM,CAAA;IACN,yCAAO,CAAA;IACP,iDAAW,CAAA;AACb,CAAC,EAJW,UAAU,0BAAV,UAAU,QAIrB"}
1
+ {"version":3,"file":"jmri-messages.js","sourceRoot":"","sources":["../../../src/types/jmri-messages.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AA6BH,gDAWC;AA5BD;;;;;GAKG;AACH,IAAY,UAIX;AAJD,WAAY,UAAU;IACpB,iDAAW,CAAA;IACX,uCAAM,CAAA;IACN,yCAAO,CAAA;AACT,CAAC,EAJW,UAAU,0BAAV,UAAU,QAIrB;AAED;;;;GAIG;AACH,SAAgB,kBAAkB,CAAC,KAAiB;IAClD,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,UAAU,CAAC,EAAE;YAChB,OAAO,IAAI,CAAC;QACd,KAAK,UAAU,CAAC,GAAG;YACjB,OAAO,KAAK,CAAC;QACf,KAAK,UAAU,CAAC,OAAO;YACrB,OAAO,SAAS,CAAC;QACnB;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC"}
package/dist/esm/index.js CHANGED
@@ -9,8 +9,9 @@ export {
9
9
  PowerState,
10
10
  // Event types
11
11
  ConnectionState } from './types/index.js';
12
- // Export utility functions if needed
12
+ // Export utility functions
13
13
  export { isThrottleFunctionKey, isValidSpeed } from './types/throttle.js';
14
+ export { powerStateToString } from './types/jmri-messages.js';
14
15
  // Export mock system for testing and demo purposes
15
16
  export { MockResponseManager, mockResponseManager, mockData } from './mocks/index.js';
16
17
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,eAAe;AACf,OAAO;AAQL,qBAAqB;AACrB,UAAU;AAOV,cAAc;AACd,eAAe,EAOhB,MAAM,kBAAkB,CAAC;AAE1B,qCAAqC;AACrC,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAE1E,mDAAmD;AACnD,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,eAAe;AACf,OAAO;AAQL,qBAAqB;AACrB,UAAU;AAOV,cAAc;AACd,eAAe,EAOhB,MAAM,kBAAkB,CAAC;AAE1B,2BAA2B;AAC3B,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE9D,mDAAmD;AACnD,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC"}
@@ -3,13 +3,32 @@
3
3
  * Based on JMRI JSON protocol specification
4
4
  */
5
5
  /**
6
- * Power state values
7
- * ON = 2, OFF = 4 (JMRI constants)
6
+ * Power state values (from JMRI JSON protocol constants)
7
+ * UNKNOWN = 0 (state cannot be determined)
8
+ * ON = 2 (power is on)
9
+ * OFF = 4 (power is off)
8
10
  */
9
11
  export var PowerState;
10
12
  (function (PowerState) {
13
+ PowerState[PowerState["UNKNOWN"] = 0] = "UNKNOWN";
11
14
  PowerState[PowerState["ON"] = 2] = "ON";
12
15
  PowerState[PowerState["OFF"] = 4] = "OFF";
13
- PowerState[PowerState["UNKNOWN"] = 0] = "UNKNOWN";
14
16
  })(PowerState || (PowerState = {}));
17
+ /**
18
+ * Convert PowerState enum to human-readable string
19
+ * @param state - The power state
20
+ * @returns 'ON', 'OFF', or 'UNKNOWN'
21
+ */
22
+ export function powerStateToString(state) {
23
+ switch (state) {
24
+ case PowerState.ON:
25
+ return 'ON';
26
+ case PowerState.OFF:
27
+ return 'OFF';
28
+ case PowerState.UNKNOWN:
29
+ return 'UNKNOWN';
30
+ default:
31
+ return 'UNKNOWN';
32
+ }
33
+ }
15
34
  //# sourceMappingURL=jmri-messages.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"jmri-messages.js","sourceRoot":"","sources":["../../../src/types/jmri-messages.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH;;;GAGG;AACH,MAAM,CAAN,IAAY,UAIX;AAJD,WAAY,UAAU;IACpB,uCAAM,CAAA;IACN,yCAAO,CAAA;IACP,iDAAW,CAAA;AACb,CAAC,EAJW,UAAU,KAAV,UAAU,QAIrB"}
1
+ {"version":3,"file":"jmri-messages.js","sourceRoot":"","sources":["../../../src/types/jmri-messages.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH;;;;;GAKG;AACH,MAAM,CAAN,IAAY,UAIX;AAJD,WAAY,UAAU;IACpB,iDAAW,CAAA;IACX,uCAAM,CAAA;IACN,yCAAO,CAAA;AACT,CAAC,EAJW,UAAU,KAAV,UAAU,QAIrB;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAiB;IAClD,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,UAAU,CAAC,EAAE;YAChB,OAAO,IAAI,CAAC;QACd,KAAK,UAAU,CAAC,GAAG;YACjB,OAAO,KAAK,CAAC;QACf,KAAK,UAAU,CAAC,OAAO;YACrB,OAAO,SAAS,CAAC;QACnB;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC"}
@@ -5,5 +5,6 @@
5
5
  export { JmriClient } from './client.js';
6
6
  export { JmriClientOptions, PartialClientOptions, ReconnectionOptions, HeartbeatOptions, MockOptions, PowerState, RosterEntry, JmriMessage, PowerMessage, ThrottleMessage, RosterMessage, ConnectionState, EventPayloads, ThrottleAcquireOptions, ThrottleFunctionKey, ThrottleState } from './types/index.js';
7
7
  export { isThrottleFunctionKey, isValidSpeed } from './types/throttle.js';
8
+ export { powerStateToString } from './types/jmri-messages.js';
8
9
  export { MockResponseManager, mockResponseManager, mockData } from './mocks/index.js';
9
10
  export type { MockResponseManagerOptions } from './mocks/index.js';
@@ -12,14 +12,22 @@ export interface JmriMessage {
12
12
  id?: number;
13
13
  }
14
14
  /**
15
- * Power state values
16
- * ON = 2, OFF = 4 (JMRI constants)
15
+ * Power state values (from JMRI JSON protocol constants)
16
+ * UNKNOWN = 0 (state cannot be determined)
17
+ * ON = 2 (power is on)
18
+ * OFF = 4 (power is off)
17
19
  */
18
20
  export declare enum PowerState {
21
+ UNKNOWN = 0,
19
22
  ON = 2,
20
- OFF = 4,
21
- UNKNOWN = 0
23
+ OFF = 4
22
24
  }
25
+ /**
26
+ * Convert PowerState enum to human-readable string
27
+ * @param state - The power state
28
+ * @returns 'ON', 'OFF', or 'UNKNOWN'
29
+ */
30
+ export declare function powerStateToString(state: PowerState): string;
23
31
  /**
24
32
  * Power message data
25
33
  */
package/docs/API.md CHANGED
@@ -58,12 +58,36 @@ client.on('heartbeat:timeout', () => { });
58
58
  ```typescript
59
59
  // Get current power state
60
60
  const state: PowerState = await client.getPower();
61
- // PowerState.ON = 2, PowerState.OFF = 4
61
+
62
+ // PowerState enum values (from JMRI JSON protocol):
63
+ // PowerState.UNKNOWN = 0 (state cannot be determined)
64
+ // PowerState.ON = 2 (power is on)
65
+ // PowerState.OFF = 4 (power is off)
66
+
67
+ // Handle power state
68
+ switch (state) {
69
+ case PowerState.ON:
70
+ console.log('Power is ON');
71
+ break;
72
+ case PowerState.OFF:
73
+ console.log('Power is OFF');
74
+ break;
75
+ case PowerState.UNKNOWN:
76
+ console.log('Power state is UNKNOWN');
77
+ break;
78
+ }
62
79
 
63
80
  // Set power
64
81
  await client.setPower(PowerState.ON);
65
82
  await client.powerOn(); // Convenience method
66
83
  await client.powerOff(); // Convenience method
84
+
85
+ // Listen for power changes (including UNKNOWN states)
86
+ client.on('power:changed', (state: PowerState) => {
87
+ if (state === PowerState.UNKNOWN) {
88
+ console.log('Power state became unknown (connection issue?)');
89
+ }
90
+ });
67
91
  ```
68
92
 
69
93
  ## Roster Management
@@ -138,6 +162,24 @@ const state = client.getConnectionState();
138
162
  // ConnectionState.CONNECTED, DISCONNECTED, CONNECTING, or RECONNECTING
139
163
  ```
140
164
 
165
+ ## Utility Functions
166
+
167
+ ```typescript
168
+ import { powerStateToString, isThrottleFunctionKey, isValidSpeed } from 'jmri-client';
169
+
170
+ // Convert PowerState enum to readable string
171
+ const stateStr = powerStateToString(PowerState.ON); // 'ON'
172
+ const stateStr2 = powerStateToString(PowerState.UNKNOWN); // 'UNKNOWN'
173
+
174
+ // Validate throttle function key
175
+ isThrottleFunctionKey('F0'); // true
176
+ isThrottleFunctionKey('F99'); // false
177
+
178
+ // Validate speed value (0.0 to 1.0)
179
+ isValidSpeed(0.5); // true
180
+ isValidSpeed(1.5); // false
181
+ ```
182
+
141
183
  ## TypeScript Types
142
184
 
143
185
  All types are exported from the main package:
package/docs/BROWSER.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Browser Usage Guide
2
2
 
3
- jmri-client v3.1.0+ supports both Node.js and browser environments. This guide shows how to use jmri-client in web applications.
3
+ jmri-client v3.2.0+ supports both Node.js and browser environments. This guide shows how to use jmri-client in web applications.
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,6 +8,21 @@ jmri-client v3.1.0+ supports both Node.js and browser environments. This guide s
8
8
  npm install jmri-client
9
9
  ```
10
10
 
11
+ ## Browser Bundle vs ESM Build
12
+
13
+ jmri-client provides two builds for different use cases:
14
+
15
+ - **Browser Bundle** (`dist/browser/jmri-client.js`) - ✅ **Recommended for browsers**
16
+ - All dependencies bundled (including eventemitter3)
17
+ - Ready to use in browsers without additional configuration
18
+ - Works with direct imports, CDN usage, and module bundlers
19
+
20
+ - **ESM Build** (`dist/esm/index.js`) - For Node.js with ESM
21
+ - Requires module resolution for dependencies
22
+ - Used automatically in Node.js environments
23
+
24
+ **Important:** When using jmri-client in browsers, always use the **browser bundle** to ensure proper functionality, especially for reconnection features.
25
+
11
26
  ## Browser Compatibility
12
27
 
13
28
  jmri-client automatically detects the environment and uses:
@@ -20,7 +35,7 @@ No configuration or polyfills required!
20
35
 
21
36
  ### Using a Module Bundler (Recommended)
22
37
 
23
- With Webpack, Vite, Rollup, or similar bundlers:
38
+ With Webpack, Vite, Rollup, or similar bundlers, the browser bundle is automatically used via the `browser` field in package.json:
24
39
 
25
40
  ```javascript
26
41
  import { JmriClient } from 'jmri-client';
@@ -51,9 +66,37 @@ await client.setThrottleSpeed(throttleId, 0.5); // Half speed
51
66
  await client.setThrottleFunction(throttleId, 'F0', true); // Headlight on
52
67
  ```
53
68
 
69
+ **Note:** Most modern bundlers (Vite, Webpack 5+, etc.) automatically use the browser bundle via the `browser` field in package.json. If your bundler doesn't support this, you may need to add an alias:
70
+
71
+ **Vite:**
72
+ ```typescript
73
+ // vite.config.ts
74
+ import { fileURLToPath, URL } from 'node:url'
75
+
76
+ export default defineConfig({
77
+ resolve: {
78
+ alias: {
79
+ 'jmri-client': fileURLToPath(new URL('./node_modules/jmri-client/dist/browser/jmri-client.js', import.meta.url))
80
+ }
81
+ }
82
+ })
83
+ ```
84
+
85
+ **Webpack:**
86
+ ```javascript
87
+ // webpack.config.js
88
+ module.exports = {
89
+ resolve: {
90
+ alias: {
91
+ 'jmri-client': path.resolve(__dirname, 'node_modules/jmri-client/dist/browser/jmri-client.js')
92
+ }
93
+ }
94
+ }
95
+ ```
96
+
54
97
  ### Using a CDN (ES Modules)
55
98
 
56
- For quick prototypes without a build step:
99
+ For quick prototypes without a build step, use the browser bundle:
57
100
 
58
101
  ```html
59
102
  <!DOCTYPE html>
@@ -68,7 +111,8 @@ For quick prototypes without a build step:
68
111
  <button id="speed">Set Speed 50%</button>
69
112
 
70
113
  <script type="module">
71
- import { JmriClient } from 'https://cdn.jsdelivr.net/npm/jmri-client@3.1.0/dist/esm/index.js';
114
+ // Use the browser bundle from CDN
115
+ import { JmriClient } from 'https://unpkg.com/jmri-client@3.3.0/dist/browser/jmri-client.js';
72
116
 
73
117
  const client = new JmriClient({
74
118
  host: 'localhost',
@@ -99,6 +143,10 @@ For quick prototypes without a build step:
99
143
  </html>
100
144
  ```
101
145
 
146
+ Alternative CDNs:
147
+ - **unpkg**: `https://unpkg.com/jmri-client@3.3.0/dist/browser/jmri-client.js`
148
+ - **jsDelivr**: `https://cdn.jsdelivr.net/npm/jmri-client@3.3.0/dist/browser/jmri-client.js`
149
+
102
150
  ## React Example
103
151
 
104
152
  ```jsx
package/docs/EXAMPLES.md CHANGED
@@ -9,7 +9,11 @@ const client = new JmriClient({ host: 'jmri.local' });
9
9
 
10
10
  client.on('connected', async () => {
11
11
  const power = await client.getPower();
12
- console.log('Current power:', power === PowerState.ON ? 'ON' : 'OFF');
12
+
13
+ // Handle all three power states
14
+ const powerStr = power === PowerState.ON ? 'ON' :
15
+ power === PowerState.OFF ? 'OFF' : 'UNKNOWN';
16
+ console.log('Current power:', powerStr);
13
17
 
14
18
  await client.powerOn();
15
19
  console.log('Power turned ON');
@@ -69,9 +73,11 @@ client.on('reconnecting', (attempt, delay) => {
69
73
  });
70
74
  client.on('reconnected', () => console.log('✓ Reconnected!'));
71
75
 
72
- // Monitor power changes
76
+ // Monitor power changes (including UNKNOWN state)
73
77
  client.on('power:changed', (state) => {
74
- console.log('Power changed:', state === PowerState.ON ? 'ON' : 'OFF');
78
+ const stateStr = state === PowerState.ON ? 'ON' :
79
+ state === PowerState.OFF ? 'OFF' : 'UNKNOWN';
80
+ console.log('Power changed:', stateStr);
75
81
  });
76
82
 
77
83
  // Monitor throttle updates
@@ -255,6 +261,8 @@ const client = new JmriClient({ host: 'jmri.local' });
255
261
 
256
262
  client.on('connected', async () => {
257
263
  const power = await client.getPower();
258
- console.log('Power:', power === PowerState.ON ? 'ON' : 'OFF');
264
+ const powerStr = power === PowerState.ON ? 'ON' :
265
+ power === PowerState.OFF ? 'OFF' : 'UNKNOWN';
266
+ console.log('Power:', powerStr);
259
267
  });
260
268
  ```
package/docs/MIGRATION.md CHANGED
@@ -44,7 +44,7 @@ console.log(powerState); // Direct value (PowerState enum)
44
44
  **Changes:**
45
45
  - Methods return data directly instead of axios response objects
46
46
  - No more `.data` property on responses
47
- - Power state is now a `PowerState` enum (ON=2, OFF=4)
47
+ - Power state is now a `PowerState` enum (UNKNOWN=0, ON=2, OFF=4)
48
48
 
49
49
  ### 3. Power Control
50
50
 
@@ -221,7 +221,9 @@ client.on('connected', () => {
221
221
  });
222
222
 
223
223
  client.on('power:changed', (state) => {
224
- console.log('Power changed:', state === PowerState.ON ? 'ON' : 'OFF');
224
+ const stateStr = state === PowerState.ON ? 'ON' :
225
+ state === PowerState.OFF ? 'OFF' : 'UNKNOWN';
226
+ console.log('Power changed:', stateStr);
225
227
  });
226
228
  ```
227
229
 
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "jmri-client",
3
- "version": "3.2.0",
3
+ "version": "3.3.0",
4
4
  "description": "WebSocket client for JMRI with real-time updates and throttle control - works in both Node.js and browsers",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.js",
7
- "browser": "./dist/esm/index.js",
7
+ "browser": "./dist/browser/jmri-client.js",
8
8
  "types": "./dist/types/index.d.ts",
9
9
  "exports": {
10
10
  ".": {
11
- "browser": "./dist/esm/index.js",
11
+ "browser": "./dist/browser/jmri-client.js",
12
12
  "import": "./dist/esm/index.js",
13
13
  "require": "./dist/cjs/index.js",
14
14
  "types": "./dist/types/index.d.ts"