@matter/general 0.16.0-alpha.0-20250817-1b000357c → 0.16.0-alpha.0-20250819-0a388db8b
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/cjs/codec/DnsCodec.d.ts +8 -6
- package/dist/cjs/codec/DnsCodec.d.ts.map +1 -1
- package/dist/cjs/codec/DnsCodec.js +10 -7
- package/dist/cjs/codec/DnsCodec.js.map +1 -1
- package/dist/cjs/crypto/Crypto.d.ts +32 -36
- package/dist/cjs/crypto/Crypto.d.ts.map +1 -1
- package/dist/cjs/environment/Environment.d.ts.map +1 -1
- package/dist/cjs/environment/Environment.js +2 -1
- package/dist/cjs/environment/Environment.js.map +1 -1
- package/dist/cjs/log/Diagnostic.d.ts +4 -6
- package/dist/cjs/log/Diagnostic.d.ts.map +1 -1
- package/dist/cjs/log/Diagnostic.js +6 -26
- package/dist/cjs/log/Diagnostic.js.map +1 -1
- package/dist/cjs/log/Logger.js +1 -1
- package/dist/cjs/log/Logger.js.map +1 -1
- package/dist/cjs/net/RetrySchedule.d.ts +10 -11
- package/dist/cjs/net/RetrySchedule.d.ts.map +1 -1
- package/dist/cjs/net/RetrySchedule.js +8 -7
- package/dist/cjs/net/RetrySchedule.js.map +1 -1
- package/dist/cjs/net/ServerAddress.d.ts +15 -4
- package/dist/cjs/net/ServerAddress.d.ts.map +1 -1
- package/dist/cjs/net/ServerAddress.js +33 -3
- package/dist/cjs/net/ServerAddress.js.map +2 -2
- package/dist/cjs/net/UdpMulticastServer.d.ts.map +1 -1
- package/dist/cjs/net/UdpMulticastServer.js +2 -1
- package/dist/cjs/net/UdpMulticastServer.js.map +1 -1
- package/dist/cjs/storage/StringifyTools.d.ts +2 -1
- package/dist/cjs/storage/StringifyTools.d.ts.map +1 -1
- package/dist/cjs/storage/StringifyTools.js +3 -0
- package/dist/cjs/storage/StringifyTools.js.map +1 -1
- package/dist/cjs/time/Duration.d.ts +47 -0
- package/dist/cjs/time/Duration.d.ts.map +1 -0
- package/dist/cjs/time/Duration.js +145 -0
- package/dist/cjs/time/Duration.js.map +6 -0
- package/dist/cjs/time/Time.d.ts +21 -19
- package/dist/cjs/time/Time.d.ts.map +1 -1
- package/dist/cjs/time/Time.js +44 -33
- package/dist/cjs/time/Time.js.map +1 -1
- package/dist/cjs/time/TimeUnit.d.ts +87 -0
- package/dist/cjs/time/TimeUnit.d.ts.map +1 -0
- package/dist/cjs/time/TimeUnit.js +88 -0
- package/dist/cjs/time/TimeUnit.js.map +6 -0
- package/dist/cjs/time/Timespan.d.ts +26 -0
- package/dist/cjs/time/Timespan.d.ts.map +1 -0
- package/dist/cjs/time/Timespan.js +52 -0
- package/dist/cjs/time/Timespan.js.map +6 -0
- package/dist/cjs/time/Timestamp.d.ts +47 -0
- package/dist/cjs/time/Timestamp.d.ts.map +1 -0
- package/dist/cjs/time/Timestamp.js +78 -0
- package/dist/cjs/time/Timestamp.js.map +6 -0
- package/dist/cjs/time/index.d.ts +4 -0
- package/dist/cjs/time/index.d.ts.map +1 -1
- package/dist/cjs/time/index.js +4 -0
- package/dist/cjs/time/index.js.map +1 -1
- package/dist/cjs/transaction/Status.d.ts +1 -1
- package/dist/cjs/transaction/Status.d.ts.map +1 -1
- package/dist/cjs/transaction/Status.js +2 -1
- package/dist/cjs/transaction/Status.js.map +1 -1
- package/dist/cjs/transaction/Tx.d.ts.map +1 -1
- package/dist/cjs/transaction/Tx.js +10 -8
- package/dist/cjs/transaction/Tx.js.map +1 -1
- package/dist/cjs/util/Cache.d.ts +5 -4
- package/dist/cjs/util/Cache.d.ts.map +1 -1
- package/dist/cjs/util/Cache.js +11 -11
- package/dist/cjs/util/Cache.js.map +1 -1
- package/dist/cjs/util/DataReadQueue.d.ts +2 -1
- package/dist/cjs/util/DataReadQueue.d.ts.map +1 -1
- package/dist/cjs/util/DataReadQueue.js +9 -3
- package/dist/cjs/util/DataReadQueue.js.map +1 -1
- package/dist/cjs/util/DeepEqual.d.ts +13 -1
- package/dist/cjs/util/DeepEqual.d.ts.map +1 -1
- package/dist/cjs/util/DeepEqual.js +24 -5
- package/dist/cjs/util/DeepEqual.js.map +2 -2
- package/dist/cjs/util/Observable.d.ts +4 -3
- package/dist/cjs/util/Observable.d.ts.map +1 -1
- package/dist/cjs/util/Observable.js +16 -15
- package/dist/cjs/util/Observable.js.map +1 -1
- package/dist/cjs/util/PromiseQueue.d.ts +2 -1
- package/dist/cjs/util/PromiseQueue.d.ts.map +1 -1
- package/dist/cjs/util/PromiseQueue.js +2 -1
- package/dist/cjs/util/PromiseQueue.js.map +1 -1
- package/dist/cjs/util/Promises.d.ts +3 -2
- package/dist/cjs/util/Promises.d.ts.map +1 -1
- package/dist/cjs/util/Promises.js +4 -4
- package/dist/cjs/util/Promises.js.map +1 -1
- package/dist/esm/codec/DnsCodec.d.ts +8 -6
- package/dist/esm/codec/DnsCodec.d.ts.map +1 -1
- package/dist/esm/codec/DnsCodec.js +10 -7
- package/dist/esm/codec/DnsCodec.js.map +1 -1
- package/dist/esm/crypto/Crypto.d.ts +32 -36
- package/dist/esm/crypto/Crypto.d.ts.map +1 -1
- package/dist/esm/environment/Environment.d.ts.map +1 -1
- package/dist/esm/environment/Environment.js +2 -1
- package/dist/esm/environment/Environment.js.map +1 -1
- package/dist/esm/log/Diagnostic.d.ts +4 -6
- package/dist/esm/log/Diagnostic.d.ts.map +1 -1
- package/dist/esm/log/Diagnostic.js +6 -26
- package/dist/esm/log/Diagnostic.js.map +1 -1
- package/dist/esm/log/Logger.js +1 -1
- package/dist/esm/log/Logger.js.map +1 -1
- package/dist/esm/net/RetrySchedule.d.ts +10 -11
- package/dist/esm/net/RetrySchedule.d.ts.map +1 -1
- package/dist/esm/net/RetrySchedule.js +8 -7
- package/dist/esm/net/RetrySchedule.js.map +1 -1
- package/dist/esm/net/ServerAddress.d.ts +15 -4
- package/dist/esm/net/ServerAddress.d.ts.map +1 -1
- package/dist/esm/net/ServerAddress.js +33 -3
- package/dist/esm/net/ServerAddress.js.map +2 -2
- package/dist/esm/net/UdpMulticastServer.d.ts.map +1 -1
- package/dist/esm/net/UdpMulticastServer.js +2 -1
- package/dist/esm/net/UdpMulticastServer.js.map +1 -1
- package/dist/esm/storage/StringifyTools.d.ts +2 -1
- package/dist/esm/storage/StringifyTools.d.ts.map +1 -1
- package/dist/esm/storage/StringifyTools.js +3 -0
- package/dist/esm/storage/StringifyTools.js.map +1 -1
- package/dist/esm/time/Duration.d.ts +47 -0
- package/dist/esm/time/Duration.d.ts.map +1 -0
- package/dist/esm/time/Duration.js +125 -0
- package/dist/esm/time/Duration.js.map +6 -0
- package/dist/esm/time/Time.d.ts +21 -19
- package/dist/esm/time/Time.d.ts.map +1 -1
- package/dist/esm/time/Time.js +44 -33
- package/dist/esm/time/Time.js.map +1 -1
- package/dist/esm/time/TimeUnit.d.ts +87 -0
- package/dist/esm/time/TimeUnit.d.ts.map +1 -0
- package/dist/esm/time/TimeUnit.js +68 -0
- package/dist/esm/time/TimeUnit.js.map +6 -0
- package/dist/esm/time/Timespan.d.ts +26 -0
- package/dist/esm/time/Timespan.d.ts.map +1 -0
- package/dist/esm/time/Timespan.js +32 -0
- package/dist/esm/time/Timespan.js.map +6 -0
- package/dist/esm/time/Timestamp.d.ts +47 -0
- package/dist/esm/time/Timestamp.d.ts.map +1 -0
- package/dist/esm/time/Timestamp.js +58 -0
- package/dist/esm/time/Timestamp.js.map +6 -0
- package/dist/esm/time/index.d.ts +4 -0
- package/dist/esm/time/index.d.ts.map +1 -1
- package/dist/esm/time/index.js +4 -0
- package/dist/esm/time/index.js.map +1 -1
- package/dist/esm/transaction/Status.d.ts +1 -1
- package/dist/esm/transaction/Status.d.ts.map +1 -1
- package/dist/esm/transaction/Status.js +2 -1
- package/dist/esm/transaction/Status.js.map +1 -1
- package/dist/esm/transaction/Tx.d.ts.map +1 -1
- package/dist/esm/transaction/Tx.js +10 -8
- package/dist/esm/transaction/Tx.js.map +1 -1
- package/dist/esm/util/Cache.d.ts +5 -4
- package/dist/esm/util/Cache.d.ts.map +1 -1
- package/dist/esm/util/Cache.js +11 -11
- package/dist/esm/util/Cache.js.map +1 -1
- package/dist/esm/util/DataReadQueue.d.ts +2 -1
- package/dist/esm/util/DataReadQueue.d.ts.map +1 -1
- package/dist/esm/util/DataReadQueue.js +9 -3
- package/dist/esm/util/DataReadQueue.js.map +1 -1
- package/dist/esm/util/DeepEqual.d.ts +13 -1
- package/dist/esm/util/DeepEqual.d.ts.map +1 -1
- package/dist/esm/util/DeepEqual.js +24 -5
- package/dist/esm/util/DeepEqual.js.map +2 -2
- package/dist/esm/util/Observable.d.ts +4 -3
- package/dist/esm/util/Observable.d.ts.map +1 -1
- package/dist/esm/util/Observable.js +16 -15
- package/dist/esm/util/Observable.js.map +1 -1
- package/dist/esm/util/PromiseQueue.d.ts +2 -1
- package/dist/esm/util/PromiseQueue.d.ts.map +1 -1
- package/dist/esm/util/PromiseQueue.js +2 -1
- package/dist/esm/util/PromiseQueue.js.map +1 -1
- package/dist/esm/util/Promises.d.ts +3 -2
- package/dist/esm/util/Promises.d.ts.map +1 -1
- package/dist/esm/util/Promises.js +4 -4
- package/dist/esm/util/Promises.js.map +1 -1
- package/package.json +3 -3
- package/src/codec/DnsCodec.ts +27 -8
- package/src/environment/Environment.ts +2 -1
- package/src/log/Diagnostic.ts +9 -37
- package/src/log/Logger.ts +1 -1
- package/src/net/RetrySchedule.ts +14 -14
- package/src/net/ServerAddress.ts +44 -5
- package/src/net/UdpMulticastServer.ts +2 -1
- package/src/storage/StringifyTools.ts +5 -0
- package/src/time/Duration.ts +181 -0
- package/src/time/Time.ts +50 -39
- package/src/time/TimeUnit.ts +159 -0
- package/src/time/Timespan.ts +52 -0
- package/src/time/Timestamp.ts +94 -0
- package/src/time/index.ts +4 -0
- package/src/transaction/Status.ts +2 -1
- package/src/transaction/Tx.ts +9 -7
- package/src/util/Cache.ts +11 -10
- package/src/util/DataReadQueue.ts +9 -3
- package/src/util/DeepEqual.ts +38 -13
- package/src/util/Observable.ts +19 -17
- package/src/util/PromiseQueue.ts +4 -2
- package/src/util/Promises.ts +6 -5
package/src/net/ServerAddress.ts
CHANGED
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { Diagnostic } from "#log/Diagnostic.js";
|
|
8
|
+
import { Duration } from "#time/Duration.js";
|
|
9
|
+
import { Timestamp } from "#time/Timestamp.js";
|
|
10
|
+
import { Seconds } from "#time/TimeUnit.js";
|
|
11
|
+
|
|
7
12
|
export type ServerAddressIp = {
|
|
8
13
|
type: "udp";
|
|
9
14
|
ip: string;
|
|
@@ -17,14 +22,48 @@ export type ServerAddressBle = {
|
|
|
17
22
|
|
|
18
23
|
export interface Lifespan {
|
|
19
24
|
/** Beginning of lifespan (system time in milliseconds) */
|
|
20
|
-
discoveredAt:
|
|
25
|
+
discoveredAt: Timestamp;
|
|
21
26
|
|
|
22
|
-
/** Length of lifespan, if known (
|
|
23
|
-
ttl:
|
|
27
|
+
/** Length of lifespan, if known (seconds) */
|
|
28
|
+
ttl: Duration;
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
export type ServerAddress = (ServerAddressIp | ServerAddressBle) & Partial<Lifespan>;
|
|
27
32
|
|
|
28
|
-
export function
|
|
29
|
-
return
|
|
33
|
+
export function ServerAddress(definition: ServerAddress.Definition) {
|
|
34
|
+
return {
|
|
35
|
+
discoveredAt: undefined,
|
|
36
|
+
...definition,
|
|
37
|
+
ttl: Seconds(definition.ttl),
|
|
38
|
+
} as ServerAddress;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export namespace ServerAddress {
|
|
42
|
+
export function urlFor(address: ServerAddress): string {
|
|
43
|
+
return address.type === "udp" ? `udp://[${address.ip}]:${address.port}` : `ble://${address.peripheralAddress}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function diagnosticFor(address: ServerAddress) {
|
|
47
|
+
const diagnostic = Array<unknown>();
|
|
48
|
+
|
|
49
|
+
if (address.type === "udp") {
|
|
50
|
+
diagnostic.push("udp://", Diagnostic.strong(address.ip), ":", address.port);
|
|
51
|
+
} else {
|
|
52
|
+
diagnostic.push("ble://", Diagnostic.strong(address.peripheralAddress));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if ("ttl" in address && typeof address.ttl === "number") {
|
|
56
|
+
diagnostic.push(" ttl ", Duration.format(address.ttl));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return Diagnostic.squash(...diagnostic);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function definitionOf(address: ServerAddress): Definition {
|
|
63
|
+
return address;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface Definition extends Omit<ServerAddress, "ttl"> {
|
|
67
|
+
ttl?: Duration;
|
|
68
|
+
}
|
|
30
69
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { MatterAggregateError } from "#MatterError.js";
|
|
8
|
+
import { Minutes } from "#time/TimeUnit.js";
|
|
8
9
|
import { Bytes } from "#util/Bytes.js";
|
|
9
10
|
import { Logger } from "../log/Logger.js";
|
|
10
11
|
import { Cache } from "../util/Cache.js";
|
|
@@ -72,7 +73,7 @@ export class UdpMulticastServer {
|
|
|
72
73
|
private readonly broadcastChannels = new Cache<Promise<UdpChannel>>(
|
|
73
74
|
"UDP broadcast channel",
|
|
74
75
|
(netInterface, iPv4) => this.createBroadcastChannel(netInterface, iPv4),
|
|
75
|
-
5
|
|
76
|
+
Minutes(5),
|
|
76
77
|
async (_netInterface, channel) => (await channel).close(),
|
|
77
78
|
);
|
|
78
79
|
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { Duration } from "#time/Duration.js";
|
|
8
|
+
import { Millis } from "#time/TimeUnit.js";
|
|
7
9
|
import { UnexpectedDataError } from "../MatterError.js";
|
|
8
10
|
import { Bytes } from "../util/Bytes.js";
|
|
9
11
|
import { isObject } from "../util/Type.js";
|
|
@@ -17,6 +19,7 @@ type SupportedComplexStorageTypes =
|
|
|
17
19
|
| { [key: string]: SupportedStorageBaseTypes | SupportedComplexStorageTypes | null | undefined } // Objects
|
|
18
20
|
| Array<[SupportedStorageBaseTypes, SupportedStorageBaseTypes | SupportedComplexStorageTypes | null | undefined]> // Map style arrays
|
|
19
21
|
| Map<SupportedStorageBaseTypes, SupportedStorageBaseTypes | SupportedComplexStorageTypes>
|
|
22
|
+
| Duration
|
|
20
23
|
| null
|
|
21
24
|
| undefined; // Maps
|
|
22
25
|
|
|
@@ -77,6 +80,8 @@ export function fromJson(json: string): SupportedStorageTypes {
|
|
|
77
80
|
SupportedStorageBaseTypes,
|
|
78
81
|
][],
|
|
79
82
|
);
|
|
83
|
+
case "Interval":
|
|
84
|
+
return Millis(data);
|
|
80
85
|
|
|
81
86
|
// TODO Remove in the future, leave here for now for backward compatibility?
|
|
82
87
|
case "AttributeId":
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { UnexpectedDataError } from "#MatterError.js";
|
|
8
|
+
import { Branded } from "#util/Type.js";
|
|
9
|
+
import type { Millis, Seconds, TimeUnit } from "./TimeUnit.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A time interval.
|
|
13
|
+
*
|
|
14
|
+
* You can create an interval using a {@link TimeUnit} factory such as {@link Seconds}.
|
|
15
|
+
*
|
|
16
|
+
* Regardless of the input unit, intervals are stored as milliseconds. You can use {@link TimeUnit#of} to convert an
|
|
17
|
+
* interval to the correct unit.
|
|
18
|
+
*
|
|
19
|
+
* Math operators always result in millisecond values and can thus be converted back to an interval using
|
|
20
|
+
* {@link Millis}. For example, `Millisecs(Hours(1) + Minutes(30))` would produce a 90 minute {@link Duration}.
|
|
21
|
+
*/
|
|
22
|
+
export type Duration = Branded<number, "Interval"> | 0;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Create an interval from a number or string.
|
|
26
|
+
*/
|
|
27
|
+
export function Duration<T extends Duration | string>(source: T): Duration {
|
|
28
|
+
if (typeof source === "string") {
|
|
29
|
+
return Duration.parse(source);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (typeof source === "number") {
|
|
33
|
+
if (Number.isNaN(source)) {
|
|
34
|
+
throw new DurationFormatError(`A duration may not be NaN`);
|
|
35
|
+
}
|
|
36
|
+
return source;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
throw new DurationFormatError(`Interval value is not a number (received ${typeof source})`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Thrown when a textual duration cannot be parsed.
|
|
44
|
+
*/
|
|
45
|
+
export class DurationFormatError extends UnexpectedDataError {}
|
|
46
|
+
|
|
47
|
+
export namespace Duration {
|
|
48
|
+
/**
|
|
49
|
+
* Determine the greater of two intervals.
|
|
50
|
+
*/
|
|
51
|
+
export function max(a: Duration, b: Duration) {
|
|
52
|
+
if (b > a) {
|
|
53
|
+
return b;
|
|
54
|
+
}
|
|
55
|
+
return a;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Determine the lesser of two intervals.
|
|
60
|
+
*/
|
|
61
|
+
export function min(a: Duration, b: Duration) {
|
|
62
|
+
if (b < a) {
|
|
63
|
+
return b;
|
|
64
|
+
}
|
|
65
|
+
return a;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Convert an interval to a compact human readable string.
|
|
70
|
+
*/
|
|
71
|
+
export function format<T extends Duration | undefined>(
|
|
72
|
+
duration: T,
|
|
73
|
+
): T extends undefined ? string | undefined : string {
|
|
74
|
+
let ms = duration as number;
|
|
75
|
+
|
|
76
|
+
if (typeof ms !== "number" || Number.isNaN(ms)) {
|
|
77
|
+
return "invalid";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
switch (ms) {
|
|
81
|
+
case 0:
|
|
82
|
+
return "0";
|
|
83
|
+
|
|
84
|
+
case Infinity:
|
|
85
|
+
return "forever";
|
|
86
|
+
|
|
87
|
+
case -Infinity:
|
|
88
|
+
return "until now"; // Umm... I guess?
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (ms < 0) {
|
|
92
|
+
return `${toPrecision(ms * 1000, 3)}μs`;
|
|
93
|
+
} else if (ms < 1000) {
|
|
94
|
+
return `${toPrecision(ms, 3)}ms`;
|
|
95
|
+
} else if (ms < 60000) {
|
|
96
|
+
return `${toPrecision(ms / 1000, 3)}s`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const parts = Array<string>();
|
|
100
|
+
|
|
101
|
+
if (ms > 86_400_000) {
|
|
102
|
+
parts.push(`${Math.floor(ms / 86_400_000)}d`);
|
|
103
|
+
ms %= 86_400_000;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const hours = Math.floor(ms / 3_600_000);
|
|
107
|
+
if (hours) {
|
|
108
|
+
parts.push(`${hours}h`);
|
|
109
|
+
}
|
|
110
|
+
ms %= 3_600_000;
|
|
111
|
+
|
|
112
|
+
const minutes = Math.floor(ms / 60_000);
|
|
113
|
+
if (minutes) {
|
|
114
|
+
parts.push(`${minutes}m`);
|
|
115
|
+
}
|
|
116
|
+
ms %= 60_000;
|
|
117
|
+
|
|
118
|
+
const seconds = Math.floor(ms / 1_000);
|
|
119
|
+
if (seconds) {
|
|
120
|
+
parts.push(`${seconds}s`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return parts.join(" ");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Parse a string into an interval.
|
|
128
|
+
*/
|
|
129
|
+
export function parse(text: string) {
|
|
130
|
+
const parts = text.split(/\s+/).filter(part => part !== "");
|
|
131
|
+
|
|
132
|
+
let interval = 0;
|
|
133
|
+
for (const part of parts) {
|
|
134
|
+
const suffix = text.match(/[a-zμ]+/i)?.[1];
|
|
135
|
+
if (suffix === undefined) {
|
|
136
|
+
throw new DurationFormatError(`Interval component "${part}" is missing an time suffix`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const value = Number(text.slice(text.length - suffix.length));
|
|
140
|
+
if (Number.isNaN(value)) {
|
|
141
|
+
throw new DurationFormatError(`Interval component "${part}" contains no numeric component`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
switch (suffix.toLowerCase()) {
|
|
145
|
+
case "μs":
|
|
146
|
+
case "us":
|
|
147
|
+
interval += value / 1000;
|
|
148
|
+
break;
|
|
149
|
+
|
|
150
|
+
case "ms":
|
|
151
|
+
interval += value;
|
|
152
|
+
break;
|
|
153
|
+
|
|
154
|
+
case "s":
|
|
155
|
+
interval += value * 1000;
|
|
156
|
+
break;
|
|
157
|
+
|
|
158
|
+
case "m":
|
|
159
|
+
interval += value * 60_000;
|
|
160
|
+
break;
|
|
161
|
+
|
|
162
|
+
case "h":
|
|
163
|
+
interval += value * 3_600_000;
|
|
164
|
+
break;
|
|
165
|
+
|
|
166
|
+
case "d":
|
|
167
|
+
interval += value * 86_400_000;
|
|
168
|
+
break;
|
|
169
|
+
|
|
170
|
+
default:
|
|
171
|
+
throw new DurationFormatError(`Interval component ${part} contains an unsupported unit suffix`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return interval as Duration;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function toPrecision(number: number, precision: number) {
|
|
180
|
+
return number.toPrecision(precision).replace(/\.?0+/, "");
|
|
181
|
+
}
|
package/src/time/Time.ts
CHANGED
|
@@ -9,6 +9,9 @@ import { CancelablePromise } from "#util/Cancelable.js";
|
|
|
9
9
|
import { ImplementationError } from "../MatterError.js";
|
|
10
10
|
import { Diagnostic } from "../log/Diagnostic.js";
|
|
11
11
|
import { DiagnosticSource } from "../log/DiagnosticSource.js";
|
|
12
|
+
import { Duration } from "./Duration.js";
|
|
13
|
+
import { Instant } from "./TimeUnit.js";
|
|
14
|
+
import type { Timestamp } from "./Timestamp.js";
|
|
12
15
|
|
|
13
16
|
const registry = new Set<Timer>();
|
|
14
17
|
|
|
@@ -19,56 +22,62 @@ const registry = new Set<Timer>();
|
|
|
19
22
|
* environment.
|
|
20
23
|
*/
|
|
21
24
|
export class Time {
|
|
22
|
-
static
|
|
25
|
+
static default: Time;
|
|
23
26
|
|
|
24
27
|
static startup = {
|
|
25
|
-
systemMs: 0,
|
|
26
|
-
processMs: 0,
|
|
28
|
+
systemMs: 0 as Timestamp,
|
|
29
|
+
processMs: 0 as Timestamp,
|
|
27
30
|
};
|
|
28
31
|
|
|
29
|
-
now() {
|
|
32
|
+
get now() {
|
|
30
33
|
return new Date();
|
|
31
34
|
}
|
|
32
|
-
static
|
|
35
|
+
static get now() {
|
|
36
|
+
return Time.default.now;
|
|
37
|
+
}
|
|
33
38
|
|
|
34
|
-
nowMs() {
|
|
39
|
+
get nowMs() {
|
|
35
40
|
return Date.now();
|
|
36
41
|
}
|
|
37
|
-
static
|
|
42
|
+
static get nowMs() {
|
|
43
|
+
return Time.default.nowMs as Timestamp;
|
|
44
|
+
}
|
|
38
45
|
|
|
39
|
-
nowUs() {
|
|
40
|
-
return Math.floor(performance.now() + performance.timeOrigin)
|
|
46
|
+
get nowUs() {
|
|
47
|
+
return Math.floor(performance.now() + performance.timeOrigin) as Timestamp;
|
|
48
|
+
}
|
|
49
|
+
static get nowUs() {
|
|
50
|
+
return Time.default.nowUs;
|
|
41
51
|
}
|
|
42
|
-
static readonly nowUs = (): number => Time.get().nowUs();
|
|
43
52
|
|
|
44
53
|
/**
|
|
45
54
|
* Create a timer that will call callback after durationMs has passed.
|
|
46
55
|
*/
|
|
47
|
-
getTimer(name: string,
|
|
48
|
-
return new StandardTimer(name,
|
|
56
|
+
getTimer(name: string, duration: Duration, callback: Timer.Callback): Timer {
|
|
57
|
+
return new StandardTimer(name, duration, callback, false);
|
|
49
58
|
}
|
|
50
|
-
static readonly getTimer = (name: string,
|
|
51
|
-
Time.
|
|
59
|
+
static readonly getTimer = (name: string, duration: Duration, callback: Timer.Callback): Timer =>
|
|
60
|
+
Time.default.getTimer(name, duration, callback);
|
|
52
61
|
|
|
53
62
|
/**
|
|
54
63
|
* Create a timer that will periodically call callback at intervalMs intervals.
|
|
55
64
|
*/
|
|
56
|
-
getPeriodicTimer(name: string,
|
|
57
|
-
return new StandardTimer(name,
|
|
65
|
+
getPeriodicTimer(name: string, duration: Duration, callback: Timer.Callback): Timer {
|
|
66
|
+
return new StandardTimer(name, duration, callback, true);
|
|
58
67
|
}
|
|
59
|
-
static readonly getPeriodicTimer = (name: string,
|
|
60
|
-
Time.
|
|
68
|
+
static readonly getPeriodicTimer = (name: string, duration: Duration, callback: Timer.Callback): Timer =>
|
|
69
|
+
Time.default.getPeriodicTimer(name, duration, callback);
|
|
61
70
|
|
|
62
71
|
/**
|
|
63
72
|
* Create a promise that resolves after a specific interval or when canceled, whichever comes first.
|
|
64
73
|
*/
|
|
65
|
-
sleep(name: string,
|
|
74
|
+
sleep(name: string, duration: Duration): CancelablePromise {
|
|
66
75
|
let timer: Timer;
|
|
67
76
|
let resolver: () => void;
|
|
68
77
|
return new CancelablePromise(
|
|
69
78
|
resolve => {
|
|
70
79
|
resolver = resolve;
|
|
71
|
-
timer = Time.getTimer(name,
|
|
80
|
+
timer = Time.getTimer(name, duration, resolve);
|
|
72
81
|
timer.start();
|
|
73
82
|
},
|
|
74
83
|
|
|
@@ -78,8 +87,8 @@ export class Time {
|
|
|
78
87
|
},
|
|
79
88
|
);
|
|
80
89
|
}
|
|
81
|
-
static sleep(name: string,
|
|
82
|
-
return Time.
|
|
90
|
+
static sleep(name: string, duration: Duration) {
|
|
91
|
+
return Time.default.sleep(name, duration);
|
|
83
92
|
}
|
|
84
93
|
|
|
85
94
|
static register(timer: Timer) {
|
|
@@ -98,7 +107,11 @@ export class Time {
|
|
|
98
107
|
|
|
99
108
|
// Check if performance API is available and has the required methods. Use lower accuracy fallback if not.
|
|
100
109
|
if (!performance || typeof performance.now !== "function" || typeof performance.timeOrigin !== "number") {
|
|
101
|
-
Time.prototype.nowUs
|
|
110
|
+
Object.defineProperty(Time.prototype.nowUs, "nowUs", {
|
|
111
|
+
get() {
|
|
112
|
+
return Time.nowMs; // Fallback is a bit less accurate
|
|
113
|
+
},
|
|
114
|
+
});
|
|
102
115
|
}
|
|
103
116
|
|
|
104
117
|
export interface Timer {
|
|
@@ -112,7 +125,7 @@ export interface Timer {
|
|
|
112
125
|
systemId: unknown;
|
|
113
126
|
|
|
114
127
|
/** Interval (diagnostics) */
|
|
115
|
-
|
|
128
|
+
interval: Duration;
|
|
116
129
|
|
|
117
130
|
/** Is the timer periodic? (diagnostics) */
|
|
118
131
|
isPeriodic: boolean;
|
|
@@ -137,7 +150,7 @@ export namespace Timer {
|
|
|
137
150
|
export class StandardTimer implements Timer {
|
|
138
151
|
#timerId: unknown;
|
|
139
152
|
#utility = false;
|
|
140
|
-
#
|
|
153
|
+
#interval = Instant; // Real value installed in constructor
|
|
141
154
|
isRunning = false;
|
|
142
155
|
|
|
143
156
|
get systemId() {
|
|
@@ -146,11 +159,11 @@ export class StandardTimer implements Timer {
|
|
|
146
159
|
|
|
147
160
|
constructor(
|
|
148
161
|
readonly name: string,
|
|
149
|
-
|
|
162
|
+
duration: Duration,
|
|
150
163
|
private readonly callback: Timer.Callback,
|
|
151
164
|
readonly isPeriodic: boolean,
|
|
152
165
|
) {
|
|
153
|
-
this.
|
|
166
|
+
this.interval = duration;
|
|
154
167
|
}
|
|
155
168
|
|
|
156
169
|
/**
|
|
@@ -158,17 +171,17 @@ export class StandardTimer implements Timer {
|
|
|
158
171
|
*
|
|
159
172
|
* You can change this value but changes have no effect until the timer restarts.
|
|
160
173
|
*/
|
|
161
|
-
set
|
|
162
|
-
if (
|
|
174
|
+
set interval(interval: Duration) {
|
|
175
|
+
if (interval < 0 || interval > 2147483647) {
|
|
163
176
|
throw new ImplementationError(
|
|
164
|
-
`Invalid intervalMs: ${
|
|
177
|
+
`Invalid intervalMs: ${interval}. The value must be between 0 and 32-bit maximum value (2147483647)`,
|
|
165
178
|
);
|
|
166
179
|
}
|
|
167
|
-
this.#
|
|
180
|
+
this.#interval = interval;
|
|
168
181
|
}
|
|
169
182
|
|
|
170
|
-
get
|
|
171
|
-
return this.#
|
|
183
|
+
get interval() {
|
|
184
|
+
return this.#interval;
|
|
172
185
|
}
|
|
173
186
|
|
|
174
187
|
get utility() {
|
|
@@ -203,7 +216,7 @@ export class StandardTimer implements Timer {
|
|
|
203
216
|
this.isRunning = false;
|
|
204
217
|
}
|
|
205
218
|
this.callback();
|
|
206
|
-
}, this.
|
|
219
|
+
}, this.interval);
|
|
207
220
|
return this;
|
|
208
221
|
}
|
|
209
222
|
|
|
@@ -222,7 +235,7 @@ DiagnosticSource.add({
|
|
|
222
235
|
timer.name,
|
|
223
236
|
Diagnostic.dict({
|
|
224
237
|
periodic: timer.isPeriodic,
|
|
225
|
-
interval:
|
|
238
|
+
interval: timer.interval,
|
|
226
239
|
system: timer.systemId,
|
|
227
240
|
elapsed: timer.elapsed,
|
|
228
241
|
}),
|
|
@@ -232,11 +245,9 @@ DiagnosticSource.add({
|
|
|
232
245
|
});
|
|
233
246
|
|
|
234
247
|
Boot.init(() => {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
Time.startup.systemMs = Time.startup.processMs = time.nowMs();
|
|
248
|
+
Time.default = new Time();
|
|
238
249
|
|
|
239
|
-
Time.
|
|
250
|
+
Time.startup.systemMs = Time.startup.processMs = Time.nowMs;
|
|
240
251
|
|
|
241
252
|
// Hook for testing frameworks
|
|
242
253
|
if (typeof MatterHooks !== "undefined") {
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Duration } from "./Duration.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Details of a specific unit of time.
|
|
11
|
+
*/
|
|
12
|
+
export interface TimeUnit {
|
|
13
|
+
(scale: number | bigint): Duration;
|
|
14
|
+
(scale: undefined | number | bigint): undefined | Duration;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Long name of the unit.
|
|
18
|
+
*/
|
|
19
|
+
readonly kind: TimeUnit.Kind;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Abbreviated name of the unit.
|
|
23
|
+
*/
|
|
24
|
+
readonly abbrev: string;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* An interval representing a single unit.
|
|
28
|
+
*/
|
|
29
|
+
readonly one: Duration;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Convert an interval to an integer of this unit.
|
|
33
|
+
*
|
|
34
|
+
* Produces an even integer result. Use {@link fractionalOf} to retain any fractional component.
|
|
35
|
+
*/
|
|
36
|
+
of<T extends Duration | undefined>(interval: T): T extends undefined ? number | undefined : number;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Convert an interval to this unit, retaining fractional component.
|
|
40
|
+
*/
|
|
41
|
+
fractionalOf<T extends Duration | undefined>(interval: T): T extends undefined ? number | undefined : number;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Compute the ceiling of an interval in this unit.
|
|
45
|
+
*/
|
|
46
|
+
ceil(duration: Duration): Duration;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Compute the floor of an interval in this unit.
|
|
50
|
+
*/
|
|
51
|
+
floor(duration: Duration): Duration;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Round an interval to this unit.
|
|
55
|
+
*/
|
|
56
|
+
round(duration: Duration): Duration;
|
|
57
|
+
|
|
58
|
+
length: never;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export namespace TimeUnit {
|
|
62
|
+
/**
|
|
63
|
+
* Standard time units.
|
|
64
|
+
*/
|
|
65
|
+
export type Kind = "microsecond" | "millisecond" | "second" | "minute" | "hour" | "day";
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Implement a {@link TimeUnit}.
|
|
70
|
+
*/
|
|
71
|
+
export function TimeUnit<T = {}>(kind: TimeUnit.Kind, abbrev: string, one: number, props = {} as T): TimeUnit & T {
|
|
72
|
+
const unit = {
|
|
73
|
+
[kind]: (scale: undefined | number | bigint) => {
|
|
74
|
+
if (scale === undefined) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
if (typeof scale === "bigint") {
|
|
78
|
+
scale = Number(scale);
|
|
79
|
+
}
|
|
80
|
+
return (scale * one) as Duration;
|
|
81
|
+
},
|
|
82
|
+
}[kind] as TimeUnit & T;
|
|
83
|
+
|
|
84
|
+
// Add properties to the function
|
|
85
|
+
Object.assign(unit, {
|
|
86
|
+
...props,
|
|
87
|
+
kind,
|
|
88
|
+
abbrev,
|
|
89
|
+
one,
|
|
90
|
+
of,
|
|
91
|
+
fractionalOf,
|
|
92
|
+
ceil,
|
|
93
|
+
floor,
|
|
94
|
+
round,
|
|
95
|
+
toString: kindOf,
|
|
96
|
+
[Symbol.for("nodejs.util.inspect.custom")]: kindOf,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return unit;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function of(this: TimeUnit, duration: Duration) {
|
|
103
|
+
return Math.floor(duration / this.one);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function fractionalOf(this: TimeUnit, duration: Duration) {
|
|
107
|
+
return duration / this.one;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function ceil(this: TimeUnit, duration: Duration) {
|
|
111
|
+
return Math.ceil(duration / this.one) * this.one;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function floor(this: TimeUnit, duration: Duration) {
|
|
115
|
+
return Math.floor(duration / this.one) * this.one;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function round(this: TimeUnit, duration: Duration) {
|
|
119
|
+
return Math.round(duration / this.one) * this.one;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function kindOf(this: TimeUnit) {
|
|
123
|
+
return this.kind;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Create an interval in microseconds.
|
|
128
|
+
*/
|
|
129
|
+
export const Microseconds = TimeUnit("microsecond", "μs", 0.001);
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Create an interval in milliseconds.
|
|
133
|
+
*/
|
|
134
|
+
export const Millis = TimeUnit("millisecond", "ms", 1);
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Create an interval in seconds.
|
|
138
|
+
*/
|
|
139
|
+
export const Seconds = TimeUnit("second", "s", 1_000);
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Create an interval in minutes.
|
|
143
|
+
*/
|
|
144
|
+
export const Minutes = TimeUnit("minute", "m", 60_000);
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Create an interval in hours.
|
|
148
|
+
*/
|
|
149
|
+
export const Hours = TimeUnit("hour", "h", 3_600_000);
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Create an interval in days.
|
|
153
|
+
*/
|
|
154
|
+
export const Days = TimeUnit("day", "d", 86_400_000);
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* A zero-length interval.
|
|
158
|
+
*/
|
|
159
|
+
export const Instant = Millis(0);
|