@matter-server/ws-client 1.1.8-alpha.0-20260707-c552b9d → 1.2.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/dist/esm/client.d.ts +47 -6
- package/dist/esm/client.d.ts.map +1 -1
- package/dist/esm/client.js +88 -14
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/exceptions.d.ts +5 -0
- package/dist/esm/exceptions.d.ts.map +1 -1
- package/dist/esm/exceptions.js +10 -1
- package/dist/esm/exceptions.js.map +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/models/model.d.ts +266 -51
- package/dist/esm/models/model.d.ts.map +1 -1
- package/dist/esm/models/model.js +2 -0
- package/dist/esm/models/model.js.map +1 -1
- package/dist/esm/topology/topology-types.d.ts +235 -0
- package/dist/esm/topology/topology-types.d.ts.map +1 -0
- package/dist/esm/topology/topology-types.js +19 -0
- package/dist/esm/topology/topology-types.js.map +6 -0
- package/dist/esm/topology/topology-utils.d.ts +185 -0
- package/dist/esm/topology/topology-utils.d.ts.map +1 -0
- package/dist/esm/topology/topology-utils.js +599 -0
- package/dist/esm/topology/topology-utils.js.map +6 -0
- package/package.json +6 -4
- package/src/client.ts +149 -21
- package/src/exceptions.ts +11 -0
- package/src/index.ts +4 -0
- package/src/models/model.ts +266 -53
- package/src/topology/topology-types.ts +249 -0
- package/src/topology/topology-utils.ts +932 -0
package/src/client.ts
CHANGED
|
@@ -5,15 +5,17 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { Connection, WebSocketFactory } from "./connection.js";
|
|
8
|
-
import { CommandTimeoutError, ConnectionClosedError, InvalidServerVersion } from "./exceptions.js";
|
|
8
|
+
import { CommandTimeoutError, ConnectionClosedError, InvalidServerVersion, ServerCommandError } from "./exceptions.js";
|
|
9
9
|
import {
|
|
10
10
|
AccessControlEntry,
|
|
11
|
+
AllCredentialsSummary,
|
|
11
12
|
APICommands,
|
|
12
13
|
BindingTarget,
|
|
13
14
|
CommissionableNodeData,
|
|
14
15
|
CommissioningParameters,
|
|
15
16
|
ErrorResultMessage,
|
|
16
17
|
EventMessage,
|
|
18
|
+
IcdStateData,
|
|
17
19
|
LogLevelResponse,
|
|
18
20
|
SettableLogLevelString,
|
|
19
21
|
MatterFabricData,
|
|
@@ -21,6 +23,7 @@ import {
|
|
|
21
23
|
MatterSoftwareVersion,
|
|
22
24
|
NodePingResult,
|
|
23
25
|
SuccessResultMessage,
|
|
26
|
+
ThreadDiagnosticsBatch,
|
|
24
27
|
WebRtcCallbackData,
|
|
25
28
|
} from "./models/model.js";
|
|
26
29
|
import { MatterNode } from "./models/node.js";
|
|
@@ -36,9 +39,33 @@ function toNodeKey(nodeId: number | bigint): string {
|
|
|
36
39
|
/** Default timeout for WebSocket commands in milliseconds (5 minutes) */
|
|
37
40
|
export const DEFAULT_COMMAND_TIMEOUT = 5 * 60 * 1000;
|
|
38
41
|
|
|
42
|
+
/** Options for {@link MatterClient.commissionWithCode}. */
|
|
43
|
+
export interface CommissionWithCodeOptions {
|
|
44
|
+
/** Stored WiFi credential id to use (schema 12; omit for the reserved `default` entry). */
|
|
45
|
+
wifiCredentialsId?: string;
|
|
46
|
+
/** Stored Thread dataset id to use (schema 12; omit for the reserved `default` entry). */
|
|
47
|
+
threadDatasetId?: string;
|
|
48
|
+
/** Per-call command timeout in ms (overrides {@link MatterClient.commandTimeout}). */
|
|
49
|
+
timeout?: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Options for the credential set/remove commands. */
|
|
53
|
+
export interface CredentialCommandOptions {
|
|
54
|
+
/** Named credential entry id (schema 12); omit for the reserved `default` entry. */
|
|
55
|
+
id?: string;
|
|
56
|
+
/** Per-call command timeout in ms (overrides {@link MatterClient.commandTimeout}). */
|
|
57
|
+
timeout?: number;
|
|
58
|
+
}
|
|
59
|
+
|
|
39
60
|
export class MatterClient {
|
|
40
61
|
public connection: Connection;
|
|
41
62
|
public nodes: Record<string, MatterNode> = {};
|
|
63
|
+
/**
|
|
64
|
+
* Latest Thread diagnostic batch per network, keyed by 16-char uppercase extPanId hex.
|
|
65
|
+
* Replaced (not mutated) on every update so consumers passing this map as a Lit
|
|
66
|
+
* @property() detect the snapshot change via the default `===` identity compare.
|
|
67
|
+
*/
|
|
68
|
+
public threadDiagnostics: ReadonlyMap<string, ThreadDiagnosticsBatch> = new Map();
|
|
42
69
|
public serverBaseAddress: string;
|
|
43
70
|
/** Whether this client is connected to a production server (optional, for UI purposes) */
|
|
44
71
|
public isProduction: boolean = false;
|
|
@@ -107,40 +134,91 @@ export class MatterClient {
|
|
|
107
134
|
};
|
|
108
135
|
}
|
|
109
136
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
137
|
+
commissionWithCode(code: string, networkOnly?: boolean, options?: CommissionWithCodeOptions): Promise<MatterNode>;
|
|
138
|
+
/** @deprecated Pass the timeout via the options object (`{ timeout }`) instead. */
|
|
139
|
+
commissionWithCode(code: string, networkOnly: boolean, timeout: number): Promise<MatterNode>;
|
|
140
|
+
async commissionWithCode(
|
|
141
|
+
code: string,
|
|
142
|
+
networkOnly = true,
|
|
143
|
+
optsOrTimeout?: number | CommissionWithCodeOptions,
|
|
144
|
+
): Promise<MatterNode> {
|
|
145
|
+
const opts = typeof optsOrTimeout === "number" ? { timeout: optsOrTimeout } : (optsOrTimeout ?? {});
|
|
146
|
+
const usesIds = opts.wifiCredentialsId !== undefined || opts.threadDatasetId !== undefined;
|
|
116
147
|
const data = await this.sendCommand(
|
|
117
148
|
"commission_with_code",
|
|
118
|
-
0,
|
|
149
|
+
usesIds ? 12 : 0,
|
|
119
150
|
{
|
|
120
|
-
code
|
|
151
|
+
code,
|
|
121
152
|
network_only: networkOnly,
|
|
153
|
+
wifi_credentials_id: opts.wifiCredentialsId,
|
|
154
|
+
thread_dataset_id: opts.threadDatasetId,
|
|
122
155
|
},
|
|
123
|
-
timeout,
|
|
156
|
+
opts.timeout,
|
|
124
157
|
);
|
|
125
158
|
return new MatterNode(data);
|
|
126
159
|
}
|
|
127
160
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
161
|
+
setWifiCredentials(ssid: string, credentials: string, options?: CredentialCommandOptions): Promise<void>;
|
|
162
|
+
/** @deprecated Pass the timeout via the options object (`{ timeout }`) instead. */
|
|
163
|
+
setWifiCredentials(ssid: string, credentials: string, timeout: number): Promise<void>;
|
|
164
|
+
async setWifiCredentials(
|
|
165
|
+
ssid: string,
|
|
166
|
+
credentials: string,
|
|
167
|
+
optsOrTimeout?: number | CredentialCommandOptions,
|
|
168
|
+
): Promise<void> {
|
|
169
|
+
const opts = typeof optsOrTimeout === "number" ? { timeout: optsOrTimeout } : (optsOrTimeout ?? {});
|
|
170
|
+
await this.sendCommand(
|
|
171
|
+
"set_wifi_credentials",
|
|
172
|
+
opts.id === undefined || opts.id === "default" ? 0 : 12,
|
|
173
|
+
{ ssid, credentials, id: opts.id },
|
|
174
|
+
opts.timeout,
|
|
175
|
+
);
|
|
131
176
|
}
|
|
132
177
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
178
|
+
setThreadOperationalDataset(dataset: string, options?: CredentialCommandOptions): Promise<void>;
|
|
179
|
+
/** @deprecated Pass the timeout via the options object (`{ timeout }`) instead. */
|
|
180
|
+
setThreadOperationalDataset(dataset: string, timeout: number): Promise<void>;
|
|
181
|
+
async setThreadOperationalDataset(
|
|
182
|
+
dataset: string,
|
|
183
|
+
optsOrTimeout?: number | CredentialCommandOptions,
|
|
184
|
+
): Promise<void> {
|
|
185
|
+
const opts = typeof optsOrTimeout === "number" ? { timeout: optsOrTimeout } : (optsOrTimeout ?? {});
|
|
186
|
+
await this.sendCommand(
|
|
187
|
+
"set_thread_dataset",
|
|
188
|
+
opts.id === undefined || opts.id === "default" ? 0 : 12,
|
|
189
|
+
{ dataset, id: opts.id },
|
|
190
|
+
opts.timeout,
|
|
191
|
+
);
|
|
136
192
|
}
|
|
137
193
|
|
|
138
|
-
|
|
139
|
-
|
|
194
|
+
removeWifiCredentials(options?: CredentialCommandOptions): Promise<void>;
|
|
195
|
+
/** @deprecated Pass the timeout via the options object (`{ timeout }`) instead. */
|
|
196
|
+
removeWifiCredentials(timeout: number): Promise<void>;
|
|
197
|
+
async removeWifiCredentials(optsOrTimeout?: number | CredentialCommandOptions): Promise<void> {
|
|
198
|
+
const opts = typeof optsOrTimeout === "number" ? { timeout: optsOrTimeout } : (optsOrTimeout ?? {});
|
|
199
|
+
await this.sendCommand(
|
|
200
|
+
"remove_wifi_credentials",
|
|
201
|
+
opts.id === undefined || opts.id === "default" ? 0 : 12,
|
|
202
|
+
{ id: opts.id },
|
|
203
|
+
opts.timeout,
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
removeThreadDataset(options?: CredentialCommandOptions): Promise<void>;
|
|
208
|
+
/** @deprecated Pass the timeout via the options object (`{ timeout }`) instead. */
|
|
209
|
+
removeThreadDataset(timeout: number): Promise<void>;
|
|
210
|
+
async removeThreadDataset(optsOrTimeout?: number | CredentialCommandOptions): Promise<void> {
|
|
211
|
+
const opts = typeof optsOrTimeout === "number" ? { timeout: optsOrTimeout } : (optsOrTimeout ?? {});
|
|
212
|
+
await this.sendCommand(
|
|
213
|
+
"remove_thread_dataset",
|
|
214
|
+
opts.id === undefined || opts.id === "default" ? 0 : 12,
|
|
215
|
+
{ id: opts.id },
|
|
216
|
+
opts.timeout,
|
|
217
|
+
);
|
|
140
218
|
}
|
|
141
219
|
|
|
142
|
-
async
|
|
143
|
-
|
|
220
|
+
async getAllCredentials(timeout?: number): Promise<AllCredentialsSummary> {
|
|
221
|
+
return this.sendCommand("get_all_credentials", 12, {}, timeout);
|
|
144
222
|
}
|
|
145
223
|
|
|
146
224
|
async openCommissioningWindow(
|
|
@@ -219,6 +297,35 @@ export class MatterClient {
|
|
|
219
297
|
await this.sendCommand("interview_node", 0, { node_id: nodeId }, timeout);
|
|
220
298
|
}
|
|
221
299
|
|
|
300
|
+
async registerIcd(
|
|
301
|
+
nodeId: number | bigint,
|
|
302
|
+
options?: { allowMultiAdmin?: boolean; ignoredVendors?: number[] },
|
|
303
|
+
timeout?: number,
|
|
304
|
+
): Promise<IcdStateData> {
|
|
305
|
+
return this.sendCommand(
|
|
306
|
+
"register_icd",
|
|
307
|
+
0,
|
|
308
|
+
{
|
|
309
|
+
node_id: nodeId,
|
|
310
|
+
allow_multi_admin: options?.allowMultiAdmin,
|
|
311
|
+
ignored_vendors: options?.ignoredVendors,
|
|
312
|
+
},
|
|
313
|
+
timeout,
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
async unregisterIcd(nodeId: number | bigint, force?: boolean, timeout?: number): Promise<IcdStateData> {
|
|
318
|
+
return this.sendCommand("unregister_icd", 0, { node_id: nodeId, force }, timeout);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
async resyncIcd(nodeId: number | bigint): Promise<null> {
|
|
322
|
+
return this.sendCommand("resync_icd", 0, { node_id: nodeId });
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
async getIcdState(nodeId: number | bigint, timeout?: number): Promise<IcdStateData> {
|
|
326
|
+
return this.sendCommand("get_icd_state", 0, { node_id: nodeId }, timeout);
|
|
327
|
+
}
|
|
328
|
+
|
|
222
329
|
async importTestNode(dump: string, timeout?: number): Promise<void> {
|
|
223
330
|
// Import test node(s) from a HA or Matter server diagnostics dump.
|
|
224
331
|
await this.sendCommand("import_test_node", 0, { dump }, timeout);
|
|
@@ -354,6 +461,11 @@ export class MatterClient {
|
|
|
354
461
|
await this.sendCommand("set_default_fabric_label", 0, { label }, timeout);
|
|
355
462
|
}
|
|
356
463
|
|
|
464
|
+
async getFabricLabel(timeout?: number): Promise<string | null> {
|
|
465
|
+
const { fabric_label } = await this.sendCommand("get_fabric_label", 12, {}, timeout);
|
|
466
|
+
return fabric_label;
|
|
467
|
+
}
|
|
468
|
+
|
|
357
469
|
/**
|
|
358
470
|
* Get the current log levels for console and file logging.
|
|
359
471
|
* @param timeout Optional command timeout in milliseconds
|
|
@@ -529,6 +641,10 @@ export class MatterClient {
|
|
|
529
641
|
nodes[toNodeKey(node.node_id)] = new MatterNode(node);
|
|
530
642
|
}
|
|
531
643
|
this.nodes = nodes;
|
|
644
|
+
|
|
645
|
+
// Reset diagnostics on every (re)start so a server restart doesn't leave batches for networks
|
|
646
|
+
// the server no longer knows; fresh batches arrive via the thread_diagnostics_updated event.
|
|
647
|
+
this.threadDiagnostics = new Map();
|
|
532
648
|
}
|
|
533
649
|
|
|
534
650
|
private _handleIncomingMessage(msg: IncomingMessage) {
|
|
@@ -538,7 +654,11 @@ export class MatterClient {
|
|
|
538
654
|
}
|
|
539
655
|
|
|
540
656
|
if ("error_code" in msg) {
|
|
541
|
-
|
|
657
|
+
const details = msg.details ?? "";
|
|
658
|
+
this._rejectPendingCommand(
|
|
659
|
+
msg.message_id,
|
|
660
|
+
new ServerCommandError(details !== "" ? details : `Server error ${msg.error_code}`, msg.error_code),
|
|
661
|
+
);
|
|
542
662
|
return;
|
|
543
663
|
}
|
|
544
664
|
|
|
@@ -601,6 +721,14 @@ export class MatterClient {
|
|
|
601
721
|
return;
|
|
602
722
|
}
|
|
603
723
|
|
|
724
|
+
if (event.event === "thread_diagnostics_updated") {
|
|
725
|
+
const next = new Map(this.threadDiagnostics);
|
|
726
|
+
next.set(event.data.extPanIdHex.toUpperCase(), event.data);
|
|
727
|
+
this.threadDiagnostics = next;
|
|
728
|
+
this.fireEvent("thread_diagnostics_updated");
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
|
|
604
732
|
if (event.event === "webrtc_callback") {
|
|
605
733
|
for (const listener of this.webrtcCallbackListeners) {
|
|
606
734
|
listener(event.data);
|
package/src/exceptions.ts
CHANGED
|
@@ -30,3 +30,14 @@ export class ConnectionClosedError extends MatterError {
|
|
|
30
30
|
this.name = "ConnectionClosedError";
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
+
|
|
34
|
+
/** Command failure reported by the server; preserves the wire error_code. */
|
|
35
|
+
export class ServerCommandError extends MatterError {
|
|
36
|
+
constructor(
|
|
37
|
+
message: string,
|
|
38
|
+
readonly errorCode: number,
|
|
39
|
+
) {
|
|
40
|
+
super(message);
|
|
41
|
+
this.name = "ServerCommandError";
|
|
42
|
+
}
|
|
43
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -23,3 +23,7 @@ export * from "./json-utils.js";
|
|
|
23
23
|
// Export models
|
|
24
24
|
export * from "./models/model.js";
|
|
25
25
|
export * from "./models/node.js";
|
|
26
|
+
|
|
27
|
+
// Export network topology derivation (shared by dashboard + server)
|
|
28
|
+
export * from "./topology/topology-types.js";
|
|
29
|
+
export * from "./topology/topology-utils.js";
|