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
package/README.md
CHANGED
|
@@ -28,7 +28,9 @@ WebSocket client for [JMRI](http://jmri.sourceforge.net/) with real-time updates
|
|
|
28
28
|
npm install jmri-client
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
**Requirements:** Node.js
|
|
31
|
+
**Requirements:** Node.js 22+ · JMRI 5.0 or later
|
|
32
|
+
|
|
33
|
+
> `getSystemConnections()` and per-connection power/throttle prefix support require JMRI 5.15.7+. All other features work with any JMRI 5.x release.
|
|
32
34
|
|
|
33
35
|
## Quick Start
|
|
34
36
|
|
|
@@ -723,8 +723,8 @@ var mockData = {
|
|
|
723
723
|
{ "name": "F4", "label": "Dynamic Brake", "lockable": true, "icon": null, "selectedIcon": null },
|
|
724
724
|
{ "name": "F5", "label": null, "lockable": false, "icon": null, "selectedIcon": null }
|
|
725
725
|
],
|
|
726
|
-
"attributes": [],
|
|
727
|
-
"rosterGroups": []
|
|
726
|
+
"attributes": [{ "name": "RosterGroup:diesels", "value": "yes" }],
|
|
727
|
+
"rosterGroups": ["diesels"]
|
|
728
728
|
},
|
|
729
729
|
"id": 1
|
|
730
730
|
},
|
|
@@ -754,8 +754,8 @@ var mockData = {
|
|
|
754
754
|
{ "name": "F3", "label": "Steam", "lockable": true, "icon": null, "selectedIcon": null },
|
|
755
755
|
{ "name": "F4", "label": null, "lockable": false, "icon": null, "selectedIcon": null }
|
|
756
756
|
],
|
|
757
|
-
"attributes": [],
|
|
758
|
-
"rosterGroups": []
|
|
757
|
+
"attributes": [{ "name": "RosterGroup:steam", "value": "yes" }],
|
|
758
|
+
"rosterGroups": ["steam"]
|
|
759
759
|
},
|
|
760
760
|
"id": 2
|
|
761
761
|
},
|
|
@@ -786,13 +786,19 @@ var mockData = {
|
|
|
786
786
|
{ "name": "F4", "label": null, "lockable": false, "icon": null, "selectedIcon": null },
|
|
787
787
|
{ "name": "F5", "label": "Mars Light", "lockable": true, "icon": null, "selectedIcon": null }
|
|
788
788
|
],
|
|
789
|
-
"attributes": [],
|
|
790
|
-
"rosterGroups": []
|
|
789
|
+
"attributes": [{ "name": "RosterGroup:diesels", "value": "yes" }],
|
|
790
|
+
"rosterGroups": ["diesels"]
|
|
791
791
|
},
|
|
792
792
|
"id": 3
|
|
793
793
|
}
|
|
794
794
|
]
|
|
795
795
|
},
|
|
796
|
+
"rosterGroup": {
|
|
797
|
+
"list": [
|
|
798
|
+
{ "type": "rosterGroup", "data": { "name": "diesels", "length": 2 } },
|
|
799
|
+
{ "type": "rosterGroup", "data": { "name": "steam", "length": 1 } }
|
|
800
|
+
]
|
|
801
|
+
},
|
|
796
802
|
"throttle": {
|
|
797
803
|
"acquire": {
|
|
798
804
|
"success": {
|
|
@@ -891,6 +897,7 @@ var mockData = {
|
|
|
891
897
|
// src/mocks/mock-response-manager.ts
|
|
892
898
|
var MockResponseManager = class {
|
|
893
899
|
constructor(options = {}) {
|
|
900
|
+
this.powerStateByPrefix = /* @__PURE__ */ new Map();
|
|
894
901
|
this.throttles = /* @__PURE__ */ new Map();
|
|
895
902
|
this.lights = /* @__PURE__ */ new Map([
|
|
896
903
|
["IL1", 4 /* OFF */],
|
|
@@ -919,6 +926,8 @@ var MockResponseManager = class {
|
|
|
919
926
|
return this.getPowerResponse(message);
|
|
920
927
|
case "roster":
|
|
921
928
|
return this.getRosterResponse(message);
|
|
929
|
+
case "rosterGroup":
|
|
930
|
+
return this.getRosterGroupResponse();
|
|
922
931
|
case "throttle":
|
|
923
932
|
return this.getThrottleResponse(message);
|
|
924
933
|
case "light":
|
|
@@ -940,34 +949,48 @@ var MockResponseManager = class {
|
|
|
940
949
|
return JSON.parse(JSON.stringify(mockData.hello));
|
|
941
950
|
}
|
|
942
951
|
/**
|
|
943
|
-
* Get power response
|
|
952
|
+
* Get power response, with optional per-prefix state tracking
|
|
944
953
|
*/
|
|
945
954
|
getPowerResponse(message) {
|
|
946
|
-
|
|
955
|
+
const prefix = message.data?.prefix;
|
|
956
|
+
if (message.method === "post" && message.data?.state !== void 0) {
|
|
957
|
+
if (prefix !== void 0) {
|
|
958
|
+
this.powerStateByPrefix.set(prefix, message.data.state);
|
|
959
|
+
return { type: "power", data: { state: message.data.state, prefix } };
|
|
960
|
+
}
|
|
947
961
|
this.powerState = message.data.state;
|
|
948
|
-
return {
|
|
949
|
-
type: "power",
|
|
950
|
-
data: { state: this.powerState }
|
|
951
|
-
};
|
|
962
|
+
return { type: "power", data: { state: this.powerState } };
|
|
952
963
|
}
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
data: { state
|
|
956
|
-
}
|
|
964
|
+
if (prefix !== void 0) {
|
|
965
|
+
const state = this.powerStateByPrefix.get(prefix) ?? 0 /* UNKNOWN */;
|
|
966
|
+
return { type: "power", data: { state, prefix } };
|
|
967
|
+
}
|
|
968
|
+
return { type: "power", data: { state: this.powerState } };
|
|
957
969
|
}
|
|
958
970
|
/**
|
|
959
|
-
* Get roster response
|
|
971
|
+
* Get roster response, optionally filtered by group
|
|
960
972
|
*/
|
|
961
973
|
getRosterResponse(message) {
|
|
962
974
|
if (message.type === "roster" && message.method === "list") {
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
975
|
+
const all = JSON.parse(JSON.stringify(mockData.roster.list));
|
|
976
|
+
const group = message.params?.group;
|
|
977
|
+
if (group) {
|
|
978
|
+
return {
|
|
979
|
+
type: "roster",
|
|
980
|
+
data: all.filter((e) => e.data.rosterGroups?.includes(group))
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
return { type: "roster", data: all };
|
|
967
984
|
}
|
|
985
|
+
return { type: "roster", data: [] };
|
|
986
|
+
}
|
|
987
|
+
/**
|
|
988
|
+
* Get roster group response
|
|
989
|
+
*/
|
|
990
|
+
getRosterGroupResponse() {
|
|
968
991
|
return {
|
|
969
|
-
type: "
|
|
970
|
-
data:
|
|
992
|
+
type: "rosterGroup",
|
|
993
|
+
data: JSON.parse(JSON.stringify(mockData.rosterGroup.list))
|
|
971
994
|
};
|
|
972
995
|
}
|
|
973
996
|
/**
|
|
@@ -986,13 +1009,11 @@ var MockResponseManager = class {
|
|
|
986
1009
|
F1: false,
|
|
987
1010
|
F2: false,
|
|
988
1011
|
F3: false,
|
|
989
|
-
F4: false
|
|
1012
|
+
F4: false,
|
|
1013
|
+
...data.prefix !== void 0 && { prefix: data.prefix }
|
|
990
1014
|
};
|
|
991
1015
|
this.throttles.set(throttleId, throttleState);
|
|
992
|
-
return {
|
|
993
|
-
type: "throttle",
|
|
994
|
-
data: { ...throttleState }
|
|
995
|
-
};
|
|
1016
|
+
return { type: "throttle", data: { ...throttleState } };
|
|
996
1017
|
}
|
|
997
1018
|
if (data.release !== void 0 && data.throttle) {
|
|
998
1019
|
this.throttles.delete(data.throttle);
|
|
@@ -1125,6 +1146,7 @@ var MockResponseManager = class {
|
|
|
1125
1146
|
*/
|
|
1126
1147
|
reset() {
|
|
1127
1148
|
this.powerState = 4 /* OFF */;
|
|
1149
|
+
this.powerStateByPrefix.clear();
|
|
1128
1150
|
this.throttles.clear();
|
|
1129
1151
|
this.lights = /* @__PURE__ */ new Map([
|
|
1130
1152
|
["IL1", 4 /* OFF */],
|
|
@@ -1608,6 +1630,32 @@ var RosterManager = class {
|
|
|
1608
1630
|
}
|
|
1609
1631
|
return results;
|
|
1610
1632
|
}
|
|
1633
|
+
/**
|
|
1634
|
+
* Get all roster groups
|
|
1635
|
+
*/
|
|
1636
|
+
async getRosterGroups() {
|
|
1637
|
+
const message = {
|
|
1638
|
+
type: "rosterGroup",
|
|
1639
|
+
method: "list"
|
|
1640
|
+
};
|
|
1641
|
+
const response = await this.client.request(message);
|
|
1642
|
+
if (!response.data) return [];
|
|
1643
|
+
return response.data.map((wrapper) => wrapper.data);
|
|
1644
|
+
}
|
|
1645
|
+
/**
|
|
1646
|
+
* Get roster entries belonging to a specific group
|
|
1647
|
+
*/
|
|
1648
|
+
async getRosterEntriesByGroup(group) {
|
|
1649
|
+
const message = {
|
|
1650
|
+
type: "roster",
|
|
1651
|
+
method: "list",
|
|
1652
|
+
params: { group }
|
|
1653
|
+
};
|
|
1654
|
+
const response = await this.client.request(message);
|
|
1655
|
+
if (!response.data) return [];
|
|
1656
|
+
const entries = response.data;
|
|
1657
|
+
return entries.filter((e) => e.type === "rosterEntry");
|
|
1658
|
+
}
|
|
1611
1659
|
/**
|
|
1612
1660
|
* Get cached roster (no network request)
|
|
1613
1661
|
*/
|
|
@@ -2315,6 +2363,18 @@ var JmriClient = class extends import_index.default {
|
|
|
2315
2363
|
async searchRoster(query) {
|
|
2316
2364
|
return this.rosterManager.searchRoster(query);
|
|
2317
2365
|
}
|
|
2366
|
+
/**
|
|
2367
|
+
* Get all roster groups
|
|
2368
|
+
*/
|
|
2369
|
+
async getRosterGroups() {
|
|
2370
|
+
return this.rosterManager.getRosterGroups();
|
|
2371
|
+
}
|
|
2372
|
+
/**
|
|
2373
|
+
* Get roster entries belonging to a specific group
|
|
2374
|
+
*/
|
|
2375
|
+
async getRosterEntriesByGroup(group) {
|
|
2376
|
+
return this.rosterManager.getRosterEntriesByGroup(group);
|
|
2377
|
+
}
|
|
2318
2378
|
// ============================================================================
|
|
2319
2379
|
// Turnout Control
|
|
2320
2380
|
// ============================================================================
|