homebridge-plugin-utils 1.35.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. package/README.md +130 -2
  2. package/build/eslint-plugin/README.md +164 -0
  3. package/build/eslint-plugin/config.mjs +308 -0
  4. package/build/eslint-plugin/index.mjs +7 -0
  5. package/build/eslint-plugin/plugin.mjs +46 -0
  6. package/build/eslint-plugin/rules/blank-line-after-open-brace.mjs +137 -0
  7. package/build/eslint-plugin/rules/blank-line-after-open-brace.test.mjs +112 -0
  8. package/build/eslint-plugin/rules/comment-style.mjs +190 -0
  9. package/build/eslint-plugin/rules/comment-style.test.mjs +190 -0
  10. package/build/eslint-plugin/rules/enforce-node-protocol.mjs +114 -0
  11. package/build/eslint-plugin/rules/enforce-node-protocol.test.mjs +116 -0
  12. package/build/eslint-plugin/rules/paren-comparisons-in-logical.mjs +94 -0
  13. package/build/eslint-plugin/rules/paren-comparisons-in-logical.test.mjs +107 -0
  14. package/build/eslint-plugin/rules/split-type-imports.mjs +354 -0
  15. package/build/eslint-plugin/rules/split-type-imports.test.mjs +268 -0
  16. package/build/eslint-plugin/test-setup.mjs +21 -0
  17. package/build/fs-ops.mjs +184 -0
  18. package/build/tsconfig.json +18 -3
  19. package/dist/backpressure.d.ts +94 -45
  20. package/dist/backpressure.js +229 -93
  21. package/dist/backpressure.js.map +1 -1
  22. package/dist/cli/index.d.ts +166 -0
  23. package/dist/cli/index.js +551 -0
  24. package/dist/cli/index.js.map +1 -0
  25. package/dist/clock-double.d.ts +93 -0
  26. package/dist/clock-double.js +141 -0
  27. package/dist/clock-double.js.map +1 -0
  28. package/dist/clock.d.ts +39 -0
  29. package/dist/clock.js +34 -0
  30. package/dist/clock.js.map +1 -0
  31. package/dist/disposable-stack.d.ts +59 -0
  32. package/dist/disposable-stack.js +155 -0
  33. package/dist/disposable-stack.js.map +1 -0
  34. package/dist/docChrome.d.ts +260 -0
  35. package/dist/docChrome.js +361 -0
  36. package/dist/docChrome.js.map +1 -0
  37. package/dist/eslint-plugin/config.d.mts +193 -0
  38. package/dist/eslint-plugin/index.d.mts +2 -0
  39. package/dist/eslint-plugin/plugin.d.mts +87 -0
  40. package/dist/eslint-plugin/rules/blank-line-after-open-brace.d.mts +19 -0
  41. package/dist/eslint-plugin/rules/comment-style.d.mts +15 -0
  42. package/dist/eslint-plugin/rules/enforce-node-protocol.d.mts +18 -0
  43. package/dist/eslint-plugin/rules/paren-comparisons-in-logical.d.mts +15 -0
  44. package/dist/eslint-plugin/rules/split-type-imports.d.mts +16 -0
  45. package/dist/featureOptions-docs.d.ts +96 -0
  46. package/dist/featureOptions-docs.js +193 -0
  47. package/dist/featureOptions-docs.js.map +1 -0
  48. package/dist/featureOptions.d.ts +674 -0
  49. package/dist/featureOptions.js +870 -0
  50. package/dist/featureOptions.js.map +1 -0
  51. package/dist/ffmpeg/codecs.d.ts +256 -72
  52. package/dist/ffmpeg/codecs.js +477 -262
  53. package/dist/ffmpeg/codecs.js.map +1 -1
  54. package/dist/ffmpeg/dgram-util.d.ts +46 -0
  55. package/dist/ffmpeg/dgram-util.js +38 -0
  56. package/dist/ffmpeg/dgram-util.js.map +1 -0
  57. package/dist/ffmpeg/exec.d.ts +83 -64
  58. package/dist/ffmpeg/exec.js +77 -86
  59. package/dist/ffmpeg/exec.js.map +1 -1
  60. package/dist/ffmpeg/fmp4.d.ts +49 -2
  61. package/dist/ffmpeg/fmp4.js +47 -11
  62. package/dist/ffmpeg/fmp4.js.map +1 -1
  63. package/dist/ffmpeg/hap-enums.d.ts +214 -0
  64. package/dist/ffmpeg/hap-enums.js +92 -0
  65. package/dist/ffmpeg/hap-enums.js.map +1 -0
  66. package/dist/ffmpeg/index.d.ts +16 -9
  67. package/dist/ffmpeg/index.js +6 -0
  68. package/dist/ffmpeg/index.js.map +1 -1
  69. package/dist/ffmpeg/mp4-assembler.d.ts +161 -0
  70. package/dist/ffmpeg/mp4-assembler.js +424 -0
  71. package/dist/ffmpeg/mp4-assembler.js.map +1 -0
  72. package/dist/ffmpeg/mp4-parser.d.ts +94 -0
  73. package/dist/ffmpeg/mp4-parser.js +130 -0
  74. package/dist/ffmpeg/mp4-parser.js.map +1 -0
  75. package/dist/ffmpeg/options.d.ts +62 -149
  76. package/dist/ffmpeg/options.js +608 -499
  77. package/dist/ffmpeg/options.js.map +1 -1
  78. package/dist/ffmpeg/process.d.ts +142 -96
  79. package/dist/ffmpeg/process.js +406 -278
  80. package/dist/ffmpeg/process.js.map +1 -1
  81. package/dist/ffmpeg/record.d.ts +325 -186
  82. package/dist/ffmpeg/record.js +418 -565
  83. package/dist/ffmpeg/record.js.map +1 -1
  84. package/dist/ffmpeg/recording-process-double.d.ts +157 -0
  85. package/dist/ffmpeg/recording-process-double.js +190 -0
  86. package/dist/ffmpeg/recording-process-double.js.map +1 -0
  87. package/dist/ffmpeg/rtp-parser.d.ts +70 -0
  88. package/dist/ffmpeg/rtp-parser.js +77 -0
  89. package/dist/ffmpeg/rtp-parser.js.map +1 -0
  90. package/dist/ffmpeg/rtp.d.ts +198 -141
  91. package/dist/ffmpeg/rtp.js +474 -251
  92. package/dist/ffmpeg/rtp.js.map +1 -1
  93. package/dist/ffmpeg/settings.d.ts +5 -2
  94. package/dist/ffmpeg/settings.js +20 -5
  95. package/dist/ffmpeg/settings.js.map +1 -1
  96. package/dist/ffmpeg/stream.d.ts +57 -107
  97. package/dist/ffmpeg/stream.js +121 -150
  98. package/dist/ffmpeg/stream.js.map +1 -1
  99. package/dist/formatters.d.ts +106 -0
  100. package/dist/formatters.js +174 -0
  101. package/dist/formatters.js.map +1 -0
  102. package/dist/homebridge-enums.d.ts +30 -0
  103. package/dist/homebridge-enums.js +17 -0
  104. package/dist/homebridge-enums.js.map +1 -0
  105. package/dist/index.d.ts +13 -6
  106. package/dist/index.js +8 -2
  107. package/dist/index.js.map +1 -1
  108. package/dist/logclient/auth.d.ts +114 -0
  109. package/dist/logclient/auth.js +199 -0
  110. package/dist/logclient/auth.js.map +1 -0
  111. package/dist/logclient/cli-run.d.ts +76 -0
  112. package/dist/logclient/cli-run.js +639 -0
  113. package/dist/logclient/cli-run.js.map +1 -0
  114. package/dist/logclient/cli.d.ts +3 -0
  115. package/dist/logclient/cli.js +97 -0
  116. package/dist/logclient/cli.js.map +1 -0
  117. package/dist/logclient/client.d.ts +145 -0
  118. package/dist/logclient/client.js +600 -0
  119. package/dist/logclient/client.js.map +1 -0
  120. package/dist/logclient/config.d.ts +173 -0
  121. package/dist/logclient/config.js +199 -0
  122. package/dist/logclient/config.js.map +1 -0
  123. package/dist/logclient/endpoints.d.ts +54 -0
  124. package/dist/logclient/endpoints.js +73 -0
  125. package/dist/logclient/endpoints.js.map +1 -0
  126. package/dist/logclient/filter.d.ts +45 -0
  127. package/dist/logclient/filter.js +51 -0
  128. package/dist/logclient/filter.js.map +1 -0
  129. package/dist/logclient/frame.d.ts +93 -0
  130. package/dist/logclient/frame.js +203 -0
  131. package/dist/logclient/frame.js.map +1 -0
  132. package/dist/logclient/index.d.ts +31 -0
  133. package/dist/logclient/index.js +12 -0
  134. package/dist/logclient/index.js.map +1 -0
  135. package/dist/logclient/parser.d.ts +211 -0
  136. package/dist/logclient/parser.js +393 -0
  137. package/dist/logclient/parser.js.map +1 -0
  138. package/dist/logclient/rest.d.ts +41 -0
  139. package/dist/logclient/rest.js +111 -0
  140. package/dist/logclient/rest.js.map +1 -0
  141. package/dist/logclient/settings.d.ts +15 -0
  142. package/dist/logclient/settings.js +64 -0
  143. package/dist/logclient/settings.js.map +1 -0
  144. package/dist/logclient/socket-double.d.ts +201 -0
  145. package/dist/logclient/socket-double.js +384 -0
  146. package/dist/logclient/socket-double.js.map +1 -0
  147. package/dist/logclient/socket.d.ts +257 -0
  148. package/dist/logclient/socket.js +620 -0
  149. package/dist/logclient/socket.js.map +1 -0
  150. package/dist/logclient/stitch.d.ts +83 -0
  151. package/dist/logclient/stitch.js +146 -0
  152. package/dist/logclient/stitch.js.map +1 -0
  153. package/dist/logclient/time-expression.d.ts +42 -0
  154. package/dist/logclient/time-expression.js +181 -0
  155. package/dist/logclient/time-expression.js.map +1 -0
  156. package/dist/logclient/time-window.d.ts +38 -0
  157. package/dist/logclient/time-window.js +53 -0
  158. package/dist/logclient/time-window.js.map +1 -0
  159. package/dist/logclient/types.d.ts +107 -0
  160. package/dist/logclient/types.js +6 -0
  161. package/dist/logclient/types.js.map +1 -0
  162. package/dist/mqttClient.d.ts +287 -0
  163. package/dist/mqttClient.js +433 -0
  164. package/dist/mqttClient.js.map +1 -0
  165. package/dist/service.d.ts +64 -15
  166. package/dist/service.js +93 -66
  167. package/dist/service.js.map +1 -1
  168. package/dist/ui/featureOptions.js +870 -0
  169. package/dist/ui/featureOptions.js.map +1 -0
  170. package/dist/ui/formatters.js +174 -0
  171. package/dist/ui/formatters.js.map +1 -0
  172. package/dist/ui/pluginConfigSession.mjs +141 -0
  173. package/dist/ui/webUi-featureOptions/categoryState.mjs +135 -0
  174. package/dist/ui/webUi-featureOptions/effects/keyboard.mjs +61 -0
  175. package/dist/ui/webUi-featureOptions/effects/persist.mjs +226 -0
  176. package/dist/ui/webUi-featureOptions/effects/theme.mjs +398 -0
  177. package/dist/ui/webUi-featureOptions/effects/tokens.mjs +152 -0
  178. package/dist/ui/webUi-featureOptions/rendering.mjs +431 -0
  179. package/dist/ui/webUi-featureOptions/selectors.mjs +360 -0
  180. package/dist/ui/webUi-featureOptions/state.mjs +319 -0
  181. package/dist/ui/webUi-featureOptions/store.mjs +181 -0
  182. package/dist/ui/webUi-featureOptions/utils.mjs +213 -0
  183. package/dist/ui/webUi-featureOptions/views/connectionError.mjs +152 -0
  184. package/dist/ui/webUi-featureOptions/views/deviceInfo.mjs +80 -0
  185. package/dist/ui/webUi-featureOptions/views/header.mjs +77 -0
  186. package/dist/ui/webUi-featureOptions/views/nav.mjs +341 -0
  187. package/dist/ui/webUi-featureOptions/views/options.mjs +521 -0
  188. package/dist/ui/webUi-featureOptions/views/search.mjs +395 -0
  189. package/dist/ui/webUi-featureOptions.mjs +702 -0
  190. package/dist/ui/webUi.mjs +225 -88
  191. package/dist/util.d.ts +679 -45
  192. package/dist/util.js +830 -77
  193. package/dist/util.js.map +1 -1
  194. package/package.json +33 -15
  195. package/build/eslint-rules.mjs +0 -511
  196. package/dist/featureoptions.d.ts +0 -264
  197. package/dist/featureoptions.js +0 -480
  198. package/dist/featureoptions.js.map +0 -1
  199. package/dist/mqttclient.d.ts +0 -178
  200. package/dist/mqttclient.js +0 -310
  201. package/dist/mqttclient.js.map +0 -1
  202. package/dist/ui/featureoptions.js +0 -480
  203. package/dist/ui/featureoptions.js.map +0 -1
  204. package/dist/ui/webUi-featureoptions.mjs +0 -3765
@@ -0,0 +1,93 @@
1
+ /**
2
+ * A reusable, controllable {@link Clock} test double.
3
+ *
4
+ * The {@link Clock} seam in `clock.ts` exists so a consuming plugin's time-dependent code can be driven without real wall-clock waits. This module ships the fake that
5
+ * cashes that in: a {@link TestClock} over a virtual timeline a test advances explicitly. `now()` returns the virtual time; `delay()` registers a pending wait that
6
+ * resolves only when {@link TestClock.advance} crosses its deadline, or rejects when its signal aborts - matching `node:timers/promises` `setTimeout`'s `AbortError`
7
+ * shape. No real timers and no wall-clock are used, so a consumer's pacing/timeout/duration path runs deterministically and instantly under test.
8
+ *
9
+ * The double builds on the library's own primitives rather than hand-rolling them: {@link onAbort} wires the abort listener and yields the `Disposable` that detaches
10
+ * it, and `Promise.withResolvers` captures each pending wait's deferred. The abort listener is detached on EITHER resolution path (deadline-crossed or aborted), so no
11
+ * listener leaks onto a long-lived signal across many short waits.
12
+ *
13
+ * @module
14
+ */
15
+ import type { Clock } from "./clock.ts";
16
+ /**
17
+ * A controllable {@link Clock} double over virtual time. `now()` returns the current virtual time; `delay()` registers a pending wait that resolves only when
18
+ * {@link TestClock.advance} crosses its deadline (in ascending-deadline order), or rejects with an `AbortError` (matching `node:timers/promises` `setTimeout` - `name`
19
+ * `"AbortError"`, `code` `"ABORT_ERR"`, NOT the signal's reason) when its signal aborts. No real timers or wall-clock are used.
20
+ *
21
+ * The virtual time is a RELATIVE timeline seeded at `start` (default `0`), NOT real epoch milliseconds. A consumer that compares `now()` against an absolute real-epoch
22
+ * constant would diverge; consumers must only compare `now()` values to each other (deriving elapsed intervals from differences), which is the only use a
23
+ * `Date.now()`-style read serves in the consuming pacing path - all its time reads come from the one injected clock.
24
+ *
25
+ * @example
26
+ *
27
+ * ```ts
28
+ * import { TestClock } from "homebridge-plugin-utils";
29
+ *
30
+ * const clock = new TestClock();
31
+ *
32
+ * const waited = clock.delay(100);
33
+ *
34
+ * // Nothing resolves until virtual time crosses the deadline.
35
+ * clock.advance(100);
36
+ *
37
+ * await waited;
38
+ * ```
39
+ *
40
+ * @see Clock
41
+ *
42
+ * @category Testing
43
+ */
44
+ export declare class TestClock implements Clock {
45
+ #private;
46
+ /**
47
+ * Construct a clock seeded at `start` (default `0`). The seed is the initial value `now()` returns; `advance` moves it forward (or back, for a negative delta).
48
+ *
49
+ * @param start - The initial virtual time, in the consumer's relative timeline. Defaults to `0`.
50
+ */
51
+ constructor(start?: number);
52
+ /**
53
+ * Advance virtual time by `ms` and resolve every delay whose deadline the new time has reached. The delta is applied regardless of sign, so a negative `ms` moves time
54
+ * backward; `advance(0)` moves time nowhere but STILL flushes any already-due entry (a `delay(0)` or a `delay` with a non-positive `ms`), so a zero or negative delay
55
+ * is never a lost wakeup.
56
+ *
57
+ * Due entries resolve in ASCENDING deadline order; entries that share a deadline keep their FIFO registration order, because the snapshot is taken before any removal
58
+ * and the numeric sort is stable - matching how `setTimeout` fires equal-deadline timers in scheduling order. Each due entry is removed by identity and has its abort
59
+ * listener detached before it resolves, so the resolve path leaks no listener and the iteration is immune to the index shifts a forward in-place splice would cause.
60
+ *
61
+ * @param ms - The amount of virtual time to advance, in milliseconds. May be zero or negative.
62
+ */
63
+ advance(ms: number): void;
64
+ /**
65
+ * Register a delay that resolves when virtual time reaches `this.now() + ms`, or rejects with an `AbortError` (matching `node:timers/promises`) if `init.signal` aborts
66
+ * first. A non-positive `ms` yields a deadline at or before the current time, which the very next {@link TestClock.advance} (including `advance(0)`) flushes.
67
+ *
68
+ * A pre-aborted signal rejects on the executor's microtask exactly as `systemClock` does (NOT a synchronous throw): {@link onAbort} fires the handler inline, which
69
+ * removes the just-registered entry and rejects, so the entry never lingers in `pending`.
70
+ *
71
+ * @param ms - The delay, in milliseconds. May be zero or negative (flushed by the next `advance`).
72
+ * @param init - Optional init options. A supplied `signal` rejects the wait with an `AbortError` when it aborts.
73
+ *
74
+ * @returns A promise that resolves when the deadline is crossed, or rejects with an `AbortError` if the signal aborts first.
75
+ */
76
+ delay(ms: number, init?: {
77
+ signal?: AbortSignal;
78
+ }): Promise<void>;
79
+ /**
80
+ * Return the current virtual time. Compare these values to each other to derive elapsed intervals - they are a relative timeline, not real epoch milliseconds.
81
+ *
82
+ * @returns The current virtual time.
83
+ */
84
+ now(): number;
85
+ /**
86
+ * The number of registered delays that have neither resolved nor rejected. A test reads this to assert a consumer registered its waits and later cleared them (no
87
+ * leak).
88
+ *
89
+ * @returns The count of unsettled delays.
90
+ */
91
+ get pending(): number;
92
+ }
93
+ //# sourceMappingURL=clock-double.d.ts.map
@@ -0,0 +1,141 @@
1
+ /* Copyright(C) 2017-2026, HJD (https://github.com/hjdhjd). All rights reserved.
2
+ *
3
+ * clock-double.ts: A reusable, controllable Clock test double - virtual time a test advances explicitly - for the injectable Clock seam in clock.ts.
4
+ */
5
+ import { onAbort } from "./util.js";
6
+ /**
7
+ * Construct the rejection a {@link TestClock} `delay` produces when its signal aborts, matching `node:timers/promises` `setTimeout` exactly: a plain `Error` whose `name`
8
+ * is `"AbortError"` and whose `code` is the STRING `"ABORT_ERR"`. The real primitive's rejection is a dedicated internal class (not a `DOMException`, whose `code` is the
9
+ * numeric `20`, and there is no constructable `AbortError` global), so the double cannot match the constructor or prototype identity - it matches the observable `name`
10
+ * and `code` a consumer branches on, which is the contract that matters.
11
+ *
12
+ * @returns The `AbortError`-shaped rejection.
13
+ */
14
+ function abortError() {
15
+ const error = new Error("The operation was aborted");
16
+ error.name = "AbortError";
17
+ // `code` is not a standard `Error` field, so assign it through an indexed widening rather than declaring a one-off subclass. The STRING value is what the real
18
+ // `node:timers/promises` rejection carries and what a consumer's `error.code === "ABORT_ERR"` check reads.
19
+ error.code = "ABORT_ERR";
20
+ return error;
21
+ }
22
+ /**
23
+ * A controllable {@link Clock} double over virtual time. `now()` returns the current virtual time; `delay()` registers a pending wait that resolves only when
24
+ * {@link TestClock.advance} crosses its deadline (in ascending-deadline order), or rejects with an `AbortError` (matching `node:timers/promises` `setTimeout` - `name`
25
+ * `"AbortError"`, `code` `"ABORT_ERR"`, NOT the signal's reason) when its signal aborts. No real timers or wall-clock are used.
26
+ *
27
+ * The virtual time is a RELATIVE timeline seeded at `start` (default `0`), NOT real epoch milliseconds. A consumer that compares `now()` against an absolute real-epoch
28
+ * constant would diverge; consumers must only compare `now()` values to each other (deriving elapsed intervals from differences), which is the only use a
29
+ * `Date.now()`-style read serves in the consuming pacing path - all its time reads come from the one injected clock.
30
+ *
31
+ * @example
32
+ *
33
+ * ```ts
34
+ * import { TestClock } from "homebridge-plugin-utils";
35
+ *
36
+ * const clock = new TestClock();
37
+ *
38
+ * const waited = clock.delay(100);
39
+ *
40
+ * // Nothing resolves until virtual time crosses the deadline.
41
+ * clock.advance(100);
42
+ *
43
+ * await waited;
44
+ * ```
45
+ *
46
+ * @see Clock
47
+ *
48
+ * @category Testing
49
+ */
50
+ export class TestClock {
51
+ // The current virtual time. Seeded by the constructor and moved only by `advance`.
52
+ #now;
53
+ // The registered, not-yet-settled delays. An entry leaves this list exactly once - either when `advance` crosses its deadline or when its signal aborts - via
54
+ // `#remove`, which splices by identity so a mixed resolve-and-abort sequence never strands or mis-removes an entry.
55
+ #pending = [];
56
+ /**
57
+ * Construct a clock seeded at `start` (default `0`). The seed is the initial value `now()` returns; `advance` moves it forward (or back, for a negative delta).
58
+ *
59
+ * @param start - The initial virtual time, in the consumer's relative timeline. Defaults to `0`.
60
+ */
61
+ constructor(start = 0) {
62
+ this.#now = start;
63
+ }
64
+ /**
65
+ * Advance virtual time by `ms` and resolve every delay whose deadline the new time has reached. The delta is applied regardless of sign, so a negative `ms` moves time
66
+ * backward; `advance(0)` moves time nowhere but STILL flushes any already-due entry (a `delay(0)` or a `delay` with a non-positive `ms`), so a zero or negative delay
67
+ * is never a lost wakeup.
68
+ *
69
+ * Due entries resolve in ASCENDING deadline order; entries that share a deadline keep their FIFO registration order, because the snapshot is taken before any removal
70
+ * and the numeric sort is stable - matching how `setTimeout` fires equal-deadline timers in scheduling order. Each due entry is removed by identity and has its abort
71
+ * listener detached before it resolves, so the resolve path leaks no listener and the iteration is immune to the index shifts a forward in-place splice would cause.
72
+ *
73
+ * @param ms - The amount of virtual time to advance, in milliseconds. May be zero or negative.
74
+ */
75
+ advance(ms) {
76
+ this.#now += ms;
77
+ // Snapshot the due entries BEFORE mutating `#pending`, then sort them into deadline order. Filtering off a live array while removing from it would shift indices and
78
+ // strand entries; the snapshot first decouples the iteration from the removal. The sort is a stable numeric comparator, so equal deadlines preserve FIFO order.
79
+ const due = this.#pending.filter((entry) => entry.deadline <= this.#now).sort((a, b) => a.deadline - b.deadline);
80
+ for (const entry of due) {
81
+ // Remove by identity first so a re-entrant observer sees the correct `pending` count, then detach the abort listener (present only when this delay had a signal) so
82
+ // the resolve path leaves no listener on a long-lived signal, then settle the caller's promise.
83
+ this.#remove(entry);
84
+ entry.dispose?.[Symbol.dispose]();
85
+ entry.resolve();
86
+ }
87
+ }
88
+ /**
89
+ * Register a delay that resolves when virtual time reaches `this.now() + ms`, or rejects with an `AbortError` (matching `node:timers/promises`) if `init.signal` aborts
90
+ * first. A non-positive `ms` yields a deadline at or before the current time, which the very next {@link TestClock.advance} (including `advance(0)`) flushes.
91
+ *
92
+ * A pre-aborted signal rejects on the executor's microtask exactly as `systemClock` does (NOT a synchronous throw): {@link onAbort} fires the handler inline, which
93
+ * removes the just-registered entry and rejects, so the entry never lingers in `pending`.
94
+ *
95
+ * @param ms - The delay, in milliseconds. May be zero or negative (flushed by the next `advance`).
96
+ * @param init - Optional init options. A supplied `signal` rejects the wait with an `AbortError` when it aborts.
97
+ *
98
+ * @returns A promise that resolves when the deadline is crossed, or rejects with an `AbortError` if the signal aborts first.
99
+ */
100
+ delay(ms, init) {
101
+ const { promise, reject, resolve } = Promise.withResolvers();
102
+ const entry = { deadline: this.#now + ms, resolve };
103
+ // Register the entry FIRST so a pre-aborted signal's inline `onAbort` handler (below) can find and remove it. `onAbort` runs the handler synchronously when the
104
+ // signal is already aborted, so for a pre-aborted signal the entry is pushed and then immediately removed-and-rejected within this call - settling on the executor's
105
+ // microtask, identical to `systemClock`. When no signal is supplied, `dispose` stays undefined and the entry only ever leaves via `advance`.
106
+ this.#pending.push(entry);
107
+ if (init?.signal !== undefined) {
108
+ entry.dispose = onAbort(init.signal, () => {
109
+ this.#remove(entry);
110
+ reject(abortError());
111
+ });
112
+ }
113
+ return promise;
114
+ }
115
+ /**
116
+ * Return the current virtual time. Compare these values to each other to derive elapsed intervals - they are a relative timeline, not real epoch milliseconds.
117
+ *
118
+ * @returns The current virtual time.
119
+ */
120
+ now() {
121
+ return this.#now;
122
+ }
123
+ /**
124
+ * The number of registered delays that have neither resolved nor rejected. A test reads this to assert a consumer registered its waits and later cleared them (no
125
+ * leak).
126
+ *
127
+ * @returns The count of unsettled delays.
128
+ */
129
+ get pending() {
130
+ return this.#pending.length;
131
+ }
132
+ // Remove `entry` from `#pending` by identity. A guarded `indexOf` + `splice` makes a second removal (e.g. an abort that races a resolve) a safe no-op and
133
+ // never removes the wrong entry, so `#pending` stays consistent across any resolve-and-abort interleaving.
134
+ #remove(entry) {
135
+ const index = this.#pending.indexOf(entry);
136
+ if (index !== -1) {
137
+ this.#pending.splice(index, 1);
138
+ }
139
+ }
140
+ }
141
+ //# sourceMappingURL=clock-double.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clock-double.js","sourceRoot":"","sources":["../src/clock-double.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAiBH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAcpC;;;;;;;GAOG;AACH,SAAS,UAAU;IAEjB,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAErD,KAAK,CAAC,IAAI,GAAG,YAAY,CAAC;IAE1B,+JAA+J;IAC/J,2GAA2G;IAC1G,KAAkC,CAAC,IAAI,GAAG,WAAW,CAAC;IAEvD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,OAAO,SAAS;IAEpB,mFAAmF;IACnF,IAAI,CAAS;IAEb,8JAA8J;IAC9J,oHAAoH;IAC3G,QAAQ,GAAiB,EAAE,CAAC;IAErC;;;;OAIG;IACH,YAAmB,KAAK,GAAG,CAAC;QAE1B,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;IACpB,CAAC;IAED;;;;;;;;;;OAUG;IACI,OAAO,CAAC,EAAU;QAEvB,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;QAEhB,qKAAqK;QACrK,gKAAgK;QAChK,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;QAEjH,KAAI,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;YAEvB,oKAAoK;YACpK,gGAAgG;YAChG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YACpB,KAAK,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAClC,KAAK,CAAC,OAAO,EAAE,CAAC;QAClB,CAAC;IACH,CAAC;IAED;;;;;;;;;;;OAWG;IACI,KAAK,CAAC,EAAU,EAAE,IAA+B;QAEtD,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,GAA+B,OAAO,CAAC,aAAa,EAAE,CAAC;QACzF,MAAM,KAAK,GAAe,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC;QAEhE,gKAAgK;QAChK,qKAAqK;QACrK,6IAA6I;QAC7I,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE1B,IAAG,IAAI,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;YAE9B,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE;gBAExC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBACpB,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACvB,CAAC,CAAC,CAAC;QACL,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;OAIG;IACI,GAAG;QAER,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED;;;;;OAKG;IACH,IAAW,OAAO;QAEhB,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;IAC9B,CAAC;IAED,0JAA0J;IAC1J,2GAA2G;IAC3G,OAAO,CAAC,KAAiB;QAEvB,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAE3C,IAAG,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YAEhB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * The injectable wall-clock contract: the platform time primitives time-dependent code reads. A consumer holds a `Clock` rather than calling `Date.now()` /
3
+ * `node:timers/promises` `setTimeout` directly, so a test can substitute a controllable double (`TestClock`) and drive time deterministically while production behavior
4
+ * stays unchanged through {@link systemClock}.
5
+ *
6
+ * @see systemClock
7
+ *
8
+ * @category Utilities
9
+ */
10
+ export interface Clock {
11
+ /**
12
+ * Resolve after `ms` milliseconds, or reject if `init.signal` aborts first. The production {@link systemClock} implements this as `node:timers/promises` `setTimeout`,
13
+ * so an abort rejects with that primitive's `AbortError` (`name` `"AbortError"`, `code` `"ABORT_ERR"`) rather than the signal's reason.
14
+ *
15
+ * @param ms - The delay, in milliseconds.
16
+ * @param init - Optional init options. `signal` cancels the delay - resolving the wait early with a rejection - when it aborts.
17
+ *
18
+ * @returns A promise that resolves after the delay, or rejects with an `AbortError` if the signal aborts first.
19
+ */
20
+ delay(ms: number, init?: {
21
+ signal?: AbortSignal;
22
+ }): Promise<void>;
23
+ /**
24
+ * Return the current time as epoch milliseconds. The production {@link systemClock} implements this as `Date.now()`.
25
+ *
26
+ * @returns The current time in epoch milliseconds.
27
+ */
28
+ now(): number;
29
+ }
30
+ /**
31
+ * The behavior-neutral production {@link Clock}: `now()` IS `Date.now()` and `delay()` IS `node:timers/promises` `setTimeout`. A consumer that routes its time reads
32
+ * through this clock instead of calling those primitives directly cannot observe any behavior change - it is the same two calls, one indirection removed at test time.
33
+ *
34
+ * @see Clock
35
+ *
36
+ * @category Utilities
37
+ */
38
+ export declare const systemClock: Clock;
39
+ //# sourceMappingURL=clock.d.ts.map
package/dist/clock.js ADDED
@@ -0,0 +1,34 @@
1
+ /* Copyright(C) 2017-2026, HJD (https://github.com/hjdhjd). All rights reserved.
2
+ *
3
+ * clock.ts: An injectable wall-clock seam - the current time and an abortable delay - so time-dependent code can be driven deterministically under test.
4
+ */
5
+ /**
6
+ * An injectable wall-clock time seam.
7
+ *
8
+ * Time-dependent code reads the platform time primitives it needs: the current epoch time (`Date.now()`) and a delay that can be cancelled (`node:timers/promises`
9
+ * `setTimeout`). Calling those directly bakes real wall-clock time into the code, so a test cannot exercise a pacing or timeout path without multi-second real waits, and
10
+ * `node:test`'s mock timers do not patch the `node:timers/promises` primitives. Holding a {@link Clock} instead - the abstraction over those primitives - inverts the
11
+ * dependency: production wires {@link systemClock}, whose `now()` IS `Date.now()` and whose `delay()` IS `node:timers/promises` `setTimeout`, so routing through the seam
12
+ * is behavior-neutral; a test wires a `TestClock` (see `clock-double.ts`) that advances virtual time explicitly, so the consumer's time-dependent path runs
13
+ * deterministically and instantly.
14
+ *
15
+ * This module imports `node:timers/promises` and is therefore Node-only (not browser-safe), like `util.ts`. A browser-targeted consumer cannot resolve that import.
16
+ *
17
+ * @module
18
+ */
19
+ import { setTimeout as delay } from "node:timers/promises";
20
+ /**
21
+ * The behavior-neutral production {@link Clock}: `now()` IS `Date.now()` and `delay()` IS `node:timers/promises` `setTimeout`. A consumer that routes its time reads
22
+ * through this clock instead of calling those primitives directly cannot observe any behavior change - it is the same two calls, one indirection removed at test time.
23
+ *
24
+ * @see Clock
25
+ *
26
+ * @category Utilities
27
+ */
28
+ export const systemClock = {
29
+ // `setTimeout(ms, value, options)` from `node:timers/promises`: pass `undefined` for the resolution value and forward `init` as the options so the caller's signal
30
+ // cancels the wait. `setTimeout(ms, undefined, opts)` resolves to `Promise<undefined>`, which is assignable to the `Promise<void>` the contract declares.
31
+ delay: (ms, init) => delay(ms, undefined, init),
32
+ now: () => Date.now()
33
+ };
34
+ //# sourceMappingURL=clock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clock.js","sourceRoot":"","sources":["../src/clock.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,UAAU,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAgC3D;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAU;IAEhC,mKAAmK;IACnK,0JAA0J;IAC1J,KAAK,EAAE,CAAC,EAAU,EAAE,IAA+B,EAAiB,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC;IACjG,GAAG,EAAE,GAAW,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;CAC9B,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * A container that aggregates disposable resources and disposes them, in reverse (last-in-first-out) order, when the stack itself is disposed.
3
+ *
4
+ * The class satisfies the platform `DisposableStack` interface by construction - the `implements` clause below binds it to `globalThis.DisposableStack`, so the
5
+ * compiler enforces that the name's promise (the platform contract) is kept at the definition site.
6
+ *
7
+ * @category Utilities
8
+ */
9
+ export declare class DisposableStack implements InstanceType<typeof globalThis.DisposableStack> {
10
+ #private;
11
+ readonly [Symbol.toStringTag] = "DisposableStack";
12
+ /**
13
+ * Whether this stack has been disposed.
14
+ */
15
+ get disposed(): boolean;
16
+ /**
17
+ * Register a {@link Disposable} whose `[Symbol.dispose]()` runs when this stack is disposed, returning the value unchanged.
18
+ *
19
+ * `null` and `undefined` pass through without being registered. The dispose method is captured at registration time and invoked with the value as its receiver, so
20
+ * a later mutation of `value[Symbol.dispose]` cannot change what runs.
21
+ *
22
+ * @param value - The resource to register, or `null`/`undefined` to skip registration.
23
+ * @returns The provided `value`.
24
+ */
25
+ use<T extends Disposable | null | undefined>(value: T): T;
26
+ /**
27
+ * Register a value together with an explicit disposal callback, returning the value unchanged. The callback is invoked with the value as its first argument when
28
+ * this stack is disposed.
29
+ *
30
+ * @param value - The value to associate with the callback.
31
+ * @param onDispose - The disposal callback, invoked with `value`.
32
+ * @returns The provided `value`.
33
+ */
34
+ adopt<T>(value: T, onDispose: (value: T) => void): T;
35
+ /**
36
+ * Register a callback to run when this stack is disposed.
37
+ *
38
+ * @param onDispose - The callback to run on disposal.
39
+ */
40
+ defer(onDispose: () => void): void;
41
+ /**
42
+ * Move every pending disposer out of this stack into a fresh {@link DisposableStack}, preserving registration order, and mark this stack disposed without running
43
+ * anything. This is the "commit" primitive: after a successful acquire sequence, moving the disposers away disarms this stack's scope-bound cleanup while handing
44
+ * responsibility for those resources to the returned stack.
45
+ *
46
+ * @returns A new stack owning the transferred disposers.
47
+ */
48
+ move(): DisposableStack;
49
+ /**
50
+ * Dispose every registered resource in reverse (last-in-first-out) order. A second call is a no-op. Every disposer runs even when an earlier one throws: a single
51
+ * failure is rethrown after the sweep completes, and multiple failures chain through `SuppressedError` (the newest failure wrapping the accumulated one).
52
+ */
53
+ dispose(): void;
54
+ /**
55
+ * Dispose this stack. Enables `using` semantics by delegating to {@link dispose}.
56
+ */
57
+ [Symbol.dispose](): void;
58
+ }
59
+ //# sourceMappingURL=disposable-stack.d.ts.map
@@ -0,0 +1,155 @@
1
+ /* Copyright(C) 2017-2026, HJD (https://github.com/hjdhjd). All rights reserved.
2
+ *
3
+ * disposable-stack.ts: An in-package stand-in for the platform `DisposableStack` global that the library's own port allocator relies on.
4
+ */
5
+ // Build a `SuppressedError` that links a newer disposal failure to the error it supersedes, matching the spec's multi-failure aggregation shape. We read the platform
6
+ // `SuppressedError` global fresh on every call rather than caching a reference, because that constructor is itself part of the Node 24 explicit-resource-management
7
+ // surface and can be absent on the engines floor this module exists to serve. When it is missing we synthesize a structurally-identical stand-in - an `Error` whose
8
+ // name is "SuppressedError" carrying `error` and `suppressed` - so multi-failure aggregation is observably identical whether or not the global is present. The typed
9
+ // optional read tells the truth the platform lib cannot: on this engines floor the global may not exist.
10
+ function createSuppressedError(error, suppressed) {
11
+ const suppressedErrorConstructor = globalThis.SuppressedError;
12
+ if (suppressedErrorConstructor !== undefined) {
13
+ return new suppressedErrorConstructor(error, suppressed);
14
+ }
15
+ const synthesized = new Error();
16
+ synthesized.error = error;
17
+ synthesized.name = "SuppressedError";
18
+ synthesized.suppressed = suppressed;
19
+ return synthesized;
20
+ }
21
+ /**
22
+ * A container that aggregates disposable resources and disposes them, in reverse (last-in-first-out) order, when the stack itself is disposed.
23
+ *
24
+ * The class satisfies the platform `DisposableStack` interface by construction - the `implements` clause below binds it to `globalThis.DisposableStack`, so the
25
+ * compiler enforces that the name's promise (the platform contract) is kept at the definition site.
26
+ *
27
+ * @category Utilities
28
+ */
29
+ export class DisposableStack {
30
+ // The pending disposers in registration order. A `null` array is the disposed state: pairing "disposed" with "no pending disposers" in a single field makes the
31
+ // disposed-with-pending-work state unrepresentable, so every member checks this one field to decide whether it may still register or run work.
32
+ #disposers = [];
33
+ // The platform tag reported by `Object.prototype.toString`, matching the native class.
34
+ [Symbol.toStringTag] = "DisposableStack";
35
+ /**
36
+ * Whether this stack has been disposed.
37
+ */
38
+ get disposed() {
39
+ return this.#disposers === null;
40
+ }
41
+ /**
42
+ * Register a {@link Disposable} whose `[Symbol.dispose]()` runs when this stack is disposed, returning the value unchanged.
43
+ *
44
+ * `null` and `undefined` pass through without being registered. The dispose method is captured at registration time and invoked with the value as its receiver, so
45
+ * a later mutation of `value[Symbol.dispose]` cannot change what runs.
46
+ *
47
+ * @param value - The resource to register, or `null`/`undefined` to skip registration.
48
+ * @returns The provided `value`.
49
+ */
50
+ use(value) {
51
+ if (this.#disposers === null) {
52
+ throw new ReferenceError("Cannot use a resource on a disposed DisposableStack.");
53
+ }
54
+ // Skip registration for null and undefined, returning them unchanged. We test undefined with `typeof` so the generic parameter narrows cleanly to a Disposable for
55
+ // the member access below.
56
+ if ((value === null) || (typeof value === "undefined")) {
57
+ return value;
58
+ }
59
+ // Capture the dispose method now, at registration time, matching the spec's registration-time capture... a later mutation of `value[Symbol.dispose]` must not change
60
+ // what runs. We read it through `unknown` because use() is a trust boundary: a value can satisfy the Disposable type nominally yet present a non-callable member at
61
+ // runtime, which the spec requires we reject with a TypeError.
62
+ const disposeMethod = value[Symbol.dispose];
63
+ if (typeof disposeMethod !== "function") {
64
+ throw new TypeError("The value passed to DisposableStack.use() is not disposable.");
65
+ }
66
+ const boundDispose = disposeMethod;
67
+ this.#disposers.push(() => {
68
+ boundDispose.call(value);
69
+ });
70
+ return value;
71
+ }
72
+ /**
73
+ * Register a value together with an explicit disposal callback, returning the value unchanged. The callback is invoked with the value as its first argument when
74
+ * this stack is disposed.
75
+ *
76
+ * @param value - The value to associate with the callback.
77
+ * @param onDispose - The disposal callback, invoked with `value`.
78
+ * @returns The provided `value`.
79
+ */
80
+ adopt(value, onDispose) {
81
+ if (this.#disposers === null) {
82
+ throw new ReferenceError("Cannot adopt a resource on a disposed DisposableStack.");
83
+ }
84
+ if (typeof onDispose !== "function") {
85
+ throw new TypeError("The onDispose callback passed to DisposableStack.adopt() is not a function.");
86
+ }
87
+ this.#disposers.push(() => onDispose(value));
88
+ return value;
89
+ }
90
+ /**
91
+ * Register a callback to run when this stack is disposed.
92
+ *
93
+ * @param onDispose - The callback to run on disposal.
94
+ */
95
+ defer(onDispose) {
96
+ if (this.#disposers === null) {
97
+ throw new ReferenceError("Cannot defer a callback on a disposed DisposableStack.");
98
+ }
99
+ if (typeof onDispose !== "function") {
100
+ throw new TypeError("The onDispose callback passed to DisposableStack.defer() is not a function.");
101
+ }
102
+ this.#disposers.push(onDispose);
103
+ }
104
+ /**
105
+ * Move every pending disposer out of this stack into a fresh {@link DisposableStack}, preserving registration order, and mark this stack disposed without running
106
+ * anything. This is the "commit" primitive: after a successful acquire sequence, moving the disposers away disarms this stack's scope-bound cleanup while handing
107
+ * responsibility for those resources to the returned stack.
108
+ *
109
+ * @returns A new stack owning the transferred disposers.
110
+ */
111
+ move() {
112
+ if (this.#disposers === null) {
113
+ throw new ReferenceError("Cannot move a disposed DisposableStack.");
114
+ }
115
+ const moved = new DisposableStack();
116
+ // Transfer the array by reference so order is preserved, then mark this stack disposed without running any disposer.
117
+ moved.#disposers = this.#disposers;
118
+ this.#disposers = null;
119
+ return moved;
120
+ }
121
+ /**
122
+ * Dispose every registered resource in reverse (last-in-first-out) order. A second call is a no-op. Every disposer runs even when an earlier one throws: a single
123
+ * failure is rethrown after the sweep completes, and multiple failures chain through `SuppressedError` (the newest failure wrapping the accumulated one).
124
+ */
125
+ dispose() {
126
+ if (this.#disposers === null) {
127
+ return;
128
+ }
129
+ // Detach the array and mark disposed before running anything, so a disposer that re-enters this stack observes the disposed state and cannot double-run work.
130
+ const disposers = this.#disposers;
131
+ this.#disposers = null;
132
+ let hasError = false;
133
+ let heldError;
134
+ // Reverse the detached array in place - we hold the only reference to it, so mutating it is safe - and run the disposers last-in-first-out.
135
+ for (const disposer of disposers.reverse()) {
136
+ try {
137
+ disposer();
138
+ }
139
+ catch (error) {
140
+ heldError = hasError ? createSuppressedError(error, heldError) : error;
141
+ hasError = true;
142
+ }
143
+ }
144
+ if (hasError) {
145
+ throw heldError;
146
+ }
147
+ }
148
+ /**
149
+ * Dispose this stack. Enables `using` semantics by delegating to {@link dispose}.
150
+ */
151
+ [Symbol.dispose]() {
152
+ this.dispose();
153
+ }
154
+ }
155
+ //# sourceMappingURL=disposable-stack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disposable-stack.js","sourceRoot":"","sources":["../src/disposable-stack.ts"],"names":[],"mappings":"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"}