@matter/general 0.14.1-alpha.0-20250605-9fc134af0 → 0.14.1-alpha.0-20250606-a9bcd03f9

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 (120) hide show
  1. package/dist/cjs/codec/DerCodec.js +2 -2
  2. package/dist/cjs/codec/DerCodec.js.map +1 -1
  3. package/dist/cjs/codec/DnsCodec.js +14 -14
  4. package/dist/cjs/codec/DnsCodec.js.map +1 -1
  5. package/dist/cjs/net/Network.d.ts +1 -0
  6. package/dist/cjs/net/Network.d.ts.map +1 -1
  7. package/dist/cjs/net/Network.js +3 -1
  8. package/dist/cjs/net/Network.js.map +1 -1
  9. package/dist/cjs/net/UdpChannel.d.ts +5 -2
  10. package/dist/cjs/net/UdpChannel.d.ts.map +1 -1
  11. package/dist/cjs/net/UdpChannel.js.map +1 -1
  12. package/dist/cjs/net/UdpInterface.d.ts +6 -6
  13. package/dist/cjs/net/UdpInterface.d.ts.map +1 -1
  14. package/dist/cjs/net/UdpInterface.js +32 -18
  15. package/dist/cjs/net/UdpInterface.js.map +1 -1
  16. package/dist/cjs/net/UdpMulticastServer.d.ts.map +1 -1
  17. package/dist/cjs/net/UdpMulticastServer.js +9 -8
  18. package/dist/cjs/net/UdpMulticastServer.js.map +1 -1
  19. package/dist/cjs/net/mock/MockUdpChannel.d.ts +2 -0
  20. package/dist/cjs/net/mock/MockUdpChannel.d.ts.map +1 -1
  21. package/dist/cjs/net/mock/MockUdpChannel.js +4 -0
  22. package/dist/cjs/net/mock/MockUdpChannel.js.map +1 -1
  23. package/dist/cjs/time/Time.d.ts +2 -0
  24. package/dist/cjs/time/Time.d.ts.map +1 -1
  25. package/dist/cjs/time/Time.js +7 -0
  26. package/dist/cjs/time/Time.js.map +1 -1
  27. package/dist/cjs/util/DataReadQueue.d.ts +1 -0
  28. package/dist/cjs/util/DataReadQueue.d.ts.map +1 -1
  29. package/dist/cjs/util/DataReadQueue.js +3 -0
  30. package/dist/cjs/util/DataReadQueue.js.map +1 -1
  31. package/dist/cjs/util/DataReader.d.ts +2 -2
  32. package/dist/cjs/util/DataReader.d.ts.map +1 -1
  33. package/dist/cjs/util/DataReader.js.map +1 -1
  34. package/dist/cjs/util/DataWriter.d.ts +2 -2
  35. package/dist/cjs/util/DataWriter.d.ts.map +1 -1
  36. package/dist/cjs/util/DataWriter.js.map +1 -1
  37. package/dist/cjs/util/Ip.d.ts +1 -0
  38. package/dist/cjs/util/Ip.d.ts.map +1 -1
  39. package/dist/cjs/util/Ip.js +45 -0
  40. package/dist/cjs/util/Ip.js.map +1 -1
  41. package/dist/cjs/util/Map.d.ts +24 -0
  42. package/dist/cjs/util/Map.d.ts.map +1 -0
  43. package/dist/cjs/util/Map.js +72 -0
  44. package/dist/cjs/util/Map.js.map +6 -0
  45. package/dist/cjs/util/Set.d.ts +1 -0
  46. package/dist/cjs/util/Set.d.ts.map +1 -1
  47. package/dist/cjs/util/Set.js +14 -5
  48. package/dist/cjs/util/Set.js.map +2 -2
  49. package/dist/cjs/util/index.d.ts +1 -0
  50. package/dist/cjs/util/index.d.ts.map +1 -1
  51. package/dist/cjs/util/index.js +1 -0
  52. package/dist/cjs/util/index.js.map +1 -1
  53. package/dist/esm/codec/DerCodec.js +3 -3
  54. package/dist/esm/codec/DerCodec.js.map +1 -1
  55. package/dist/esm/codec/DnsCodec.js +15 -15
  56. package/dist/esm/codec/DnsCodec.js.map +1 -1
  57. package/dist/esm/net/Network.d.ts +1 -0
  58. package/dist/esm/net/Network.d.ts.map +1 -1
  59. package/dist/esm/net/Network.js +3 -1
  60. package/dist/esm/net/Network.js.map +1 -1
  61. package/dist/esm/net/UdpChannel.d.ts +5 -2
  62. package/dist/esm/net/UdpChannel.d.ts.map +1 -1
  63. package/dist/esm/net/UdpChannel.js.map +1 -1
  64. package/dist/esm/net/UdpInterface.d.ts +6 -6
  65. package/dist/esm/net/UdpInterface.d.ts.map +1 -1
  66. package/dist/esm/net/UdpInterface.js +32 -18
  67. package/dist/esm/net/UdpInterface.js.map +1 -1
  68. package/dist/esm/net/UdpMulticastServer.d.ts.map +1 -1
  69. package/dist/esm/net/UdpMulticastServer.js +9 -8
  70. package/dist/esm/net/UdpMulticastServer.js.map +1 -1
  71. package/dist/esm/net/mock/MockUdpChannel.d.ts +2 -0
  72. package/dist/esm/net/mock/MockUdpChannel.d.ts.map +1 -1
  73. package/dist/esm/net/mock/MockUdpChannel.js +4 -0
  74. package/dist/esm/net/mock/MockUdpChannel.js.map +1 -1
  75. package/dist/esm/time/Time.d.ts +2 -0
  76. package/dist/esm/time/Time.d.ts.map +1 -1
  77. package/dist/esm/time/Time.js +7 -0
  78. package/dist/esm/time/Time.js.map +1 -1
  79. package/dist/esm/util/DataReadQueue.d.ts +1 -0
  80. package/dist/esm/util/DataReadQueue.d.ts.map +1 -1
  81. package/dist/esm/util/DataReadQueue.js +3 -0
  82. package/dist/esm/util/DataReadQueue.js.map +1 -1
  83. package/dist/esm/util/DataReader.d.ts +2 -2
  84. package/dist/esm/util/DataReader.d.ts.map +1 -1
  85. package/dist/esm/util/DataReader.js.map +1 -1
  86. package/dist/esm/util/DataWriter.d.ts +2 -2
  87. package/dist/esm/util/DataWriter.d.ts.map +1 -1
  88. package/dist/esm/util/DataWriter.js.map +1 -1
  89. package/dist/esm/util/Ip.d.ts +1 -0
  90. package/dist/esm/util/Ip.d.ts.map +1 -1
  91. package/dist/esm/util/Ip.js +45 -0
  92. package/dist/esm/util/Ip.js.map +1 -1
  93. package/dist/esm/util/Map.d.ts +24 -0
  94. package/dist/esm/util/Map.d.ts.map +1 -0
  95. package/dist/esm/util/Map.js +52 -0
  96. package/dist/esm/util/Map.js.map +6 -0
  97. package/dist/esm/util/Set.d.ts +1 -0
  98. package/dist/esm/util/Set.d.ts.map +1 -1
  99. package/dist/esm/util/Set.js +14 -5
  100. package/dist/esm/util/Set.js.map +2 -2
  101. package/dist/esm/util/index.d.ts +1 -0
  102. package/dist/esm/util/index.d.ts.map +1 -1
  103. package/dist/esm/util/index.js +1 -0
  104. package/dist/esm/util/index.js.map +1 -1
  105. package/package.json +2 -2
  106. package/src/codec/DerCodec.ts +5 -5
  107. package/src/codec/DnsCodec.ts +14 -14
  108. package/src/net/Network.ts +2 -0
  109. package/src/net/UdpChannel.ts +6 -2
  110. package/src/net/UdpInterface.ts +36 -17
  111. package/src/net/UdpMulticastServer.ts +8 -7
  112. package/src/net/mock/MockUdpChannel.ts +8 -0
  113. package/src/time/Time.ts +10 -0
  114. package/src/util/DataReadQueue.ts +4 -0
  115. package/src/util/DataReader.ts +2 -2
  116. package/src/util/DataWriter.ts +2 -2
  117. package/src/util/Ip.ts +50 -0
  118. package/src/util/Map.ts +65 -0
  119. package/src/util/Set.ts +13 -1
  120. package/src/util/index.ts +1 -0
@@ -12,16 +12,24 @@ import { TransportInterface } from "./TransportInterface.js";
12
12
  import { UdpChannel } from "./UdpChannel.js";
13
13
 
14
14
  export class UdpInterface implements NetInterface {
15
+ readonly #server: UdpChannel;
16
+
15
17
  static async create(network: Network, type: "udp4" | "udp6", port?: number, host?: string, netInterface?: string) {
16
18
  return new UdpInterface(
17
19
  await network.createUdpChannel({ listeningPort: port, type, netInterface, listeningAddress: host }),
18
20
  );
19
21
  }
20
22
 
21
- constructor(private readonly server: UdpChannel) {}
23
+ constructor(server: UdpChannel) {
24
+ this.#server = server;
25
+ }
26
+
27
+ protected get server() {
28
+ return this.#server;
29
+ }
22
30
 
23
31
  supports(type: ChannelType, address: string) {
24
- return this.server.supports(type, address);
32
+ return this.#server.supports(type, address);
25
33
  }
26
34
 
27
35
  async openChannel(address: ServerAddress) {
@@ -29,48 +37,59 @@ export class UdpInterface implements NetInterface {
29
37
  throw new NetworkError(`Unsupported address type ${address.type}`);
30
38
  }
31
39
  const { ip, port } = address;
32
- return Promise.resolve(new UdpConnection(this.server, ip, port));
40
+ return Promise.resolve(new UdpConnection(this.#server, ip, port));
33
41
  }
34
42
 
35
43
  onData(listener: (channel: Channel<Uint8Array>, messageBytes: Uint8Array) => void): TransportInterface.Listener {
36
- return this.server.onData((_netInterface, peerHost, peerPort, data) =>
37
- listener(new UdpConnection(this.server, peerHost, peerPort), data),
44
+ return this.#server.onData((_netInterface, peerHost, peerPort, data) =>
45
+ listener(new UdpConnection(this.#server, peerHost, peerPort), data),
38
46
  );
39
47
  }
40
48
 
41
49
  get port() {
42
- return this.server.port;
50
+ return this.#server.port;
43
51
  }
44
52
 
45
53
  close() {
46
- return this.server.close();
54
+ return this.#server.close();
55
+ }
56
+
57
+ addMembership(address: string) {
58
+ return this.#server.addMembership(address);
59
+ }
60
+
61
+ dropMembership(address: string) {
62
+ return this.#server.dropMembership(address);
47
63
  }
48
64
  }
49
65
 
50
- class UdpConnection implements IpNetworkChannel<Uint8Array> {
66
+ export class UdpConnection implements IpNetworkChannel<Uint8Array> {
51
67
  readonly isReliable = false;
52
68
  readonly type = ChannelType.UDP;
69
+ readonly #server: UdpChannel;
70
+ readonly #peerAddress: string;
71
+ readonly #peerPort: number;
53
72
 
54
- constructor(
55
- private readonly server: UdpChannel,
56
- private readonly peerAddress: string,
57
- private readonly peerPort: number,
58
- ) {}
73
+ constructor(server: UdpChannel, peerAddress: string, peerPort: number) {
74
+ this.#server = server;
75
+ this.#peerAddress = peerAddress;
76
+ this.#peerPort = peerPort;
77
+ }
59
78
 
60
79
  get maxPayloadSize() {
61
- return this.server.maxPayloadSize;
80
+ return this.#server.maxPayloadSize;
62
81
  }
63
82
 
64
83
  send(data: Uint8Array) {
65
- return this.server.send(this.peerAddress, this.peerPort, data);
84
+ return this.#server.send(this.#peerAddress, this.#peerPort, data);
66
85
  }
67
86
 
68
87
  get name() {
69
- return `${this.type}://[${this.peerAddress}]:${this.peerPort}`;
88
+ return `${this.type}://[${this.#peerAddress}]:${this.#peerPort}`;
70
89
  }
71
90
 
72
91
  get networkAddress(): ServerAddressIp {
73
- return { type: "udp", ip: this.peerAddress, port: this.peerPort };
92
+ return { type: "udp", ip: this.#peerAddress, port: this.#peerPort };
74
93
  }
75
94
 
76
95
  async close() {
@@ -37,8 +37,8 @@ export class UdpMulticastServer {
37
37
  type: "udp4",
38
38
  netInterface,
39
39
  listeningPort,
40
- membershipAddresses: [broadcastAddressIpv4],
41
40
  });
41
+ await ipv4UdpChannel.addMembership(broadcastAddressIpv4);
42
42
  } catch (error) {
43
43
  NoAddressAvailableError.accept(error);
44
44
  logger.info(`IPv4 UDP channel not created because IPv4 is not available: ${asError(error).message}`);
@@ -46,18 +46,19 @@ export class UdpMulticastServer {
46
46
  }
47
47
 
48
48
  try {
49
+ const ipv6UdpChannel = await network.createUdpChannel({
50
+ type: "udp6",
51
+ netInterface,
52
+ listeningPort,
53
+ });
54
+ await ipv6UdpChannel.addMembership(broadcastAddressIpv6);
49
55
  return new UdpMulticastServer(
50
56
  network,
51
57
  broadcastAddressIpv4,
52
58
  broadcastAddressIpv6,
53
59
  listeningPort,
54
60
  ipv4UdpChannel,
55
- await network.createUdpChannel({
56
- type: "udp6",
57
- netInterface,
58
- listeningPort,
59
- membershipAddresses: [broadcastAddressIpv6],
60
- }),
61
+ ipv6UdpChannel,
61
62
  netInterface,
62
63
  );
63
64
  } catch (error) {
@@ -59,4 +59,12 @@ export class MockUdpChannel implements UdpChannel {
59
59
  supports(type: ChannelType, _address: string) {
60
60
  return type === ChannelType.UDP;
61
61
  }
62
+
63
+ addMembership(_address: string): void {
64
+ // No-op for mock channel
65
+ }
66
+
67
+ dropMembership(_address: string): void {
68
+ // No-op for mock channel
69
+ }
62
70
  }
package/src/time/Time.ts CHANGED
@@ -36,6 +36,11 @@ export class Time {
36
36
  }
37
37
  static readonly nowMs = (): number => Time.get().nowMs();
38
38
 
39
+ nowUs() {
40
+ return Math.floor(performance.now() + performance.timeOrigin) * 1000;
41
+ }
42
+ static readonly nowUs = (): number => Time.get().nowUs();
43
+
39
44
  /**
40
45
  * Create a timer that will call callback after durationMs has passed.
41
46
  */
@@ -91,6 +96,11 @@ export class Time {
91
96
  }
92
97
  }
93
98
 
99
+ // Check if performance API is available and has the required methods. Use lower accuracy fallback if not.
100
+ if (!performance || typeof performance.now !== "function" || typeof performance.timeOrigin !== "number") {
101
+ Time.prototype.nowUs = () => Time.nowMs() * 1000; // Fallback is a bit less accurate
102
+ }
103
+
94
104
  const time = new Time();
95
105
 
96
106
  Time.startup.systemMs = Time.startup.processMs = time.nowMs();
@@ -38,6 +38,10 @@ export class DataReadQueue<T> implements Stream<T> {
38
38
  this.push(data);
39
39
  }
40
40
 
41
+ get size() {
42
+ return this.#queue.length;
43
+ }
44
+
41
45
  /**
42
46
  * Same as write but doesn't require the await required to satisfy {@link Stream#write}.
43
47
  */
@@ -7,13 +7,13 @@
7
7
  import { Bytes, Endian } from "./Bytes.js";
8
8
 
9
9
  /** Reader that auto-increments its offset after each read. */
10
- export class DataReader<E extends Endian> {
10
+ export class DataReader<E extends Endian = Endian.Big> {
11
11
  readonly #littleEndian: boolean;
12
12
  readonly #dataView: DataView;
13
13
  readonly #buffer: Uint8Array;
14
14
  #offset = 0;
15
15
 
16
- constructor(buffer: Uint8Array, endian: E) {
16
+ constructor(buffer: Uint8Array, endian?: E) {
17
17
  this.#buffer = buffer;
18
18
  this.#dataView = Bytes.dataViewOf(this.#buffer);
19
19
  this.#littleEndian = endian === Endian.Little;
@@ -9,12 +9,12 @@ import { toBigInt, toNumber } from "./Number.js";
9
9
 
10
10
  /** Writer that auto-increments its offset after each write. */
11
11
  // TODO: some research should be done to make sure this is most performant implementation.
12
- export class DataWriter<E extends Endian> {
12
+ export class DataWriter<E extends Endian = Endian.Big> {
13
13
  private readonly littleEndian: boolean;
14
14
  private length = 0;
15
15
  private readonly chunks = new Array<Uint8Array>();
16
16
 
17
- constructor(endian: E) {
17
+ constructor(endian?: E) {
18
18
  this.littleEndian = endian === Endian.Little;
19
19
  }
20
20
 
package/src/util/Ip.ts CHANGED
@@ -46,6 +46,56 @@ export function ipv6ToBytes(ip: string) {
46
46
  return Uint8Array.from(Array.from(ipv6ToArray(ip)).flatMap(value => [value >> 8, value & 0xff]));
47
47
  }
48
48
 
49
+ export function ipv6BytesToString(bytes: Uint8Array): string {
50
+ if (bytes.length !== 16) {
51
+ throw new Error("IPv6 address must be 16 bytes");
52
+ }
53
+
54
+ // Divide into 8 blocks of 2 bytes (16 bits) each
55
+ const blocks = [];
56
+ for (let i = 0; i < 16; i += 2) {
57
+ blocks.push(((bytes[i] << 8) | bytes[i + 1]).toString(16));
58
+ }
59
+
60
+ // Compression of the longest zero sequence (RFC 5952)
61
+ let bestStart = -1;
62
+ let bestLen = 0;
63
+ let currStart = -1;
64
+ let currLen = 0;
65
+ for (let i = 0; i < 8; i++) {
66
+ if (blocks[i] === "0") {
67
+ if (currStart === -1) {
68
+ currStart = i;
69
+ currLen = 1;
70
+ } else {
71
+ currLen++;
72
+ }
73
+ } else {
74
+ if (currLen > bestLen) {
75
+ bestStart = currStart;
76
+ bestLen = currLen;
77
+ }
78
+ currStart = -1;
79
+ currLen = 0;
80
+ }
81
+ }
82
+ if (currLen > bestLen) {
83
+ bestStart = currStart;
84
+ bestLen = currLen;
85
+ }
86
+ if (bestLen > 1) {
87
+ blocks.splice(bestStart, bestLen, "");
88
+ if (bestStart === 0) {
89
+ blocks.unshift("");
90
+ }
91
+ if (bestStart + bestLen === 8) {
92
+ blocks.push("");
93
+ }
94
+ }
95
+
96
+ return blocks.join(":").replace(/:{3,}/, "::").toLowerCase();
97
+ }
98
+
49
99
  export function onSameNetwork(ip1: string, ip2: string, mask: string) {
50
100
  if (isIPv4(ip1)) {
51
101
  // IPv4 addresses
@@ -0,0 +1,65 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2025 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { Observable } from "#util/Observable.js";
7
+
8
+ /**
9
+ * Set change events.
10
+ */
11
+ export interface ObservableMap<K, V> {
12
+ get added(): Observable<[key: K, newValue: V]>;
13
+ get deleted(): Observable<[key: K, oldValue: V]>;
14
+ get changed(): Observable<[key: K, newValue: V, oldValue: V]>;
15
+ }
16
+
17
+ /** Map extension to get added, deleted or changed events */
18
+ export class BasicMap<K, V> extends Map<K, V> implements ObservableMap<K, V> {
19
+ #added?: Observable<[K, V]>;
20
+ #deleted?: Observable<[K, V]>;
21
+ #changed?: Observable<[K, V, V]>;
22
+
23
+ override set(key: K, value: V): this {
24
+ const existing = this.get(key);
25
+ if (existing !== undefined) {
26
+ if (existing === value) {
27
+ // No change, do not emit events
28
+ return this;
29
+ }
30
+ this.#changed?.emit(key, value, existing);
31
+ } else {
32
+ this.#added?.emit(key, value);
33
+ }
34
+ return super.set(key, value);
35
+ }
36
+
37
+ override delete(key: K): boolean {
38
+ const existing = this.get(key);
39
+ if (existing !== undefined) {
40
+ this.#deleted?.emit(key, existing);
41
+ }
42
+ return super.delete(key);
43
+ }
44
+
45
+ get added() {
46
+ if (this.#added === undefined) {
47
+ this.#added = Observable();
48
+ }
49
+ return this.#added;
50
+ }
51
+
52
+ get deleted() {
53
+ if (this.#deleted === undefined) {
54
+ this.#deleted = Observable();
55
+ }
56
+ return this.#deleted;
57
+ }
58
+
59
+ get changed() {
60
+ if (this.#changed === undefined) {
61
+ this.#changed = Observable();
62
+ }
63
+ return this.#changed;
64
+ }
65
+ }
package/src/util/Set.ts CHANGED
@@ -177,7 +177,19 @@ export class BasicSet<T, AddT = T> implements ImmutableSet<T>, MutableSet<T, Add
177
177
  return map;
178
178
  }
179
179
 
180
- delete(item: T) {
180
+ delete(item: T): boolean;
181
+ delete<F extends keyof T>(field: keyof T, value: T[F]): boolean;
182
+ delete<F extends keyof T>(itemOrField: T | F, value?: T[F]): boolean {
183
+ let item: T | undefined;
184
+ if (value === undefined) {
185
+ item = itemOrField as T;
186
+ } else {
187
+ item = this.get(itemOrField as F, value);
188
+ if (item === undefined) {
189
+ return false; // Item not found
190
+ }
191
+ }
192
+
181
193
  if (!this.#entries.delete(item)) {
182
194
  return false;
183
195
  }
package/src/util/index.ts CHANGED
@@ -20,6 +20,7 @@ export * from "./FormattedText.js";
20
20
  export * from "./GeneratedClass.js";
21
21
  export * from "./Ip.js";
22
22
  export * from "./Lifecycle.js";
23
+ export * from "./Map.js";
23
24
  export * from "./Mutex.js";
24
25
  export * from "./NamedHandler.js";
25
26
  export * from "./Number.js";