@matter-server/ws-controller 0.7.0-alpha.0-20260512-b404bea → 0.7.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.
Files changed (35) hide show
  1. package/dist/esm/controller/ControllerCommandHandler.d.ts +10 -0
  2. package/dist/esm/controller/ControllerCommandHandler.d.ts.map +1 -1
  3. package/dist/esm/controller/ControllerCommandHandler.js +93 -24
  4. package/dist/esm/controller/ControllerCommandHandler.js.map +1 -1
  5. package/dist/esm/controller/MatterController.d.ts +7 -2
  6. package/dist/esm/controller/MatterController.d.ts.map +1 -1
  7. package/dist/esm/controller/MatterController.js +46 -3
  8. package/dist/esm/controller/MatterController.js.map +1 -1
  9. package/dist/esm/controller/Nodes.d.ts +7 -61
  10. package/dist/esm/controller/Nodes.d.ts.map +1 -1
  11. package/dist/esm/controller/Nodes.js +13 -77
  12. package/dist/esm/controller/Nodes.js.map +1 -1
  13. package/dist/esm/controller/WebRtcCallbackBridge.d.ts +9 -0
  14. package/dist/esm/controller/WebRtcCallbackBridge.d.ts.map +1 -0
  15. package/dist/esm/controller/WebRtcCallbackBridge.js +75 -0
  16. package/dist/esm/controller/WebRtcCallbackBridge.js.map +6 -0
  17. package/dist/esm/controller/behaviors/WebRtcTransportRequestorServer.d.ts +35 -0
  18. package/dist/esm/controller/behaviors/WebRtcTransportRequestorServer.d.ts.map +1 -0
  19. package/dist/esm/controller/behaviors/WebRtcTransportRequestorServer.js +123 -0
  20. package/dist/esm/controller/behaviors/WebRtcTransportRequestorServer.js.map +6 -0
  21. package/dist/esm/index.d.ts +2 -1
  22. package/dist/esm/index.d.ts.map +1 -1
  23. package/dist/esm/index.js +3 -1
  24. package/dist/esm/index.js.map +1 -1
  25. package/dist/esm/server/WebSocketControllerHandler.d.ts.map +1 -1
  26. package/dist/esm/server/WebSocketControllerHandler.js +17 -0
  27. package/dist/esm/server/WebSocketControllerHandler.js.map +1 -1
  28. package/package.json +22 -21
  29. package/src/controller/ControllerCommandHandler.ts +121 -42
  30. package/src/controller/MatterController.ts +54 -4
  31. package/src/controller/Nodes.ts +13 -78
  32. package/src/controller/WebRtcCallbackBridge.ts +79 -0
  33. package/src/controller/behaviors/WebRtcTransportRequestorServer.ts +149 -0
  34. package/src/index.ts +2 -1
  35. package/src/server/WebSocketControllerHandler.ts +24 -0
@@ -9,33 +9,21 @@ import { AttributeDataCache } from "./AttributeDataCache.js";
9
9
  class Nodes {
10
10
  #nodes = /* @__PURE__ */ new Map();
11
11
  #attributeCache = new AttributeDataCache();
12
- /** Track previous connection state for availability debouncing */
13
- #previousStates = /* @__PURE__ */ new Map();
14
- /** Cached availability so serialization and event paths always agree */
12
+ /** Cached so serialization and event paths always agree on availability. */
15
13
  #lastAvailability = /* @__PURE__ */ new Map();
16
14
  /**
17
- * Endpoint additions queued until the next nodeStructureChanged for that node.
18
- * Preserves the wire contract used by python-matter-server: endpoint_added must
19
- * arrive AFTER a node_updated that already carries the new endpoint, so consumers
20
- * (e.g., Home Assistant) can resolve node.endpoints[endpoint_id] in their callback.
15
+ * Buffered endpoint_added events. python-matter-server wire contract requires
16
+ * node_updated (carrying the new endpoint) to arrive before endpoint_added,
17
+ * so HA can resolve node.endpoints[endpoint_id] in its callback.
21
18
  */
22
19
  #pendingEndpointAdds = /* @__PURE__ */ new Map();
23
- /**
24
- * Get the attribute cache instance.
25
- */
26
20
  get attributeCache() {
27
21
  return this.#attributeCache;
28
22
  }
29
- /**
30
- * Get all node IDs.
31
- */
32
23
  getIds() {
33
24
  return Array.from(this.#nodes.keys());
34
25
  }
35
- /**
36
- * Get a node by ID.
37
- * @throws ServerError if node not found
38
- */
26
+ /** @throws ServerError if node not found */
39
27
  get(nodeId) {
40
28
  const node = this.#nodes.get(nodeId);
41
29
  if (node === void 0) {
@@ -43,31 +31,18 @@ class Nodes {
43
31
  }
44
32
  return node;
45
33
  }
46
- /**
47
- * Check if a node exists.
48
- */
49
34
  has(nodeId) {
50
35
  return this.#nodes.has(nodeId);
51
36
  }
52
- /**
53
- * Add or update a node in storage.
54
- */
55
37
  set(nodeId, node) {
56
38
  this.#nodes.set(nodeId, node);
57
39
  }
58
- /**
59
- * Remove a node from storage and clear its attribute cache and state tracking.
60
- */
61
40
  delete(nodeId) {
62
41
  this.#nodes.delete(nodeId);
63
42
  this.#attributeCache.delete(nodeId);
64
- this.#previousStates.delete(nodeId);
65
43
  this.#lastAvailability.delete(nodeId);
66
44
  this.#pendingEndpointAdds.delete(nodeId);
67
45
  }
68
- /**
69
- * Buffer an endpoint_added until the next nodeStructureChanged for that node.
70
- */
71
46
  queueEndpointAdded(nodeId, endpointId) {
72
47
  let queue = this.#pendingEndpointAdds.get(nodeId);
73
48
  if (queue === void 0) {
@@ -76,10 +51,7 @@ class Nodes {
76
51
  }
77
52
  queue.push(endpointId);
78
53
  }
79
- /**
80
- * Take ownership of buffered endpoint additions for a node and clear the queue.
81
- * Returned array is in insertion order; an empty array is returned if nothing is queued.
82
- */
54
+ /** Returns insertion-ordered queue; empty if nothing pending. */
83
55
  drainPendingEndpointAdds(nodeId) {
84
56
  const queue = this.#pendingEndpointAdds.get(nodeId);
85
57
  if (queue === void 0 || queue.length === 0) {
@@ -88,68 +60,32 @@ class Nodes {
88
60
  this.#pendingEndpointAdds.delete(nodeId);
89
61
  return queue;
90
62
  }
91
- /**
92
- * Initialize state tracking for a newly paired/discovered node.
93
- * Sets previous state and initial availability so the first stateChanged event
94
- * has a real previous state instead of undefined.
95
- */
96
63
  seedState(nodeId, initialState) {
97
- this.#previousStates.set(nodeId, initialState);
98
64
  this.#lastAvailability.set(nodeId, initialState === NodeStates.Connected);
99
65
  }
100
- /**
101
- * Process a state change for a node. Reads previous state BEFORE updating,
102
- * computes new availability, and updates both tracking maps atomically.
103
- * Returns whether availability changed and the new value.
104
- */
105
- processStateChange(nodeId, newState) {
106
- const previousState = this.#previousStates.get(nodeId);
66
+ /** `debouncePending` = reconnect timer armed by caller; keeps non-Connected states available. */
67
+ processStateChange(nodeId, newState, debouncePending) {
107
68
  const wasAvailable = this.#lastAvailability.get(nodeId) ?? false;
108
- const available = this.isNodeAvailable(newState, previousState);
109
- this.#previousStates.set(nodeId, newState);
69
+ const available = this.isNodeAvailable(newState, debouncePending);
110
70
  this.#lastAvailability.set(nodeId, available);
111
71
  if (wasAvailable !== available) {
112
72
  return { availabilityChanged: true, available };
113
73
  }
114
74
  return { availabilityChanged: false };
115
75
  }
116
- /**
117
- * Force a node to unavailable state. Used by reconnect timeout
118
- * when debounce period expires without reconnection.
119
- * Only updates #lastAvailability — #previousStates is left as-is because
120
- * processStateChange() will overwrite it on the next real state transition.
121
- * Returns true if the node was previously considered available.
122
- */
76
+ /** Returns true if the node was previously considered available. */
123
77
  forceUnavailable(nodeId) {
124
78
  const wasAvailable = this.#lastAvailability.get(nodeId) ?? false;
125
79
  this.#lastAvailability.set(nodeId, false);
126
80
  return wasAvailable;
127
81
  }
128
- /**
129
- * Determine if a node should be considered available based on its connection state.
130
- * Uses debouncing logic similar to Python Matter Server:
131
- * - Connected: available
132
- * - Reconnecting when previously Connected: still available (debouncing)
133
- * - WaitingForDeviceDiscovery or Disconnected: unavailable
134
- *
135
- * @param currentState Current connection state
136
- * @param previousState Previous connection state (undefined if first state change)
137
- * @returns true if node should be considered available
138
- */
139
- isNodeAvailable(currentState, previousState) {
82
+ isNodeAvailable(currentState, debouncePending = false) {
140
83
  if (currentState === NodeStates.Connected) {
141
84
  return true;
142
85
  }
143
- if (currentState === NodeStates.Reconnecting && previousState === NodeStates.Connected) {
144
- return true;
145
- }
146
- return false;
86
+ return debouncePending;
147
87
  }
148
- /**
149
- * Check if a node is available. Returns the cached availability value set by
150
- * seedState/processStateChange/forceUnavailable, avoiding the race where
151
- * recomputing from live state disagrees with the event path's determination.
152
- */
88
+ /** Returns the cached value, not a recomputation — avoids disagreement with the event path. */
153
89
  isAvailable(nodeId) {
154
90
  return this.#lastAvailability.get(nodeId) ?? false;
155
91
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/controller/Nodes.ts"],
4
- "mappings": "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",
4
+ "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,SAAS,kBAA8B;AACvC,SAAS,mBAAmB;AAC5B,SAAS,0BAA0B;AAW5B,MAAM,MAAM;AAAA,EACf,SAAS,oBAAI,IAAwB;AAAA,EACrC,kBAAkB,IAAI,mBAAmB;AAAA;AAAA,EAEzC,oBAAoB,oBAAI,IAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM7C,uBAAuB,oBAAI,IAA8B;AAAA,EAEzD,IAAI,iBAAqC;AACrC,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,SAAmB;AACf,WAAO,MAAM,KAAK,KAAK,OAAO,KAAK,CAAC;AAAA,EACxC;AAAA;AAAA,EAGA,IAAI,QAA4B;AAC5B,UAAM,OAAO,KAAK,OAAO,IAAI,MAAM;AACnC,QAAI,SAAS,QAAW;AACpB,YAAM,YAAY,cAAc,MAAM;AAAA,IAC1C;AACA,WAAO;AAAA,EACX;AAAA,EAEA,IAAI,QAAyB;AACzB,WAAO,KAAK,OAAO,IAAI,MAAM;AAAA,EACjC;AAAA,EAEA,IAAI,QAAgB,MAAwB;AACxC,SAAK,OAAO,IAAI,QAAQ,IAAI;AAAA,EAChC;AAAA,EAEA,OAAO,QAAsB;AACzB,SAAK,OAAO,OAAO,MAAM;AACzB,SAAK,gBAAgB,OAAO,MAAM;AAClC,SAAK,kBAAkB,OAAO,MAAM;AACpC,SAAK,qBAAqB,OAAO,MAAM;AAAA,EAC3C;AAAA,EAEA,mBAAmB,QAAgB,YAAkC;AACjE,QAAI,QAAQ,KAAK,qBAAqB,IAAI,MAAM;AAChD,QAAI,UAAU,QAAW;AACrB,cAAQ,CAAC;AACT,WAAK,qBAAqB,IAAI,QAAQ,KAAK;AAAA,IAC/C;AACA,UAAM,KAAK,UAAU;AAAA,EACzB;AAAA;AAAA,EAGA,yBAAyB,QAAkC;AACvD,UAAM,QAAQ,KAAK,qBAAqB,IAAI,MAAM;AAClD,QAAI,UAAU,UAAa,MAAM,WAAW,GAAG;AAC3C,aAAO,CAAC;AAAA,IACZ;AACA,SAAK,qBAAqB,OAAO,MAAM;AACvC,WAAO;AAAA,EACX;AAAA,EAEA,UAAU,QAAgB,cAAgC;AACtD,SAAK,kBAAkB,IAAI,QAAQ,iBAAiB,WAAW,SAAS;AAAA,EAC5E;AAAA;AAAA,EAGA,mBACI,QACA,UACA,iBACkF;AAClF,UAAM,eAAe,KAAK,kBAAkB,IAAI,MAAM,KAAK;AAC3D,UAAM,YAAY,KAAK,gBAAgB,UAAU,eAAe;AAEhE,SAAK,kBAAkB,IAAI,QAAQ,SAAS;AAE5C,QAAI,iBAAiB,WAAW;AAC5B,aAAO,EAAE,qBAAqB,MAAM,UAAU;AAAA,IAClD;AACA,WAAO,EAAE,qBAAqB,MAAM;AAAA,EACxC;AAAA;AAAA,EAGA,iBAAiB,QAAyB;AACtC,UAAM,eAAe,KAAK,kBAAkB,IAAI,MAAM,KAAK;AAC3D,SAAK,kBAAkB,IAAI,QAAQ,KAAK;AACxC,WAAO;AAAA,EACX;AAAA,EAEA,gBAAgB,cAA0B,kBAAkB,OAAgB;AACxE,QAAI,iBAAiB,WAAW,WAAW;AACvC,aAAO;AAAA,IACX;AACA,WAAO;AAAA,EACX;AAAA;AAAA,EAGA,YAAY,QAAyB;AACjC,WAAO,KAAK,kBAAkB,IAAI,MAAM,KAAK;AAAA,EACjD;AACJ;",
5
5
  "names": []
6
6
  }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { WebRtcCallbackData } from "@matter-server/ws-client";
7
+ import type { WebRtcTransportRequestorServer } from "./behaviors/WebRtcTransportRequestorServer.js";
8
+ export declare function attachWebRtcCallbackBridge(events: WebRtcTransportRequestorServer.Events, emit: (data: WebRtcCallbackData) => void): void;
9
+ //# sourceMappingURL=WebRtcCallbackBridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebRtcCallbackBridge.d.ts","sourceRoot":"","sources":["../../../src/controller/WebRtcCallbackBridge.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,+CAA+C,CAAC;AAIpG,wBAAgB,0BAA0B,CACtC,MAAM,EAAE,8BAA8B,CAAC,MAAM,EAC7C,IAAI,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,GACzC,IAAI,CA+DN"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { Logger } from "@matter/main";
7
+ const logger = Logger.get("WebRtcCallbackBridge");
8
+ function attachWebRtcCallbackBridge(events, emit) {
9
+ events.offer.on((session, request) => {
10
+ logger.info(
11
+ `offer from peer node=${session.peerNodeId} ep=${session.peerEndpointId} session=${session.id} sdpLen=${request.sdp.length}`
12
+ );
13
+ emit({
14
+ event_type: "offer",
15
+ webrtc_session_id: session.id,
16
+ node_id: session.peerNodeId,
17
+ endpoint_id: session.peerEndpointId,
18
+ fabric_index: session.fabricIndex,
19
+ data: {
20
+ sdp: request.sdp,
21
+ ice_servers: request.iceServers,
22
+ ice_transport_policy: request.iceTransportPolicy
23
+ }
24
+ });
25
+ });
26
+ events.answer.on((session, sdp) => {
27
+ logger.info(
28
+ `answer from peer node=${session.peerNodeId} ep=${session.peerEndpointId} session=${session.id} sdpLen=${sdp.length}`
29
+ );
30
+ emit({
31
+ event_type: "answer",
32
+ webrtc_session_id: session.id,
33
+ node_id: session.peerNodeId,
34
+ endpoint_id: session.peerEndpointId,
35
+ fabric_index: session.fabricIndex,
36
+ data: { sdp }
37
+ });
38
+ });
39
+ events.iceCandidates.on((session, candidates) => {
40
+ logger.info(
41
+ `ice_candidates from peer node=${session.peerNodeId} ep=${session.peerEndpointId} session=${session.id} count=${candidates.length}`
42
+ );
43
+ emit({
44
+ event_type: "ice_candidates",
45
+ webrtc_session_id: session.id,
46
+ node_id: session.peerNodeId,
47
+ endpoint_id: session.peerEndpointId,
48
+ fabric_index: session.fabricIndex,
49
+ data: {
50
+ ice_candidates: candidates.map((c) => ({
51
+ candidate: c.candidate,
52
+ sdpMid: c.sdpMid ?? null,
53
+ sdpMLineIndex: c.sdpmLineIndex ?? null
54
+ }))
55
+ }
56
+ });
57
+ });
58
+ events.end.on((session, reason) => {
59
+ logger.info(
60
+ `end from peer node=${session.peerNodeId} ep=${session.peerEndpointId} session=${session.id} reason=${reason}`
61
+ );
62
+ emit({
63
+ event_type: "end",
64
+ webrtc_session_id: session.id,
65
+ node_id: session.peerNodeId,
66
+ endpoint_id: session.peerEndpointId,
67
+ fabric_index: session.fabricIndex,
68
+ data: { reason }
69
+ });
70
+ });
71
+ }
72
+ export {
73
+ attachWebRtcCallbackBridge
74
+ };
75
+ //# sourceMappingURL=WebRtcCallbackBridge.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/controller/WebRtcCallbackBridge.ts"],
4
+ "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,SAAS,cAAc;AAGvB,MAAM,SAAS,OAAO,IAAI,sBAAsB;AAEzC,SAAS,2BACZ,QACA,MACI;AACJ,SAAO,MAAM,GAAG,CAAC,SAAS,YAAY;AAClC,WAAO;AAAA,MACH,wBAAwB,QAAQ,UAAU,OAAO,QAAQ,cAAc,YAAY,QAAQ,EAAE,WAAW,QAAQ,IAAI,MAAM;AAAA,IAC9H;AACA,SAAK;AAAA,MACD,YAAY;AAAA,MACZ,mBAAmB,QAAQ;AAAA,MAC3B,SAAS,QAAQ;AAAA,MACjB,aAAa,QAAQ;AAAA,MACrB,cAAc,QAAQ;AAAA,MACtB,MAAM;AAAA,QACF,KAAK,QAAQ;AAAA,QACb,aAAa,QAAQ;AAAA,QACrB,sBAAsB,QAAQ;AAAA,MAClC;AAAA,IACJ,CAAC;AAAA,EACL,CAAC;AACD,SAAO,OAAO,GAAG,CAAC,SAAS,QAAQ;AAC/B,WAAO;AAAA,MACH,yBAAyB,QAAQ,UAAU,OAAO,QAAQ,cAAc,YAAY,QAAQ,EAAE,WAAW,IAAI,MAAM;AAAA,IACvH;AACA,SAAK;AAAA,MACD,YAAY;AAAA,MACZ,mBAAmB,QAAQ;AAAA,MAC3B,SAAS,QAAQ;AAAA,MACjB,aAAa,QAAQ;AAAA,MACrB,cAAc,QAAQ;AAAA,MACtB,MAAM,EAAE,IAAI;AAAA,IAChB,CAAC;AAAA,EACL,CAAC;AACD,SAAO,cAAc,GAAG,CAAC,SAAS,eAAe;AAC7C,WAAO;AAAA,MACH,iCAAiC,QAAQ,UAAU,OAAO,QAAQ,cAAc,YAAY,QAAQ,EAAE,UAAU,WAAW,MAAM;AAAA,IACrI;AACA,SAAK;AAAA,MACD,YAAY;AAAA,MACZ,mBAAmB,QAAQ;AAAA,MAC3B,SAAS,QAAQ;AAAA,MACjB,aAAa,QAAQ;AAAA,MACrB,cAAc,QAAQ;AAAA,MACtB,MAAM;AAAA,QACF,gBAAgB,WAAW,IAAI,QAAM;AAAA,UACjC,WAAW,EAAE;AAAA,UACb,QAAQ,EAAE,UAAU;AAAA,UACpB,eAAe,EAAE,iBAAiB;AAAA,QACtC,EAAE;AAAA,MACN;AAAA,IACJ,CAAC;AAAA,EACL,CAAC;AACD,SAAO,IAAI,GAAG,CAAC,SAAS,WAAW;AAC/B,WAAO;AAAA,MACH,sBAAsB,QAAQ,UAAU,OAAO,QAAQ,cAAc,YAAY,QAAQ,EAAE,WAAW,MAAM;AAAA,IAChH;AACA,SAAK;AAAA,MACD,YAAY;AAAA,MACZ,mBAAmB,QAAQ;AAAA,MAC3B,SAAS,QAAQ;AAAA,MACjB,aAAa,QAAQ;AAAA,MACrB,cAAc,QAAQ;AAAA,MACtB,MAAM,EAAE,OAAO;AAAA,IACnB,CAAC;AAAA,EACL,CAAC;AACL;",
5
+ "names": []
6
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { Observable } from "@matter/general";
7
+ import { WebRtcTransportRequestorBehavior } from "@matter/node/behaviors/web-rtc-transport-requestor";
8
+ import { WebRtcTransportDefinitions } from "@matter/types/clusters/web-rtc-transport-definitions";
9
+ import { WebRtcTransportRequestor } from "@matter/types/clusters/web-rtc-transport-requestor";
10
+ type WebRtcSession = WebRtcTransportDefinitions.WebRtcSession;
11
+ export declare class WebRtcTransportRequestorServer extends WebRtcTransportRequestorBehavior {
12
+ #private;
13
+ state: WebRtcTransportRequestorServer.State;
14
+ events: WebRtcTransportRequestorServer.Events;
15
+ upsertSession(session: WebRtcSession): void;
16
+ removeSession(id: number): void;
17
+ offer(request: WebRtcTransportRequestor.OfferRequest): Promise<void>;
18
+ answer(request: WebRtcTransportRequestor.AnswerRequest): Promise<void>;
19
+ iceCandidates(request: WebRtcTransportRequestor.IceCandidatesRequest): Promise<void>;
20
+ end(request: WebRtcTransportRequestor.EndRequest): Promise<void>;
21
+ initialize(): Promise<void>;
22
+ }
23
+ export declare namespace WebRtcTransportRequestorServer {
24
+ class State extends WebRtcTransportRequestorBehavior.State {
25
+ currentSessions: WebRtcSession[];
26
+ }
27
+ class Events extends WebRtcTransportRequestorBehavior.Events {
28
+ offer: Observable<[session: WebRtcTransportDefinitions.WebRtcSession, args: WebRtcTransportRequestor.OfferRequest], void>;
29
+ answer: Observable<[session: WebRtcTransportDefinitions.WebRtcSession, sdp: string], void>;
30
+ iceCandidates: Observable<[session: WebRtcTransportDefinitions.WebRtcSession, candidates: WebRtcTransportDefinitions.IceCandidate[]], void>;
31
+ end: Observable<[session: WebRtcTransportDefinitions.WebRtcSession, reason: WebRtcTransportDefinitions.WebRtcEndReason], void>;
32
+ }
33
+ }
34
+ export {};
35
+ //# sourceMappingURL=WebRtcTransportRequestorServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebRtcTransportRequestorServer.d.ts","sourceRoot":"","sources":["../../../../src/controller/behaviors/WebRtcTransportRequestorServer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAI7C,OAAO,EAAE,gCAAgC,EAAE,MAAM,oDAAoD,CAAC;AAItG,OAAO,EAAE,0BAA0B,EAAE,MAAM,sDAAsD,CAAC;AAClG,OAAO,EAAE,wBAAwB,EAAE,MAAM,oDAAoD,CAAC;AAE9F,KAAK,aAAa,GAAG,0BAA0B,CAAC,aAAa,CAAC;AAI9D,qBAAa,8BAA+B,SAAQ,gCAAgC;;IACxE,KAAK,EAAE,8BAA8B,CAAC,KAAK,CAAC;IAC5C,MAAM,EAAE,8BAA8B,CAAC,MAAM,CAAC;IAEtD,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAa1C;IAED,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE9B;IAEc,KAAK,CAAC,OAAO,EAAE,wBAAwB,CAAC,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAIlF;IAEc,MAAM,CAAC,OAAO,EAAE,wBAAwB,CAAC,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAIpF;IAEc,aAAa,CAAC,OAAO,EAAE,wBAAwB,CAAC,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CASlG;IAEc,GAAG,CAAC,OAAO,EAAE,wBAAwB,CAAC,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAK9E;IAEc,UAAU,kBASxB;CAqDJ;AAED,yBAAiB,8BAA8B,CAAC,CAAC;IAC7C,MAAa,KAAM,SAAQ,gCAAgC,CAAC,KAAK;QACpD,eAAe,EAAE,aAAa,EAAE,CAA8B;KAC1E;IACD,MAAa,MAAO,SAAQ,gCAAgC,CAAC,MAAM;QAC/D,KAAK,qHAAuF;QAC5F,MAAM,qFAAuD;QAC7D,aAAa,+HAAiG;QAC9G,GAAG,4HAA8F;KACpG;CACJ"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { Observable } from "@matter/general";
7
+ import { Logger, Node } from "@matter/main";
8
+ import { AccessControlServer } from "@matter/node/behaviors/access-control";
9
+ import { WebRtcTransportRequestorBehavior } from "@matter/node/behaviors/web-rtc-transport-requestor";
10
+ import { assertRemoteActor, FabricAuthority, NodeSession } from "@matter/protocol";
11
+ import { Status, StatusResponseError } from "@matter/types";
12
+ import { AccessControl } from "@matter/types/clusters/access-control";
13
+ import { WebRtcTransportRequestor } from "@matter/types/clusters/web-rtc-transport-requestor";
14
+ const logger = Logger.get("WebRtcTransportRequestorServer");
15
+ class WebRtcTransportRequestorServer extends WebRtcTransportRequestorBehavior {
16
+ upsertSession(session) {
17
+ const enriched = {
18
+ ...session,
19
+ videoStreamId: session.videoStreams?.[0] ?? null,
20
+ audioStreamId: session.audioStreams?.[0] ?? null
21
+ };
22
+ const sessions = this.state.currentSessions;
23
+ const idx = sessions.findIndex((s) => s.id === session.id);
24
+ if (idx === -1) {
25
+ this.state.currentSessions = [...sessions, enriched];
26
+ } else {
27
+ this.state.currentSessions = sessions.map((s, i) => i === idx ? enriched : s);
28
+ }
29
+ }
30
+ removeSession(id) {
31
+ this.state.currentSessions = this.state.currentSessions.filter((s) => s.id !== id);
32
+ }
33
+ async offer(request) {
34
+ logger.info(`incoming Offer webRtcSessionId=${request.webRtcSessionId} sdpLen=${request.sdp.length}`);
35
+ const session = this.#findSessionStrict(request.webRtcSessionId);
36
+ this.events.offer.emit(session, request);
37
+ }
38
+ async answer(request) {
39
+ logger.info(`incoming Answer webRtcSessionId=${request.webRtcSessionId} sdpLen=${request.sdp.length}`);
40
+ const session = this.#findSessionStrict(request.webRtcSessionId);
41
+ this.events.answer.emit(session, request.sdp);
42
+ }
43
+ async iceCandidates(request) {
44
+ logger.info(
45
+ `incoming ICECandidates webRtcSessionId=${request.webRtcSessionId} count=${request.iceCandidates.length}`
46
+ );
47
+ if (request.iceCandidates.length === 0) {
48
+ throw new StatusResponseError("ICE candidates list must not be empty", Status.InvalidCommand);
49
+ }
50
+ const session = this.#findSessionStrict(request.webRtcSessionId);
51
+ this.events.iceCandidates.emit(session, request.iceCandidates);
52
+ }
53
+ async end(request) {
54
+ logger.info(`incoming End webRtcSessionId=${request.webRtcSessionId} reason=${request.reason}`);
55
+ const session = this.#findSessionStrict(request.webRtcSessionId);
56
+ this.removeSession(request.webRtcSessionId);
57
+ this.events.end.emit(session, request.reason);
58
+ }
59
+ async initialize() {
60
+ const node = Node.forEndpoint(this.endpoint);
61
+ logger.info(
62
+ `initialized on endpoint=${this.endpoint.number} (id="${this.endpoint.id}") cluster=0x${WebRtcTransportRequestor.id.toString(16)}`
63
+ );
64
+ this.reactTo(node.lifecycle.online, this.#nodeOnline);
65
+ if (node.lifecycle.isOnline) {
66
+ await this.#nodeOnline();
67
+ }
68
+ }
69
+ async #nodeOnline() {
70
+ const fabricAuthority = this.env.get(FabricAuthority);
71
+ const ownFabric = fabricAuthority.fabrics[0];
72
+ if (!ownFabric) {
73
+ fabricAuthority.fabricAdded.once(() => void this.#nodeOnline());
74
+ return;
75
+ }
76
+ const node = Node.forEndpoint(this.endpoint);
77
+ await node.act((agent) => agent.load(AccessControlServer));
78
+ if (node.behaviors.has(AccessControlServer)) {
79
+ if (!node.stateOf(AccessControlServer).acl.some(
80
+ ({ fabricIndex, privilege, authMode, subjects, targets }) => fabricIndex === ownFabric.fabricIndex && privilege === AccessControl.AccessControlEntryPrivilege.Operate && authMode === AccessControl.AccessControlEntryAuthMode.Case && subjects?.length === 0 && targets?.length === 1 && targets[0].endpoint === this.endpoint.number && targets[0].cluster === WebRtcTransportRequestor.id
81
+ )) {
82
+ const acl = [
83
+ ...node.stateOf(AccessControlServer).acl,
84
+ {
85
+ fabricIndex: ownFabric.fabricIndex,
86
+ privilege: AccessControl.AccessControlEntryPrivilege.Operate,
87
+ authMode: AccessControl.AccessControlEntryAuthMode.Case,
88
+ subjects: [],
89
+ targets: [{ endpoint: this.endpoint.number, cluster: WebRtcTransportRequestor.id }]
90
+ }
91
+ ];
92
+ await node.setStateOf(AccessControlServer, { acl });
93
+ }
94
+ }
95
+ }
96
+ #findSessionStrict(id) {
97
+ assertRemoteActor(this.context);
98
+ NodeSession.assert(this.context.session);
99
+ const peer = this.context.session.peerAddress;
100
+ const session = this.state.currentSessions.find((s) => s.id === id);
101
+ if (session === void 0 || session.fabricIndex !== peer.fabricIndex || session.peerNodeId !== peer.nodeId) {
102
+ throw new StatusResponseError(`WebRTC session ${id} not found`, Status.NotFound);
103
+ }
104
+ return session;
105
+ }
106
+ }
107
+ ((WebRtcTransportRequestorServer2) => {
108
+ class State extends WebRtcTransportRequestorBehavior.State {
109
+ currentSessions = new Array();
110
+ }
111
+ WebRtcTransportRequestorServer2.State = State;
112
+ class Events extends WebRtcTransportRequestorBehavior.Events {
113
+ offer = Observable();
114
+ answer = Observable();
115
+ iceCandidates = Observable();
116
+ end = Observable();
117
+ }
118
+ WebRtcTransportRequestorServer2.Events = Events;
119
+ })(WebRtcTransportRequestorServer || (WebRtcTransportRequestorServer = {}));
120
+ export {
121
+ WebRtcTransportRequestorServer
122
+ };
123
+ //# sourceMappingURL=WebRtcTransportRequestorServer.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/controller/behaviors/WebRtcTransportRequestorServer.ts"],
4
+ "mappings": "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",
5
+ "names": ["WebRtcTransportRequestorServer"]
6
+ }
@@ -6,6 +6,7 @@
6
6
  /**
7
7
  * @matter-server/ws-controller - Matter controller Websocket library
8
8
  */
9
+ export * from "./controller/behaviors/WebRtcTransportRequestorServer.js";
9
10
  export * from "./controller/ControllerCommandHandler.js";
10
11
  export * from "./controller/LegacyDataInjector.js";
11
12
  export * from "./controller/MatterController.js";
@@ -19,5 +20,5 @@ export * from "./types/CommandHandler.js";
19
20
  export * from "./types/WebSocketMessageTypes.js";
20
21
  export { formatNodeId } from "./util/formatNodeId.js";
21
22
  export * from "./util/matterVersion.js";
22
- export { Crypto, Environment, LogDestination, LogFormat, LogLevel, Logger } from "@matter/main";
23
+ export { Crypto, Environment, LogDestination, LogFormat, LogLevel, Logger, StorageService } from "@matter/main";
23
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AAGH,cAAc,0CAA0C,CAAC;AACzD,cAAc,oCAAoC,CAAC;AACnD,cAAc,kCAAkC,CAAC;AACjD,cAAc,kCAAkC,CAAC;AAGjD,cAAc,wBAAwB,CAAC;AAGvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,wCAAwC,CAAC;AACvD,cAAc,sBAAsB,CAAC;AAGrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AAGjD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,cAAc,yBAAyB,CAAC;AAGxC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AAGH,cAAc,0DAA0D,CAAC;AACzE,cAAc,0CAA0C,CAAC;AACzD,cAAc,oCAAoC,CAAC;AACnD,cAAc,kCAAkC,CAAC;AACjD,cAAc,kCAAkC,CAAC;AAGjD,cAAc,wBAAwB,CAAC;AAGvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,wCAAwC,CAAC;AACvD,cAAc,sBAAsB,CAAC;AAGrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AAGjD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,cAAc,yBAAyB,CAAC;AAGxC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
package/dist/esm/index.js CHANGED
@@ -3,6 +3,7 @@
3
3
  * Copyright 2025-2026 Open Home Foundation
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
+ export * from "./controller/behaviors/WebRtcTransportRequestorServer.js";
6
7
  export * from "./controller/ControllerCommandHandler.js";
7
8
  export * from "./controller/LegacyDataInjector.js";
8
9
  export * from "./controller/MatterController.js";
@@ -16,7 +17,7 @@ export * from "./types/CommandHandler.js";
16
17
  export * from "./types/WebSocketMessageTypes.js";
17
18
  import { formatNodeId } from "./util/formatNodeId.js";
18
19
  export * from "./util/matterVersion.js";
19
- import { Crypto, Environment, LogDestination, LogFormat, LogLevel, Logger } from "@matter/main";
20
+ import { Crypto, Environment, LogDestination, LogFormat, LogLevel, Logger, StorageService } from "@matter/main";
20
21
  export {
21
22
  Crypto,
22
23
  Environment,
@@ -24,6 +25,7 @@ export {
24
25
  LogFormat,
25
26
  LogLevel,
26
27
  Logger,
28
+ StorageService,
27
29
  formatNodeId
28
30
  };
29
31
  //# sourceMappingURL=index.js.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts"],
4
- "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAWA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AAGd,SAAS,oBAAoB;AAC7B,cAAc;AAGd,SAAS,QAAQ,aAAa,gBAAgB,WAAW,UAAU,cAAc;",
4
+ "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAWA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AAGd,SAAS,oBAAoB;AAC7B,cAAc;AAGd,SAAS,QAAQ,aAAa,gBAAgB,WAAW,UAAU,QAAQ,sBAAsB;",
5
5
  "names": []
6
6
  }
@@ -1 +1 @@
1
- {"version":3,"file":"WebSocketControllerHandler.d.ts","sourceRoot":"","sources":["../../../src/server/WebSocketControllerHandler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAoBH,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAKrE,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAMH,eAAe,EAMlB,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AA+BnD,yDAAyD;AACzD,qBAAa,0BAA2B,YAAW,gBAAgB;;IAc/D,YAAY,UAAU,EAAE,gBAAgB,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,EAMrF;IAED;;;OAGG;IACH,MAAM;QAIE,OAAO;QACP,UAAU;MAEjB;IAoBD;;OAEG;IACH,eAAe,IAAI,eAAe,EAAE,CAEnC;IAED,gBAAgB,IAAI,IAAI,CAEvB;IAEK,QAAQ,CAAC,MAAM,EAAE,UAAU,iBAiOhC;IAED,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CA+B1B;CAqxBJ"}
1
+ {"version":3,"file":"WebSocketControllerHandler.d.ts","sourceRoot":"","sources":["../../../src/server/WebSocketControllerHandler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAoBH,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAKrE,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAMH,eAAe,EAMlB,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AA+BnD,yDAAyD;AACzD,qBAAa,0BAA2B,YAAW,gBAAgB;;IAe/D,YAAY,UAAU,EAAE,gBAAgB,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,EAMrF;IAED;;;OAGG;IACH,MAAM;QAIE,OAAO;QACP,UAAU;MAEjB;IAoBD;;OAEG;IACH,eAAe,IAAI,eAAe,EAAE,CAEnC;IAED,gBAAgB,IAAI,IAAI,CAEvB;IAEK,QAAQ,CAAC,MAAM,EAAE,UAAU,iBAwOhC;IAED,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAgC1B;CAoyBJ"}
@@ -54,6 +54,7 @@ class WebSocketControllerHandler {
54
54
  #wss;
55
55
  #closed = false;
56
56
  #shuttingDown = false;
57
+ #serverObservers = new ObserverGroup();
57
58
  /** Circular buffer for recent node events (max 25) */
58
59
  #eventHistory = [];
59
60
  /** Track when each node was last interviewed (connected) - keyed by nodeId */
@@ -105,6 +106,9 @@ class WebSocketControllerHandler {
105
106
  async register(server) {
106
107
  logger.info(`Starting server: matter-server/${this.#serverVersion} (matter.js/${MATTER_VERSION})`);
107
108
  const wss = this.#wss = new WebSocketServer({ server, path: "/ws" });
109
+ this.#serverObservers.on(this.#commandHandler.events.webRtcCallback, (data) => {
110
+ this.#broadcastEvent("webrtc_callback", data);
111
+ });
108
112
  wss.on("connection", (ws) => {
109
113
  if (this.#closed || this.#shuttingDown) {
110
114
  try {
@@ -293,6 +297,7 @@ class WebSocketControllerHandler {
293
297
  return Promise.resolve();
294
298
  }
295
299
  this.#closed = true;
300
+ this.#serverObservers.close();
296
301
  const shutdownMessage = toBigIntAwareJson({ event: "server_shutdown", data: {} });
297
302
  this.#wss.clients.forEach((client) => {
298
303
  if (client.readyState === 1) {
@@ -359,6 +364,9 @@ class WebSocketControllerHandler {
359
364
  case "device_command":
360
365
  result = await this.#handleDeviceCommand(args);
361
366
  break;
367
+ case "send_webrtc_provider_command":
368
+ result = await this.#handleSendWebRtcProviderCommand(args);
369
+ break;
362
370
  case "write_attribute":
363
371
  result = await this.#handleWriteAttribute(args);
364
372
  break;
@@ -713,6 +721,15 @@ class WebSocketControllerHandler {
713
721
  }
714
722
  return cmdResult;
715
723
  }
724
+ async #handleSendWebRtcProviderCommand(args) {
725
+ const { node_id, endpoint_id, command_name, payload } = args;
726
+ return this.#commandHandler.sendWebRtcProviderCommand({
727
+ nodeId: NodeId(node_id),
728
+ endpointId: EndpointNumber(endpoint_id),
729
+ commandName: command_name,
730
+ payload
731
+ });
732
+ }
716
733
  async #handleInterviewNode(args) {
717
734
  const { node_id } = args;
718
735
  const nodeId = NodeId(node_id);