@matter-server/ws-controller 0.5.9 → 0.5.11

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 (30) hide show
  1. package/dist/esm/controller/AttributeDataCache.d.ts.map +1 -1
  2. package/dist/esm/controller/AttributeDataCache.js +18 -14
  3. package/dist/esm/controller/AttributeDataCache.js.map +1 -1
  4. package/dist/esm/controller/ControllerCommandHandler.d.ts +2 -14
  5. package/dist/esm/controller/ControllerCommandHandler.d.ts.map +1 -1
  6. package/dist/esm/controller/ControllerCommandHandler.js +17 -74
  7. package/dist/esm/controller/ControllerCommandHandler.js.map +1 -1
  8. package/dist/esm/controller/LegacyDataInjector.d.ts.map +1 -1
  9. package/dist/esm/controller/LegacyDataInjector.js +2 -3
  10. package/dist/esm/controller/LegacyDataInjector.js.map +1 -1
  11. package/dist/esm/controller/MatterController.d.ts.map +1 -1
  12. package/dist/esm/controller/MatterController.js +30 -27
  13. package/dist/esm/controller/MatterController.js.map +1 -1
  14. package/dist/esm/controller/Nodes.d.ts +1 -1
  15. package/dist/esm/controller/Nodes.d.ts.map +1 -1
  16. package/dist/esm/controller/Nodes.js.map +1 -1
  17. package/dist/esm/controller/ServerIdResolver.d.ts.map +1 -1
  18. package/dist/esm/controller/ServerIdResolver.js +35 -25
  19. package/dist/esm/controller/ServerIdResolver.js.map +1 -1
  20. package/dist/esm/server/WebSocketControllerHandler.d.ts.map +1 -1
  21. package/dist/esm/server/WebSocketControllerHandler.js +26 -1
  22. package/dist/esm/server/WebSocketControllerHandler.js.map +1 -1
  23. package/package.json +5 -5
  24. package/src/controller/AttributeDataCache.ts +18 -14
  25. package/src/controller/ControllerCommandHandler.ts +20 -84
  26. package/src/controller/LegacyDataInjector.ts +2 -3
  27. package/src/controller/MatterController.ts +35 -33
  28. package/src/controller/Nodes.ts +2 -2
  29. package/src/controller/ServerIdResolver.ts +38 -28
  30. package/src/server/WebSocketControllerHandler.ts +26 -1
@@ -168,7 +168,7 @@ export class Nodes {
168
168
  nodeId: NodeId,
169
169
  endpointId: EndpointNumber,
170
170
  cluster: T,
171
- ): ClusterClientObj<T> {
172
- return this.clusterClientByIdFor(nodeId, endpointId, cluster.id) as ClusterClientObj<T>;
171
+ ): ClusterClientObj<T["Typing"]> {
172
+ return this.clusterClientByIdFor(nodeId, endpointId, cluster.id!) as ClusterClientObj<T["Typing"]>;
173
173
  }
174
174
  }
@@ -104,39 +104,49 @@ export async function resolveServerId(
104
104
  // Open and verify the fabric configuration matches
105
105
  try {
106
106
  const baseStorage = await config.service.open(DEFAULT_SERVER_ID);
107
- const fabricsContext = baseStorage.createContext("fabrics");
107
+ let closed = false;
108
+ try {
109
+ const fabricsContext = baseStorage.createContext("fabrics");
108
110
 
109
- // Read fabric entries
110
- const fabrics = await fabricsContext.get<{ fabricId: FabricId; rootVendorId: VendorId }[]>("fabrics", []);
111
- if (fabrics.length === 1) {
112
- // Single fabric - check if it matches
113
- const fabricData = fabrics[0];
114
- const storedFabricId = fabricData.fabricId;
115
- const storedVendorId = fabricData.rootVendorId;
116
- if (storedFabricId === FabricId(fabricId) && storedVendorId === vendorId) {
117
- // Matching fabric - rename it to the new format to avoid future checks
118
- await baseStorage.close();
119
- if (storagePath !== undefined) {
120
- const oldPath = join(storagePath, DEFAULT_SERVER_ID);
121
- const newPath = join(storagePath, candidateId);
122
- try {
123
- await rename(oldPath, newPath);
124
- logger.info(`Renamed storage "${DEFAULT_SERVER_ID}" to "${candidateId}"`);
125
- return candidateId;
126
- } catch (renameErr) {
127
- logger.error(
128
- `Failed to rename storage from "${DEFAULT_SERVER_ID}" to "${candidateId}"`,
129
- renameErr,
130
- );
131
- return DEFAULT_SERVER_ID;
111
+ // Read fabric entries
112
+ const fabrics = await fabricsContext.get<{ fabricId: FabricId; rootVendorId: VendorId }[]>(
113
+ "fabrics",
114
+ [],
115
+ );
116
+ if (fabrics.length === 1) {
117
+ // Single fabric - check if it matches
118
+ const fabricData = fabrics[0];
119
+ const storedFabricId = fabricData.fabricId;
120
+ const storedVendorId = fabricData.rootVendorId;
121
+ if (storedFabricId === FabricId(fabricId) && storedVendorId === vendorId) {
122
+ // Matching fabric - close before rename to release file handles
123
+ await baseStorage.close();
124
+ closed = true;
125
+ if (storagePath !== undefined) {
126
+ const oldPath = join(storagePath, DEFAULT_SERVER_ID);
127
+ const newPath = join(storagePath, candidateId);
128
+ try {
129
+ await rename(oldPath, newPath);
130
+ logger.info(`Renamed storage "${DEFAULT_SERVER_ID}" to "${candidateId}"`);
131
+ return candidateId;
132
+ } catch (renameErr) {
133
+ logger.error(
134
+ `Failed to rename storage from "${DEFAULT_SERVER_ID}" to "${candidateId}"`,
135
+ renameErr,
136
+ );
137
+ return DEFAULT_SERVER_ID;
138
+ }
132
139
  }
140
+ return DEFAULT_SERVER_ID;
133
141
  }
134
- return DEFAULT_SERVER_ID;
142
+ } else {
143
+ logger.error(`Multiple fabrics found, using new storage`, fabrics);
144
+ }
145
+ } finally {
146
+ if (!closed) {
147
+ await baseStorage.close();
135
148
  }
136
- } else {
137
- logger.error(`Multiple fabrics found, using new storage`, fabrics);
138
149
  }
139
- await baseStorage.close();
140
150
  logger.info(`Existing "server" storage does not match fabric config, using new ID: ${candidateId}`);
141
151
  } catch (err) {
142
152
  logger.debug(`Could not verify "server" storage: ${err}`);
@@ -4,7 +4,19 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import { camelize, ClusterId, FabricIndex, Logger, LogLevel, Millis, NodeId, ObserverGroup } from "@matter/main";
7
+ import {
8
+ MatterError,
9
+ Diagnostic,
10
+ Bytes,
11
+ camelize,
12
+ ClusterId,
13
+ FabricIndex,
14
+ Logger,
15
+ LogLevel,
16
+ Millis,
17
+ NodeId,
18
+ ObserverGroup,
19
+ } from "@matter/main";
8
20
  import { ControllerCommissioningFlowOptions } from "@matter/main/protocol";
9
21
  import { EndpointNumber, QrPairingCodeCodec } from "@matter/main/types";
10
22
  import { NodeStates } from "@project-chip/matter.js/device";
@@ -874,6 +886,19 @@ export class WebSocketControllerHandler implements WebServerHandler {
874
886
 
875
887
  async #handleSetThreadDataset(args: ArgsOf<"set_thread_dataset">): Promise<ResponseOf<"set_thread_dataset">> {
876
888
  const { dataset } = args;
889
+ if (!/^[0-9a-fA-F]*$/.test(dataset) || dataset.length % 2 !== 0) {
890
+ throw ServerError.invalidArguments(
891
+ "Invalid Thread operational dataset: must be a hex string with even length (each byte is two hex characters)",
892
+ );
893
+ }
894
+ try {
895
+ Bytes.fromHex(dataset);
896
+ } catch (error) {
897
+ MatterError.accept(error);
898
+ throw ServerError.invalidArguments(
899
+ `Invalid Thread operational dataset: failed to parse hex string: ${Diagnostic.errorMessage(error)}`,
900
+ );
901
+ }
877
902
  await this.#config.set({ threadDataset: dataset });
878
903
  // Broadcast server_info_updated event to notify clients of credential change
879
904
  try {