matter-server 0.2.3 → 0.2.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA0BH,QAAA,MAAM,UAAU,uEAAwE,CAAC;AAGzF,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnD,MAAM,WAAW,UAAU;IAEvB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAG7B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAG/B,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAGvB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAGhC,gBAAgB,EAAE,OAAO,CAAC;IAG1B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAGhC,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAG9B,gBAAgB,EAAE,OAAO,CAAC;CAC7B;AAsBD,wBAAgB,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,UAAU,CAgExD;AAKD,wBAAgB,aAAa,IAAI,UAAU,CAK1C"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA0BH,QAAA,MAAM,UAAU,uEAAwE,CAAC;AAGzF,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnD,MAAM,WAAW,UAAU;IAEvB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAG7B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAG/B,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAGvB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAGhC,gBAAgB,EAAE,OAAO,CAAC;IAG1B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAGhC,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAG9B,gBAAgB,EAAE,OAAO,CAAC;CAC7B;AA6BD,wBAAgB,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,UAAU,CAkHxD;AAKD,wBAAgB,aAAa,IAAI,UAAU,CAK1C"}
package/dist/esm/cli.js CHANGED
@@ -3,7 +3,7 @@
3
3
  * Copyright 2025-2026 Open Home Foundation
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- import { Command, Option } from "commander";
6
+ import { Command, InvalidArgumentError, Option } from "commander";
7
7
  import { readFileSync } from "node:fs";
8
8
  import { homedir } from "node:os";
9
9
  import { dirname, join } from "node:path";
@@ -28,6 +28,12 @@ function parseIntOption(value) {
28
28
  function collectAddresses(value, previous) {
29
29
  return previous.concat(value);
30
30
  }
31
+ function parseBooleanEnv(value) {
32
+ const lower = (value ?? "").toLowerCase().trim();
33
+ if (lower === "" || ["false", "0", "no", "off"].includes(lower)) return false;
34
+ if (["true", "1", "yes", "on"].includes(lower)) return true;
35
+ throw new InvalidArgumentError(`Invalid boolean value: "${value}". Use true/false, 1/0, yes/no, or on/off.`);
36
+ }
31
37
  const DEPRECATED_OPTIONS = {
32
38
  logLevelSdk: "--log-level-sdk",
33
39
  logNodeIds: "--log-node-ids",
@@ -37,17 +43,34 @@ const DEPRECATED_OPTIONS = {
37
43
  function parseCliArgs(argv) {
38
44
  const program = new Command();
39
45
  program.name("matter-server").description("Matter Controller Server using WebSockets.").version(VERSION);
40
- program.option("--vendorid <id>", "Vendor ID for the Fabric", parseIntOption, DEFAULT_VENDOR_ID).option(
41
- "--fabricid <id>",
42
- "Fabric ID for the Fabric (random if not specified)",
43
- parseIntOption,
44
- DEFAULT_FABRIC_ID
45
- ).option("--storage-path <path>", "Storage path to keep persistent data", DEFAULT_STORAGE_PATH).option("--port <port>", "TCP Port for WebSocket server", parseIntOption, DEFAULT_PORT).option(
46
+ program.addOption(
47
+ new Option("--vendorid <id>", "Vendor ID for the Fabric").argParser(parseIntOption).default(DEFAULT_VENDOR_ID).env("VENDOR_ID")
48
+ ).addOption(
49
+ new Option("--fabricid <id>", "Fabric ID for the Fabric (random if not specified)").argParser(parseIntOption).default(DEFAULT_FABRIC_ID).env("FABRIC_ID")
50
+ ).addOption(
51
+ new Option("--storage-path <path>", "Storage path to keep persistent data").default(DEFAULT_STORAGE_PATH).env("STORAGE_PATH")
52
+ ).addOption(
53
+ new Option("--port <port>", "TCP Port for WebSocket server").argParser(parseIntOption).default(DEFAULT_PORT).env("PORT")
54
+ ).option(
46
55
  "--listen-address <address>",
47
- "IP address to bind WebSocket server (repeatable, default: bind all)",
56
+ "IP address to bind WebSocket server (repeatable via CLI, single value via env: LISTEN_ADDRESS)",
48
57
  collectAddresses,
49
58
  []
50
- ).addOption(new Option("--log-level <level>", "Global logging level").choices(LOG_LEVELS).default("info")).option("--log-file <path>", "Log file path (optional)").option("--primary-interface <interface>", "Primary network interface for link-local addresses").option("--enable-test-net-dcl", "Enable test-net DCL certificates", false).option("--bluetooth-adapter <id>", "Bluetooth adapter HCI ID (e.g., 0 for hci0)", parseIntOption).option("--disable-ota", "Disable OTA update functionality", false).option("--ota-provider-dir <path>", "Directory for OTA Provider files").option("--disable-dashboard", "Disable the web dashboard", false).addOption(
59
+ ).addOption(
60
+ new Option("--log-level <level>", "Global logging level").choices(LOG_LEVELS).default("info").env("LOG_LEVEL")
61
+ ).addOption(new Option("--log-file <path>", "Log file path (optional)").env("LOG_FILE")).addOption(
62
+ new Option("--primary-interface <interface>", "Primary network interface for link-local addresses").env(
63
+ "PRIMARY_INTERFACE"
64
+ )
65
+ ).addOption(
66
+ new Option("--enable-test-net-dcl", "Enable test-net DCL certificates").argParser(parseBooleanEnv).default(false).env("ENABLE_TEST_NET_DCL")
67
+ ).addOption(
68
+ new Option("--bluetooth-adapter <id>", "Bluetooth adapter HCI ID (e.g., 0 for hci0)").argParser(parseIntOption).env("BLUETOOTH_ADAPTER")
69
+ ).addOption(
70
+ new Option("--disable-ota", "Disable OTA update functionality").argParser(parseBooleanEnv).default(false).env("DISABLE_OTA")
71
+ ).addOption(new Option("--ota-provider-dir <path>", "Directory for OTA Provider files").env("OTA_PROVIDER_DIR")).addOption(
72
+ new Option("--disable-dashboard", "Disable the web dashboard").argParser(parseBooleanEnv).default(false).env("DISABLE_DASHBOARD")
73
+ ).addOption(
51
74
  new Option("--log-level-sdk <level>", "Matter SDK logging level (deprecated, no longer used)").choices(SDK_LOG_LEVELS).hideHelp()
52
75
  ).option("--log-node-ids <ids...>", "Node IDs to filter logs (deprecated, no longer used)").option("--paa-root-cert-dir <path>", "Directory for PAA root certificates (deprecated, no longer used)").option("--disable-server-interactions", "Disable server cluster interactions (deprecated, no longer used)");
53
76
  program.parse(argv);
@@ -57,12 +80,18 @@ function parseCliArgs(argv) {
57
80
  console.warn(`Warning: ${flag} is deprecated and no longer supported. This option will be ignored.`);
58
81
  }
59
82
  }
83
+ let listenAddress = null;
84
+ if (Array.isArray(opts.listenAddress) && opts.listenAddress.length > 0) {
85
+ listenAddress = opts.listenAddress;
86
+ } else if (process.env.LISTEN_ADDRESS) {
87
+ listenAddress = [process.env.LISTEN_ADDRESS];
88
+ }
60
89
  return {
61
90
  vendorId: opts.vendorid,
62
91
  fabricId: opts.fabricid ?? void 0,
63
92
  storagePath: opts.storagePath,
64
93
  port: opts.port,
65
- listenAddress: opts.listenAddress.length > 0 ? opts.listenAddress : null,
94
+ listenAddress,
66
95
  logLevel: opts.logLevel,
67
96
  logFile: opts.logFile ?? null,
68
97
  primaryInterface: opts.primaryInterface ?? null,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/cli.ts"],
4
- "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAWA,SAAS,SAAS,cAAc;AAChC,SAAS,oBAAoB;AAC7B,SAAS,eAAe;AACxB,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAG9B,MAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AACxD,MAAM,kBAAkB,KAAK,WAAW,oBAAoB;AAC5D,MAAM,cAAc,KAAK,MAAM,aAAa,iBAAiB,OAAO,CAAC;AACrE,MAAM,UAAU,YAAY;AAG5B,MAAM,oBAAoB;AAC1B,MAAM,eAAe;AACrB,MAAM,uBAAuB,KAAK,QAAQ,GAAG,gBAAgB;AAC7D,MAAM,oBAAoB;AAG1B,MAAM,aAAa,CAAC,YAAY,SAAS,WAAW,QAAQ,SAAS,SAAS;AAC9E,MAAM,iBAAiB,CAAC,QAAQ,SAAS,YAAY,UAAU,YAAY;AAmC3E,SAAS,eAAe,OAAuB;AAC3C,QAAM,SAAS,SAAS,OAAO,EAAE;AACjC,MAAI,MAAM,MAAM,GAAG;AACf,UAAM,IAAI,MAAM,oBAAoB,KAAK,EAAE;AAAA,EAC/C;AACA,SAAO;AACX;AAEA,SAAS,iBAAiB,OAAe,UAA8B;AACnE,SAAO,SAAS,OAAO,KAAK;AAChC;AAGA,MAAM,qBAA6C;AAAA,EAC/C,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,2BAA2B;AAC/B;AAEO,SAAS,aAAa,MAA6B;AACtD,QAAM,UAAU,IAAI,QAAQ;AAE5B,UAAQ,KAAK,eAAe,EAAE,YAAY,4CAA4C,EAAE,QAAQ,OAAO;AAEvG,UACK,OAAO,mBAAmB,4BAA4B,gBAAgB,iBAAiB,EACvF;AAAA,IACG;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ,EACC,OAAO,yBAAyB,wCAAwC,oBAAoB,EAC5F,OAAO,iBAAiB,iCAAiC,gBAAgB,YAAY,EACrF;AAAA,IACG;AAAA,IACA;AAAA,IACA;AAAA,IACA,CAAC;AAAA,EACL,EACC,UAAU,IAAI,OAAO,uBAAuB,sBAAsB,EAAE,QAAQ,UAAU,EAAE,QAAQ,MAAM,CAAC,EACvG,OAAO,qBAAqB,0BAA0B,EACtD,OAAO,mCAAmC,oDAAoD,EAC9F,OAAO,yBAAyB,oCAAoC,KAAK,EACzE,OAAO,4BAA4B,+CAA+C,cAAc,EAChG,OAAO,iBAAiB,oCAAoC,KAAK,EACjE,OAAO,6BAA6B,kCAAkC,EACtE,OAAO,uBAAuB,6BAA6B,KAAK,EAEhE;AAAA,IACG,IAAI,OAAO,2BAA2B,uDAAuD,EACxF,QAAQ,cAAc,EACtB,SAAS;AAAA,EAClB,EACC,OAAO,2BAA2B,sDAAsD,EACxF,OAAO,8BAA8B,kEAAkE,EACvG,OAAO,iCAAiC,kEAAkE;AAE/G,UAAQ,MAAM,IAAI;AAClB,QAAM,OAAO,QAAQ,KAAK;AAG1B,aAAW,CAAC,KAAK,IAAI,KAAK,OAAO,QAAQ,kBAAkB,GAAG;AAC1D,QAAI,KAAK,GAAG,MAAM,UAAa,KAAK,GAAG,MAAM,OAAO;AAChD,cAAQ,KAAK,YAAY,IAAI,sEAAsE;AAAA,IACvG;AAAA,EACJ;AAEA,SAAO;AAAA,IACH,UAAU,KAAK;AAAA,IACf,UAAU,KAAK,YAAY;AAAA,IAC3B,aAAa,KAAK;AAAA,IAClB,MAAM,KAAK;AAAA,IACX,eAAe,KAAK,cAAc,SAAS,IAAI,KAAK,gBAAgB;AAAA,IACpE,UAAU,KAAK;AAAA,IACf,SAAS,KAAK,WAAW;AAAA,IACzB,kBAAkB,KAAK,oBAAoB;AAAA,IAC3C,kBAAkB,KAAK;AAAA,IACvB,kBAAkB,KAAK,oBAAoB;AAAA,IAC3C,YAAY,KAAK;AAAA,IACjB,gBAAgB,KAAK,kBAAkB;AAAA,IACvC,kBAAkB,KAAK;AAAA,EAC3B;AACJ;AAGA,IAAI;AAEG,SAAS,gBAA4B;AACxC,MAAI,CAAC,YAAY;AACb,iBAAa,aAAa;AAAA,EAC9B;AACA,SAAO;AACX;",
4
+ "mappings": "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",
5
5
  "names": []
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matter-server",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "type": "module",
5
5
  "description": "WebSocket Matter server based on matter.js",
6
6
  "bugs": {
@@ -23,18 +23,18 @@
23
23
  "node": ">=20.19.0 <22.0.0 || >=22.13.0"
24
24
  },
25
25
  "dependencies": {
26
- "@matter/main": "0.16.4",
27
- "@matter-server/ws-controller": "0.2.3",
28
- "@matter-server/dashboard": "0.2.3",
29
- "@matter-server/custom-clusters": "0.2.3",
26
+ "@matter/main": "0.16.5",
27
+ "@matter-server/ws-controller": "0.2.4",
28
+ "@matter-server/dashboard": "0.2.4",
29
+ "@matter-server/custom-clusters": "0.2.4",
30
30
  "commander": "^14.0.2",
31
31
  "express": "^5.2.1"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/express": "^5.0.6",
35
35
  "@types/node": "^25.0.8",
36
- "@matter/testing": "0.16.4",
37
- "@matter-server/ws-client": "0.2.3"
36
+ "@matter/testing": "0.16.5",
37
+ "@matter-server/ws-client": "0.2.4"
38
38
  },
39
39
  "files": [
40
40
  "dist/**/*",
package/src/cli.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  * Compatible with Python Matter Server CLI interface.
10
10
  */
11
11
 
12
- import { Command, Option } from "commander";
12
+ import { Command, InvalidArgumentError, Option } from "commander";
13
13
  import { readFileSync } from "node:fs";
14
14
  import { homedir } from "node:os";
15
15
  import { dirname, join } from "node:path";
@@ -76,6 +76,13 @@ function collectAddresses(value: string, previous: string[]): string[] {
76
76
  return previous.concat(value);
77
77
  }
78
78
 
79
+ function parseBooleanEnv(value: string | undefined): boolean {
80
+ const lower = (value ?? "").toLowerCase().trim();
81
+ if (lower === "" || ["false", "0", "no", "off"].includes(lower)) return false;
82
+ if (["true", "1", "yes", "on"].includes(lower)) return true;
83
+ throw new InvalidArgumentError(`Invalid boolean value: "${value}". Use true/false, 1/0, yes/no, or on/off.`);
84
+ }
85
+
79
86
  /** Deprecated options that are still accepted but no longer used */
80
87
  const DEPRECATED_OPTIONS: Record<string, string> = {
81
88
  logLevelSdk: "--log-level-sdk",
@@ -90,29 +97,71 @@ export function parseCliArgs(argv?: string[]): CliOptions {
90
97
  program.name("matter-server").description("Matter Controller Server using WebSockets.").version(VERSION);
91
98
 
92
99
  program
93
- .option("--vendorid <id>", "Vendor ID for the Fabric", parseIntOption, DEFAULT_VENDOR_ID)
94
- .option(
95
- "--fabricid <id>",
96
- "Fabric ID for the Fabric (random if not specified)",
97
- parseIntOption,
98
- DEFAULT_FABRIC_ID,
100
+ .addOption(
101
+ new Option("--vendorid <id>", "Vendor ID for the Fabric")
102
+ .argParser(parseIntOption)
103
+ .default(DEFAULT_VENDOR_ID)
104
+ .env("VENDOR_ID"),
105
+ )
106
+ .addOption(
107
+ new Option("--fabricid <id>", "Fabric ID for the Fabric (random if not specified)")
108
+ .argParser(parseIntOption)
109
+ .default(DEFAULT_FABRIC_ID)
110
+ .env("FABRIC_ID"),
111
+ )
112
+ .addOption(
113
+ new Option("--storage-path <path>", "Storage path to keep persistent data")
114
+ .default(DEFAULT_STORAGE_PATH)
115
+ .env("STORAGE_PATH"),
116
+ )
117
+ .addOption(
118
+ new Option("--port <port>", "TCP Port for WebSocket server")
119
+ .argParser(parseIntOption)
120
+ .default(DEFAULT_PORT)
121
+ .env("PORT"),
99
122
  )
100
- .option("--storage-path <path>", "Storage path to keep persistent data", DEFAULT_STORAGE_PATH)
101
- .option("--port <port>", "TCP Port for WebSocket server", parseIntOption, DEFAULT_PORT)
102
123
  .option(
103
124
  "--listen-address <address>",
104
- "IP address to bind WebSocket server (repeatable, default: bind all)",
125
+ "IP address to bind WebSocket server (repeatable via CLI, single value via env: LISTEN_ADDRESS)",
105
126
  collectAddresses,
106
127
  [],
107
128
  )
108
- .addOption(new Option("--log-level <level>", "Global logging level").choices(LOG_LEVELS).default("info"))
109
- .option("--log-file <path>", "Log file path (optional)")
110
- .option("--primary-interface <interface>", "Primary network interface for link-local addresses")
111
- .option("--enable-test-net-dcl", "Enable test-net DCL certificates", false)
112
- .option("--bluetooth-adapter <id>", "Bluetooth adapter HCI ID (e.g., 0 for hci0)", parseIntOption)
113
- .option("--disable-ota", "Disable OTA update functionality", false)
114
- .option("--ota-provider-dir <path>", "Directory for OTA Provider files")
115
- .option("--disable-dashboard", "Disable the web dashboard", false)
129
+ .addOption(
130
+ new Option("--log-level <level>", "Global logging level")
131
+ .choices(LOG_LEVELS)
132
+ .default("info")
133
+ .env("LOG_LEVEL"),
134
+ )
135
+ .addOption(new Option("--log-file <path>", "Log file path (optional)").env("LOG_FILE"))
136
+ .addOption(
137
+ new Option("--primary-interface <interface>", "Primary network interface for link-local addresses").env(
138
+ "PRIMARY_INTERFACE",
139
+ ),
140
+ )
141
+ .addOption(
142
+ new Option("--enable-test-net-dcl", "Enable test-net DCL certificates")
143
+ .argParser(parseBooleanEnv)
144
+ .default(false)
145
+ .env("ENABLE_TEST_NET_DCL"),
146
+ )
147
+ .addOption(
148
+ new Option("--bluetooth-adapter <id>", "Bluetooth adapter HCI ID (e.g., 0 for hci0)")
149
+ .argParser(parseIntOption)
150
+ .env("BLUETOOTH_ADAPTER"),
151
+ )
152
+ .addOption(
153
+ new Option("--disable-ota", "Disable OTA update functionality")
154
+ .argParser(parseBooleanEnv)
155
+ .default(false)
156
+ .env("DISABLE_OTA"),
157
+ )
158
+ .addOption(new Option("--ota-provider-dir <path>", "Directory for OTA Provider files").env("OTA_PROVIDER_DIR"))
159
+ .addOption(
160
+ new Option("--disable-dashboard", "Disable the web dashboard")
161
+ .argParser(parseBooleanEnv)
162
+ .default(false)
163
+ .env("DISABLE_DASHBOARD"),
164
+ )
116
165
  // Deprecated options - still accepted for backwards compatibility
117
166
  .addOption(
118
167
  new Option("--log-level-sdk <level>", "Matter SDK logging level (deprecated, no longer used)")
@@ -133,12 +182,20 @@ export function parseCliArgs(argv?: string[]): CliOptions {
133
182
  }
134
183
  }
135
184
 
185
+ // Handle listenAddress: CLI provides an array, env var (LISTEN_ADDRESS) provides a single string
186
+ let listenAddress: string[] | null = null;
187
+ if (Array.isArray(opts.listenAddress) && opts.listenAddress.length > 0) {
188
+ listenAddress = opts.listenAddress;
189
+ } else if (process.env.LISTEN_ADDRESS) {
190
+ listenAddress = [process.env.LISTEN_ADDRESS];
191
+ }
192
+
136
193
  return {
137
194
  vendorId: opts.vendorid,
138
195
  fabricId: opts.fabricid ?? undefined,
139
196
  storagePath: opts.storagePath,
140
197
  port: opts.port,
141
- listenAddress: opts.listenAddress.length > 0 ? opts.listenAddress : null,
198
+ listenAddress,
142
199
  logLevel: opts.logLevel,
143
200
  logFile: opts.logFile ?? null,
144
201
  primaryInterface: opts.primaryInterface ?? null,