@matter/general 0.16.0-alpha.0-20250816-d22ad240d → 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.
Files changed (237) hide show
  1. package/dist/cjs/codec/DnsCodec.d.ts +8 -6
  2. package/dist/cjs/codec/DnsCodec.d.ts.map +1 -1
  3. package/dist/cjs/codec/DnsCodec.js +10 -7
  4. package/dist/cjs/codec/DnsCodec.js.map +1 -1
  5. package/dist/cjs/crypto/Crypto.d.ts +32 -36
  6. package/dist/cjs/crypto/Crypto.d.ts.map +1 -1
  7. package/dist/cjs/environment/Environment.d.ts.map +1 -1
  8. package/dist/cjs/environment/Environment.js +2 -1
  9. package/dist/cjs/environment/Environment.js.map +1 -1
  10. package/dist/cjs/log/Diagnostic.d.ts +4 -6
  11. package/dist/cjs/log/Diagnostic.d.ts.map +1 -1
  12. package/dist/cjs/log/Diagnostic.js +6 -26
  13. package/dist/cjs/log/Diagnostic.js.map +1 -1
  14. package/dist/cjs/log/Logger.js +1 -1
  15. package/dist/cjs/log/Logger.js.map +1 -1
  16. package/dist/cjs/net/RetrySchedule.d.ts +10 -11
  17. package/dist/cjs/net/RetrySchedule.d.ts.map +1 -1
  18. package/dist/cjs/net/RetrySchedule.js +8 -7
  19. package/dist/cjs/net/RetrySchedule.js.map +1 -1
  20. package/dist/cjs/net/ServerAddress.d.ts +15 -4
  21. package/dist/cjs/net/ServerAddress.d.ts.map +1 -1
  22. package/dist/cjs/net/ServerAddress.js +33 -3
  23. package/dist/cjs/net/ServerAddress.js.map +2 -2
  24. package/dist/cjs/net/UdpMulticastServer.d.ts.map +1 -1
  25. package/dist/cjs/net/UdpMulticastServer.js +2 -1
  26. package/dist/cjs/net/UdpMulticastServer.js.map +1 -1
  27. package/dist/cjs/net/mock/MockRouter.d.ts +2 -1
  28. package/dist/cjs/net/mock/MockRouter.d.ts.map +1 -1
  29. package/dist/cjs/net/mock/MockRouter.js.map +1 -1
  30. package/dist/cjs/net/mock/MockUdpChannel.d.ts +2 -1
  31. package/dist/cjs/net/mock/MockUdpChannel.d.ts.map +1 -1
  32. package/dist/cjs/net/mock/MockUdpChannel.js.map +1 -1
  33. package/dist/cjs/net/mock/NetworkSimulator.d.ts +2 -1
  34. package/dist/cjs/net/mock/NetworkSimulator.d.ts.map +1 -1
  35. package/dist/cjs/net/mock/NetworkSimulator.js.map +1 -1
  36. package/dist/cjs/storage/Storage.d.ts +2 -1
  37. package/dist/cjs/storage/Storage.d.ts.map +1 -1
  38. package/dist/cjs/storage/Storage.js.map +1 -1
  39. package/dist/cjs/storage/StorageBackendMemory.d.ts +2 -1
  40. package/dist/cjs/storage/StorageBackendMemory.d.ts.map +1 -1
  41. package/dist/cjs/storage/StorageBackendMemory.js +1 -1
  42. package/dist/cjs/storage/StorageBackendMemory.js.map +1 -1
  43. package/dist/cjs/storage/StorageContext.d.ts +2 -1
  44. package/dist/cjs/storage/StorageContext.d.ts.map +1 -1
  45. package/dist/cjs/storage/StorageContext.js.map +1 -1
  46. package/dist/cjs/storage/StringifyTools.d.ts +2 -1
  47. package/dist/cjs/storage/StringifyTools.d.ts.map +1 -1
  48. package/dist/cjs/storage/StringifyTools.js +3 -0
  49. package/dist/cjs/storage/StringifyTools.js.map +1 -1
  50. package/dist/cjs/time/Duration.d.ts +47 -0
  51. package/dist/cjs/time/Duration.d.ts.map +1 -0
  52. package/dist/cjs/time/Duration.js +145 -0
  53. package/dist/cjs/time/Duration.js.map +6 -0
  54. package/dist/cjs/time/Time.d.ts +21 -19
  55. package/dist/cjs/time/Time.d.ts.map +1 -1
  56. package/dist/cjs/time/Time.js +44 -33
  57. package/dist/cjs/time/Time.js.map +1 -1
  58. package/dist/cjs/time/TimeUnit.d.ts +87 -0
  59. package/dist/cjs/time/TimeUnit.d.ts.map +1 -0
  60. package/dist/cjs/time/TimeUnit.js +88 -0
  61. package/dist/cjs/time/TimeUnit.js.map +6 -0
  62. package/dist/cjs/time/Timespan.d.ts +26 -0
  63. package/dist/cjs/time/Timespan.d.ts.map +1 -0
  64. package/dist/cjs/time/Timespan.js +52 -0
  65. package/dist/cjs/time/Timespan.js.map +6 -0
  66. package/dist/cjs/time/Timestamp.d.ts +47 -0
  67. package/dist/cjs/time/Timestamp.d.ts.map +1 -0
  68. package/dist/cjs/time/Timestamp.js +78 -0
  69. package/dist/cjs/time/Timestamp.js.map +6 -0
  70. package/dist/cjs/time/index.d.ts +4 -0
  71. package/dist/cjs/time/index.d.ts.map +1 -1
  72. package/dist/cjs/time/index.js +4 -0
  73. package/dist/cjs/time/index.js.map +1 -1
  74. package/dist/cjs/transaction/Status.d.ts +1 -1
  75. package/dist/cjs/transaction/Status.d.ts.map +1 -1
  76. package/dist/cjs/transaction/Status.js +2 -1
  77. package/dist/cjs/transaction/Status.js.map +1 -1
  78. package/dist/cjs/transaction/Tx.d.ts.map +1 -1
  79. package/dist/cjs/transaction/Tx.js +10 -8
  80. package/dist/cjs/transaction/Tx.js.map +1 -1
  81. package/dist/cjs/util/Cache.d.ts +5 -4
  82. package/dist/cjs/util/Cache.d.ts.map +1 -1
  83. package/dist/cjs/util/Cache.js +11 -11
  84. package/dist/cjs/util/Cache.js.map +1 -1
  85. package/dist/cjs/util/DataReadQueue.d.ts +2 -1
  86. package/dist/cjs/util/DataReadQueue.d.ts.map +1 -1
  87. package/dist/cjs/util/DataReadQueue.js +9 -3
  88. package/dist/cjs/util/DataReadQueue.js.map +1 -1
  89. package/dist/cjs/util/DeepEqual.d.ts +13 -1
  90. package/dist/cjs/util/DeepEqual.d.ts.map +1 -1
  91. package/dist/cjs/util/DeepEqual.js +24 -5
  92. package/dist/cjs/util/DeepEqual.js.map +2 -2
  93. package/dist/cjs/util/Observable.d.ts +4 -3
  94. package/dist/cjs/util/Observable.d.ts.map +1 -1
  95. package/dist/cjs/util/Observable.js +16 -15
  96. package/dist/cjs/util/Observable.js.map +1 -1
  97. package/dist/cjs/util/PromiseQueue.d.ts +2 -1
  98. package/dist/cjs/util/PromiseQueue.d.ts.map +1 -1
  99. package/dist/cjs/util/PromiseQueue.js +2 -1
  100. package/dist/cjs/util/PromiseQueue.js.map +1 -1
  101. package/dist/cjs/util/Promises.d.ts +3 -2
  102. package/dist/cjs/util/Promises.d.ts.map +1 -1
  103. package/dist/cjs/util/Promises.js +4 -4
  104. package/dist/cjs/util/Promises.js.map +1 -1
  105. package/dist/esm/codec/DnsCodec.d.ts +8 -6
  106. package/dist/esm/codec/DnsCodec.d.ts.map +1 -1
  107. package/dist/esm/codec/DnsCodec.js +10 -7
  108. package/dist/esm/codec/DnsCodec.js.map +1 -1
  109. package/dist/esm/crypto/Crypto.d.ts +32 -36
  110. package/dist/esm/crypto/Crypto.d.ts.map +1 -1
  111. package/dist/esm/environment/Environment.d.ts.map +1 -1
  112. package/dist/esm/environment/Environment.js +2 -1
  113. package/dist/esm/environment/Environment.js.map +1 -1
  114. package/dist/esm/log/Diagnostic.d.ts +4 -6
  115. package/dist/esm/log/Diagnostic.d.ts.map +1 -1
  116. package/dist/esm/log/Diagnostic.js +6 -26
  117. package/dist/esm/log/Diagnostic.js.map +1 -1
  118. package/dist/esm/log/Logger.js +1 -1
  119. package/dist/esm/log/Logger.js.map +1 -1
  120. package/dist/esm/net/RetrySchedule.d.ts +10 -11
  121. package/dist/esm/net/RetrySchedule.d.ts.map +1 -1
  122. package/dist/esm/net/RetrySchedule.js +8 -7
  123. package/dist/esm/net/RetrySchedule.js.map +1 -1
  124. package/dist/esm/net/ServerAddress.d.ts +15 -4
  125. package/dist/esm/net/ServerAddress.d.ts.map +1 -1
  126. package/dist/esm/net/ServerAddress.js +33 -3
  127. package/dist/esm/net/ServerAddress.js.map +2 -2
  128. package/dist/esm/net/UdpMulticastServer.d.ts.map +1 -1
  129. package/dist/esm/net/UdpMulticastServer.js +2 -1
  130. package/dist/esm/net/UdpMulticastServer.js.map +1 -1
  131. package/dist/esm/net/mock/MockRouter.d.ts +2 -1
  132. package/dist/esm/net/mock/MockRouter.d.ts.map +1 -1
  133. package/dist/esm/net/mock/MockRouter.js.map +1 -1
  134. package/dist/esm/net/mock/MockUdpChannel.d.ts +2 -1
  135. package/dist/esm/net/mock/MockUdpChannel.d.ts.map +1 -1
  136. package/dist/esm/net/mock/MockUdpChannel.js.map +1 -1
  137. package/dist/esm/net/mock/NetworkSimulator.d.ts +2 -1
  138. package/dist/esm/net/mock/NetworkSimulator.d.ts.map +1 -1
  139. package/dist/esm/net/mock/NetworkSimulator.js.map +1 -1
  140. package/dist/esm/storage/Storage.d.ts +2 -1
  141. package/dist/esm/storage/Storage.d.ts.map +1 -1
  142. package/dist/esm/storage/Storage.js.map +1 -1
  143. package/dist/esm/storage/StorageBackendMemory.d.ts +2 -1
  144. package/dist/esm/storage/StorageBackendMemory.d.ts.map +1 -1
  145. package/dist/esm/storage/StorageBackendMemory.js +1 -1
  146. package/dist/esm/storage/StorageBackendMemory.js.map +1 -1
  147. package/dist/esm/storage/StorageContext.d.ts +2 -1
  148. package/dist/esm/storage/StorageContext.d.ts.map +1 -1
  149. package/dist/esm/storage/StorageContext.js.map +1 -1
  150. package/dist/esm/storage/StringifyTools.d.ts +2 -1
  151. package/dist/esm/storage/StringifyTools.d.ts.map +1 -1
  152. package/dist/esm/storage/StringifyTools.js +3 -0
  153. package/dist/esm/storage/StringifyTools.js.map +1 -1
  154. package/dist/esm/time/Duration.d.ts +47 -0
  155. package/dist/esm/time/Duration.d.ts.map +1 -0
  156. package/dist/esm/time/Duration.js +125 -0
  157. package/dist/esm/time/Duration.js.map +6 -0
  158. package/dist/esm/time/Time.d.ts +21 -19
  159. package/dist/esm/time/Time.d.ts.map +1 -1
  160. package/dist/esm/time/Time.js +44 -33
  161. package/dist/esm/time/Time.js.map +1 -1
  162. package/dist/esm/time/TimeUnit.d.ts +87 -0
  163. package/dist/esm/time/TimeUnit.d.ts.map +1 -0
  164. package/dist/esm/time/TimeUnit.js +68 -0
  165. package/dist/esm/time/TimeUnit.js.map +6 -0
  166. package/dist/esm/time/Timespan.d.ts +26 -0
  167. package/dist/esm/time/Timespan.d.ts.map +1 -0
  168. package/dist/esm/time/Timespan.js +32 -0
  169. package/dist/esm/time/Timespan.js.map +6 -0
  170. package/dist/esm/time/Timestamp.d.ts +47 -0
  171. package/dist/esm/time/Timestamp.d.ts.map +1 -0
  172. package/dist/esm/time/Timestamp.js +58 -0
  173. package/dist/esm/time/Timestamp.js.map +6 -0
  174. package/dist/esm/time/index.d.ts +4 -0
  175. package/dist/esm/time/index.d.ts.map +1 -1
  176. package/dist/esm/time/index.js +4 -0
  177. package/dist/esm/time/index.js.map +1 -1
  178. package/dist/esm/transaction/Status.d.ts +1 -1
  179. package/dist/esm/transaction/Status.d.ts.map +1 -1
  180. package/dist/esm/transaction/Status.js +2 -1
  181. package/dist/esm/transaction/Status.js.map +1 -1
  182. package/dist/esm/transaction/Tx.d.ts.map +1 -1
  183. package/dist/esm/transaction/Tx.js +10 -8
  184. package/dist/esm/transaction/Tx.js.map +1 -1
  185. package/dist/esm/util/Cache.d.ts +5 -4
  186. package/dist/esm/util/Cache.d.ts.map +1 -1
  187. package/dist/esm/util/Cache.js +11 -11
  188. package/dist/esm/util/Cache.js.map +1 -1
  189. package/dist/esm/util/DataReadQueue.d.ts +2 -1
  190. package/dist/esm/util/DataReadQueue.d.ts.map +1 -1
  191. package/dist/esm/util/DataReadQueue.js +9 -3
  192. package/dist/esm/util/DataReadQueue.js.map +1 -1
  193. package/dist/esm/util/DeepEqual.d.ts +13 -1
  194. package/dist/esm/util/DeepEqual.d.ts.map +1 -1
  195. package/dist/esm/util/DeepEqual.js +24 -5
  196. package/dist/esm/util/DeepEqual.js.map +2 -2
  197. package/dist/esm/util/Observable.d.ts +4 -3
  198. package/dist/esm/util/Observable.d.ts.map +1 -1
  199. package/dist/esm/util/Observable.js +16 -15
  200. package/dist/esm/util/Observable.js.map +1 -1
  201. package/dist/esm/util/PromiseQueue.d.ts +2 -1
  202. package/dist/esm/util/PromiseQueue.d.ts.map +1 -1
  203. package/dist/esm/util/PromiseQueue.js +2 -1
  204. package/dist/esm/util/PromiseQueue.js.map +1 -1
  205. package/dist/esm/util/Promises.d.ts +3 -2
  206. package/dist/esm/util/Promises.d.ts.map +1 -1
  207. package/dist/esm/util/Promises.js +4 -4
  208. package/dist/esm/util/Promises.js.map +1 -1
  209. package/package.json +3 -3
  210. package/src/codec/DnsCodec.ts +27 -8
  211. package/src/environment/Environment.ts +2 -1
  212. package/src/log/Diagnostic.ts +9 -37
  213. package/src/log/Logger.ts +1 -1
  214. package/src/net/RetrySchedule.ts +14 -14
  215. package/src/net/ServerAddress.ts +44 -5
  216. package/src/net/UdpMulticastServer.ts +2 -1
  217. package/src/net/mock/MockRouter.ts +2 -1
  218. package/src/net/mock/MockUdpChannel.ts +2 -1
  219. package/src/net/mock/NetworkSimulator.ts +2 -1
  220. package/src/storage/Storage.ts +2 -5
  221. package/src/storage/StorageBackendMemory.ts +2 -2
  222. package/src/storage/StorageContext.ts +2 -1
  223. package/src/storage/StringifyTools.ts +5 -0
  224. package/src/time/Duration.ts +181 -0
  225. package/src/time/Time.ts +50 -39
  226. package/src/time/TimeUnit.ts +159 -0
  227. package/src/time/Timespan.ts +52 -0
  228. package/src/time/Timestamp.ts +94 -0
  229. package/src/time/index.ts +4 -0
  230. package/src/transaction/Status.ts +2 -1
  231. package/src/transaction/Tx.ts +9 -7
  232. package/src/util/Cache.ts +11 -10
  233. package/src/util/DataReadQueue.ts +9 -3
  234. package/src/util/DeepEqual.ts +38 -13
  235. package/src/util/Observable.ts +19 -17
  236. package/src/util/PromiseQueue.ts +4 -2
  237. package/src/util/Promises.ts +6 -5
@@ -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 get: () => Time;
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 readonly now = (): Date => Time.get().now();
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 readonly nowMs = (): number => Time.get().nowMs();
42
+ static get nowMs() {
43
+ return Time.default.nowMs as Timestamp;
44
+ }
38
45
 
39
- nowUs() {
40
- return Math.floor(performance.now() + performance.timeOrigin) * 1000;
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, durationMs: number, callback: Timer.Callback): Timer {
48
- return new StandardTimer(name, durationMs, callback, false);
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, durationMs: number, callback: Timer.Callback): Timer =>
51
- Time.get().getTimer(name, durationMs, callback);
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, intervalMs: number, callback: Timer.Callback): Timer {
57
- return new StandardTimer(name, intervalMs, callback, true);
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, intervalMs: number, callback: Timer.Callback): Timer =>
60
- Time.get().getPeriodicTimer(name, intervalMs, callback);
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, durationMs: number): CancelablePromise {
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, durationMs, resolve);
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, durationMs: number) {
82
- return Time.get().sleep(name, durationMs);
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 = () => Time.nowMs() * 1000; // Fallback is a bit less accurate
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
- intervalMs: number;
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
- #intervalMs = -1;
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
- intervalMs: number,
162
+ duration: Duration,
150
163
  private readonly callback: Timer.Callback,
151
164
  readonly isPeriodic: boolean,
152
165
  ) {
153
- this.intervalMs = intervalMs;
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 intervalMs(intervalMs: number) {
162
- if (intervalMs < 0 || intervalMs > 2147483647) {
174
+ set interval(interval: Duration) {
175
+ if (interval < 0 || interval > 2147483647) {
163
176
  throw new ImplementationError(
164
- `Invalid intervalMs: ${intervalMs}. The value must be between 0 and 32-bit maximum value (2147483647)`,
177
+ `Invalid intervalMs: ${interval}. The value must be between 0 and 32-bit maximum value (2147483647)`,
165
178
  );
166
179
  }
167
- this.#intervalMs = intervalMs;
180
+ this.#interval = interval;
168
181
  }
169
182
 
170
- get intervalMs() {
171
- return this.#intervalMs;
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.intervalMs);
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: Diagnostic.interval(timer.intervalMs),
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
- const time = new Time();
236
-
237
- Time.startup.systemMs = Time.startup.processMs = time.nowMs();
248
+ Time.default = new Time();
238
249
 
239
- Time.get = () => 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);
@@ -0,0 +1,52 @@
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
+ import { Timestamp } from "./Timestamp.js";
9
+
10
+ /**
11
+ * A period between two {@link Timestamp}s.
12
+ */
13
+ export interface Timespan {
14
+ start: Timestamp;
15
+ stop: Timestamp;
16
+ duration: Duration;
17
+
18
+ from(newStart: Timestamp.Definition): Timespan;
19
+ to(newStart: Timestamp.Definition): Timespan;
20
+ valueOf(): { start: Timestamp; stop: Timestamp };
21
+ }
22
+
23
+ /**
24
+ * Create a new timespan representing time between {@link start} and {@link stop}.
25
+ */
26
+ export function Timespan(start: Timestamp.Definition, stop: Timestamp.Definition) {
27
+ return Object.create(prototype, {
28
+ start: { value: Timestamp(start), enumerable: true },
29
+ stop: { value: Timestamp(stop), enumerable: true },
30
+ }) as Timespan;
31
+ }
32
+
33
+ const prototype: Timespan = {
34
+ start: 0 as Timestamp,
35
+ stop: 0 as Timestamp,
36
+
37
+ get duration() {
38
+ return (this.stop - this.start) as Duration;
39
+ },
40
+
41
+ from(this: Timespan, newStart) {
42
+ return Timespan(newStart, this.stop);
43
+ },
44
+
45
+ to(this: Timespan, newStop) {
46
+ return Timespan(this.start, newStop);
47
+ },
48
+
49
+ valueOf(this: Timespan) {
50
+ return { start: this.start, stop: this.stop };
51
+ },
52
+ };