jmri-client 4.2.0-beta.2 → 5.1.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 +3 -1
- package/dist/browser/jmri-client.js +88 -28
- package/dist/cjs/index.js +2442 -31
- package/dist/esm/index.js +2393 -17
- package/dist/types/client.d.ts +9 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/managers/roster-manager.d.ts +9 -1
- package/dist/types/mocks/mock-data.d.ts +30 -6
- package/dist/types/mocks/mock-response-manager.d.ts +7 -2
- package/dist/types/types/jmri-messages.d.ts +22 -0
- package/docs/API.md +8 -0
- package/docs/BROWSER.md +4 -4
- package/docs/MIGRATION.md +30 -1
- package/docs/MOCK_MODE.md +15 -9
- package/package.json +17 -18
- package/dist/cjs/client.js +0 -366
- package/dist/cjs/core/connection-state-manager.js +0 -84
- package/dist/cjs/core/heartbeat-manager.js +0 -79
- package/dist/cjs/core/index.js +0 -25
- package/dist/cjs/core/message-queue.js +0 -59
- package/dist/cjs/core/reconnection-manager.js +0 -97
- package/dist/cjs/core/websocket-adapter.js +0 -135
- package/dist/cjs/core/websocket-client.js +0 -388
- package/dist/cjs/managers/index.js +0 -25
- package/dist/cjs/managers/light-manager.js +0 -111
- package/dist/cjs/managers/power-manager.js +0 -90
- package/dist/cjs/managers/roster-manager.js +0 -118
- package/dist/cjs/managers/system-connections-manager.js +0 -28
- package/dist/cjs/managers/throttle-manager.js +0 -233
- package/dist/cjs/managers/turnout-manager.js +0 -111
- package/dist/cjs/mocks/index.js +0 -12
- package/dist/cjs/mocks/mock-data.js +0 -237
- package/dist/cjs/mocks/mock-response-manager.js +0 -290
- package/dist/cjs/types/client-options.js +0 -66
- package/dist/cjs/types/events.js +0 -16
- package/dist/cjs/types/index.js +0 -23
- package/dist/cjs/types/jmri-messages.js +0 -95
- package/dist/cjs/types/throttle.js +0 -19
- package/dist/cjs/utils/exponential-backoff.js +0 -40
- package/dist/cjs/utils/index.js +0 -21
- package/dist/cjs/utils/message-id.js +0 -40
- package/dist/esm/client.js +0 -362
- package/dist/esm/core/connection-state-manager.js +0 -80
- package/dist/esm/core/heartbeat-manager.js +0 -75
- package/dist/esm/core/index.js +0 -9
- package/dist/esm/core/message-queue.js +0 -55
- package/dist/esm/core/reconnection-manager.js +0 -93
- package/dist/esm/core/websocket-adapter.js +0 -98
- package/dist/esm/core/websocket-client.js +0 -384
- package/dist/esm/managers/index.js +0 -9
- package/dist/esm/managers/light-manager.js +0 -107
- package/dist/esm/managers/power-manager.js +0 -86
- package/dist/esm/managers/roster-manager.js +0 -114
- package/dist/esm/managers/system-connections-manager.js +0 -24
- package/dist/esm/managers/throttle-manager.js +0 -229
- package/dist/esm/managers/turnout-manager.js +0 -107
- package/dist/esm/mocks/index.js +0 -6
- package/dist/esm/mocks/mock-data.js +0 -234
- package/dist/esm/mocks/mock-response-manager.js +0 -286
- package/dist/esm/types/client-options.js +0 -62
- package/dist/esm/types/events.js +0 -13
- package/dist/esm/types/index.js +0 -7
- package/dist/esm/types/jmri-messages.js +0 -89
- package/dist/esm/types/throttle.js +0 -15
- package/dist/esm/utils/exponential-backoff.js +0 -36
- package/dist/esm/utils/index.js +0 -5
- package/dist/esm/utils/message-id.js +0 -36
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Heartbeat (ping/pong) management
|
|
3
|
-
*/
|
|
4
|
-
import { EventEmitter } from 'eventemitter3';
|
|
5
|
-
/**
|
|
6
|
-
* Manages WebSocket heartbeat via ping/pong
|
|
7
|
-
*/
|
|
8
|
-
export class HeartbeatManager extends EventEmitter {
|
|
9
|
-
constructor(options) {
|
|
10
|
-
super();
|
|
11
|
-
this.isRunning = false;
|
|
12
|
-
this.options = options;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Start heartbeat monitoring
|
|
16
|
-
* @param sendPing - Callback to send ping message
|
|
17
|
-
*/
|
|
18
|
-
start(sendPing) {
|
|
19
|
-
if (!this.options.enabled || this.isRunning) {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
this.isRunning = true;
|
|
23
|
-
// Send ping at regular intervals
|
|
24
|
-
this.pingInterval = setInterval(() => {
|
|
25
|
-
sendPing();
|
|
26
|
-
this.emit('pingSent');
|
|
27
|
-
// Start pong timeout
|
|
28
|
-
this.pongTimeout = setTimeout(() => {
|
|
29
|
-
this.emit('timeout');
|
|
30
|
-
}, this.options.timeout);
|
|
31
|
-
}, this.options.interval);
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Stop heartbeat monitoring
|
|
35
|
-
*/
|
|
36
|
-
stop() {
|
|
37
|
-
this.isRunning = false;
|
|
38
|
-
if (this.pingInterval) {
|
|
39
|
-
clearInterval(this.pingInterval);
|
|
40
|
-
this.pingInterval = undefined;
|
|
41
|
-
}
|
|
42
|
-
if (this.pongTimeout) {
|
|
43
|
-
clearTimeout(this.pongTimeout);
|
|
44
|
-
this.pongTimeout = undefined;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Handle pong received from server
|
|
49
|
-
*/
|
|
50
|
-
receivedPong() {
|
|
51
|
-
// Clear pong timeout
|
|
52
|
-
if (this.pongTimeout) {
|
|
53
|
-
clearTimeout(this.pongTimeout);
|
|
54
|
-
this.pongTimeout = undefined;
|
|
55
|
-
}
|
|
56
|
-
this.emit('pongReceived');
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Check if heartbeat is running
|
|
60
|
-
*/
|
|
61
|
-
running() {
|
|
62
|
-
return this.isRunning;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Update heartbeat options
|
|
66
|
-
*/
|
|
67
|
-
updateOptions(options) {
|
|
68
|
-
const wasRunning = this.isRunning;
|
|
69
|
-
if (wasRunning) {
|
|
70
|
-
this.stop();
|
|
71
|
-
}
|
|
72
|
-
this.options = { ...this.options, ...options };
|
|
73
|
-
// Note: Caller must call start() again if needed
|
|
74
|
-
}
|
|
75
|
-
}
|
package/dist/esm/core/index.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Core infrastructure exports
|
|
3
|
-
*/
|
|
4
|
-
export * from './websocket-client.js';
|
|
5
|
-
export * from './websocket-adapter.js';
|
|
6
|
-
export * from './connection-state-manager.js';
|
|
7
|
-
export * from './reconnection-manager.js';
|
|
8
|
-
export * from './heartbeat-manager.js';
|
|
9
|
-
export * from './message-queue.js';
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Message queue for offline message handling
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Queue for storing messages when disconnected
|
|
6
|
-
* Messages are sent when connection is restored
|
|
7
|
-
*/
|
|
8
|
-
export class MessageQueue {
|
|
9
|
-
constructor(maxSize = 100) {
|
|
10
|
-
this.queue = [];
|
|
11
|
-
this.maxSize = maxSize;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Add message to queue
|
|
15
|
-
* If queue is full, oldest message is removed
|
|
16
|
-
*/
|
|
17
|
-
enqueue(message) {
|
|
18
|
-
if (this.queue.length >= this.maxSize) {
|
|
19
|
-
this.queue.shift(); // Remove oldest
|
|
20
|
-
}
|
|
21
|
-
this.queue.push(message);
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Get all queued messages and clear queue
|
|
25
|
-
*/
|
|
26
|
-
flush() {
|
|
27
|
-
const messages = [...this.queue];
|
|
28
|
-
this.queue = [];
|
|
29
|
-
return messages;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Clear all queued messages without returning them
|
|
33
|
-
*/
|
|
34
|
-
clear() {
|
|
35
|
-
this.queue = [];
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Get number of queued messages
|
|
39
|
-
*/
|
|
40
|
-
size() {
|
|
41
|
-
return this.queue.length;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Check if queue is empty
|
|
45
|
-
*/
|
|
46
|
-
isEmpty() {
|
|
47
|
-
return this.queue.length === 0;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Check if queue is full
|
|
51
|
-
*/
|
|
52
|
-
isFull() {
|
|
53
|
-
return this.queue.length >= this.maxSize;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Automatic reconnection management with exponential backoff
|
|
3
|
-
*/
|
|
4
|
-
import { EventEmitter } from 'eventemitter3';
|
|
5
|
-
import { calculateBackoffDelay, shouldReconnect } from '../utils/exponential-backoff.js';
|
|
6
|
-
/**
|
|
7
|
-
* Manages automatic reconnection with exponential backoff
|
|
8
|
-
*/
|
|
9
|
-
export class ReconnectionManager extends EventEmitter {
|
|
10
|
-
constructor(options) {
|
|
11
|
-
super();
|
|
12
|
-
this.currentAttempt = 0;
|
|
13
|
-
this.isReconnecting = false;
|
|
14
|
-
this.options = options;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Start reconnection process
|
|
18
|
-
* @param reconnect - Callback to attempt reconnection
|
|
19
|
-
*/
|
|
20
|
-
start(reconnect) {
|
|
21
|
-
if (!this.options.enabled || this.isReconnecting) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
this.isReconnecting = true;
|
|
25
|
-
this.currentAttempt = 0;
|
|
26
|
-
this.scheduleNextAttempt(reconnect);
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Schedule next reconnection attempt
|
|
30
|
-
*/
|
|
31
|
-
scheduleNextAttempt(reconnect) {
|
|
32
|
-
this.currentAttempt++;
|
|
33
|
-
// Check if should continue trying
|
|
34
|
-
if (!shouldReconnect(this.currentAttempt, this.options.maxAttempts)) {
|
|
35
|
-
this.emit('maxAttemptsReached', this.currentAttempt - 1);
|
|
36
|
-
this.stop();
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
// Calculate delay with backoff
|
|
40
|
-
const delay = calculateBackoffDelay(this.currentAttempt, this.options);
|
|
41
|
-
this.emit('attemptScheduled', this.currentAttempt, delay);
|
|
42
|
-
// Schedule attempt
|
|
43
|
-
this.reconnectTimeout = setTimeout(async () => {
|
|
44
|
-
this.emit('attempting', this.currentAttempt);
|
|
45
|
-
try {
|
|
46
|
-
await reconnect();
|
|
47
|
-
// Success - stop reconnection process
|
|
48
|
-
this.stop();
|
|
49
|
-
this.emit('success', this.currentAttempt);
|
|
50
|
-
}
|
|
51
|
-
catch (error) {
|
|
52
|
-
// Failure - schedule next attempt
|
|
53
|
-
this.emit('failed', this.currentAttempt, error);
|
|
54
|
-
this.scheduleNextAttempt(reconnect);
|
|
55
|
-
}
|
|
56
|
-
}, delay);
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Stop reconnection process
|
|
60
|
-
*/
|
|
61
|
-
stop() {
|
|
62
|
-
this.isReconnecting = false;
|
|
63
|
-
if (this.reconnectTimeout) {
|
|
64
|
-
clearTimeout(this.reconnectTimeout);
|
|
65
|
-
this.reconnectTimeout = undefined;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Reset attempt counter
|
|
70
|
-
*/
|
|
71
|
-
reset() {
|
|
72
|
-
this.stop();
|
|
73
|
-
this.currentAttempt = 0;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Check if currently reconnecting
|
|
77
|
-
*/
|
|
78
|
-
reconnecting() {
|
|
79
|
-
return this.isReconnecting;
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Get current attempt number
|
|
83
|
-
*/
|
|
84
|
-
getAttempt() {
|
|
85
|
-
return this.currentAttempt;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Update reconnection options
|
|
89
|
-
*/
|
|
90
|
-
updateOptions(options) {
|
|
91
|
-
this.options = { ...this.options, ...options };
|
|
92
|
-
}
|
|
93
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WebSocket Adapter
|
|
3
|
-
* Provides a unified interface for WebSocket connections in both Node.js and browser environments
|
|
4
|
-
*/
|
|
5
|
-
import { EventEmitter } from 'eventemitter3';
|
|
6
|
-
/**
|
|
7
|
-
* WebSocket ready states
|
|
8
|
-
*/
|
|
9
|
-
export var ReadyState;
|
|
10
|
-
(function (ReadyState) {
|
|
11
|
-
ReadyState[ReadyState["CONNECTING"] = 0] = "CONNECTING";
|
|
12
|
-
ReadyState[ReadyState["OPEN"] = 1] = "OPEN";
|
|
13
|
-
ReadyState[ReadyState["CLOSING"] = 2] = "CLOSING";
|
|
14
|
-
ReadyState[ReadyState["CLOSED"] = 3] = "CLOSED";
|
|
15
|
-
})(ReadyState || (ReadyState = {}));
|
|
16
|
-
/**
|
|
17
|
-
* Create a WebSocket adapter for the current environment
|
|
18
|
-
*/
|
|
19
|
-
export async function createWebSocketAdapter(url, protocols) {
|
|
20
|
-
// Detect environment
|
|
21
|
-
const isBrowser = typeof window !== 'undefined' && typeof window.WebSocket !== 'undefined';
|
|
22
|
-
if (isBrowser) {
|
|
23
|
-
return new BrowserWebSocketAdapter(url, protocols);
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
return await NodeWebSocketAdapter.create(url, protocols);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Browser WebSocket adapter
|
|
31
|
-
* Wraps native browser WebSocket with EventEmitter interface
|
|
32
|
-
*/
|
|
33
|
-
class BrowserWebSocketAdapter extends EventEmitter {
|
|
34
|
-
constructor(url, protocols) {
|
|
35
|
-
super();
|
|
36
|
-
this.ws = new WebSocket(url, protocols);
|
|
37
|
-
this.ws.onopen = () => {
|
|
38
|
-
this.emit('open');
|
|
39
|
-
};
|
|
40
|
-
this.ws.onmessage = (event) => {
|
|
41
|
-
this.emit('message', event.data);
|
|
42
|
-
};
|
|
43
|
-
this.ws.onerror = () => {
|
|
44
|
-
this.emit('error', new Error('WebSocket error'));
|
|
45
|
-
};
|
|
46
|
-
this.ws.onclose = (event) => {
|
|
47
|
-
this.emit('close', event.code, event.reason);
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
send(data) {
|
|
51
|
-
this.ws.send(data);
|
|
52
|
-
}
|
|
53
|
-
close(code, reason) {
|
|
54
|
-
this.ws.close(code, reason);
|
|
55
|
-
}
|
|
56
|
-
get readyState() {
|
|
57
|
-
return this.ws.readyState;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Node.js WebSocket adapter
|
|
62
|
-
* Wraps ws package with consistent interface
|
|
63
|
-
*/
|
|
64
|
-
class NodeWebSocketAdapter extends EventEmitter {
|
|
65
|
-
constructor(ws) {
|
|
66
|
-
super();
|
|
67
|
-
this.ws = ws;
|
|
68
|
-
this.ws.on('open', () => {
|
|
69
|
-
this.emit('open');
|
|
70
|
-
});
|
|
71
|
-
this.ws.on('message', (data) => {
|
|
72
|
-
// Convert Buffer to string if needed
|
|
73
|
-
const message = typeof data === 'string' ? data : data.toString();
|
|
74
|
-
this.emit('message', message);
|
|
75
|
-
});
|
|
76
|
-
this.ws.on('error', (error) => {
|
|
77
|
-
this.emit('error', error);
|
|
78
|
-
});
|
|
79
|
-
this.ws.on('close', (code, reason) => {
|
|
80
|
-
this.emit('close', code, reason);
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
static async create(url, protocols) {
|
|
84
|
-
// Use dynamic import for ESM compatibility
|
|
85
|
-
const { default: WebSocket } = await import('ws');
|
|
86
|
-
const ws = new WebSocket(url, protocols);
|
|
87
|
-
return new NodeWebSocketAdapter(ws);
|
|
88
|
-
}
|
|
89
|
-
send(data) {
|
|
90
|
-
this.ws.send(data);
|
|
91
|
-
}
|
|
92
|
-
close(code, reason) {
|
|
93
|
-
this.ws.close(code, reason);
|
|
94
|
-
}
|
|
95
|
-
get readyState() {
|
|
96
|
-
return this.ws.readyState;
|
|
97
|
-
}
|
|
98
|
-
}
|