homebridge-plugin-utils 1.34.0 → 2.0.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 (198) 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 +128 -0
  20. package/dist/backpressure.js +273 -0
  21. package/dist/backpressure.js.map +1 -0
  22. package/dist/cli/index.d.ts +95 -0
  23. package/dist/cli/index.js +355 -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/eslint-plugin/config.d.mts +193 -0
  32. package/dist/eslint-plugin/index.d.mts +2 -0
  33. package/dist/eslint-plugin/plugin.d.mts +87 -0
  34. package/dist/eslint-plugin/rules/blank-line-after-open-brace.d.mts +19 -0
  35. package/dist/eslint-plugin/rules/comment-style.d.mts +15 -0
  36. package/dist/eslint-plugin/rules/enforce-node-protocol.d.mts +18 -0
  37. package/dist/eslint-plugin/rules/paren-comparisons-in-logical.d.mts +15 -0
  38. package/dist/eslint-plugin/rules/split-type-imports.d.mts +16 -0
  39. package/dist/featureOptions-docs.d.ts +96 -0
  40. package/dist/featureOptions-docs.js +193 -0
  41. package/dist/featureOptions-docs.js.map +1 -0
  42. package/dist/featureOptions.d.ts +674 -0
  43. package/dist/featureOptions.js +870 -0
  44. package/dist/featureOptions.js.map +1 -0
  45. package/dist/ffmpeg/codecs.d.ts +256 -72
  46. package/dist/ffmpeg/codecs.js +477 -257
  47. package/dist/ffmpeg/codecs.js.map +1 -1
  48. package/dist/ffmpeg/dgram-util.d.ts +46 -0
  49. package/dist/ffmpeg/dgram-util.js +38 -0
  50. package/dist/ffmpeg/dgram-util.js.map +1 -0
  51. package/dist/ffmpeg/exec.d.ts +83 -64
  52. package/dist/ffmpeg/exec.js +77 -86
  53. package/dist/ffmpeg/exec.js.map +1 -1
  54. package/dist/ffmpeg/fmp4.d.ts +70 -4
  55. package/dist/ffmpeg/fmp4.js +100 -11
  56. package/dist/ffmpeg/fmp4.js.map +1 -1
  57. package/dist/ffmpeg/hap-enums.d.ts +214 -0
  58. package/dist/ffmpeg/hap-enums.js +92 -0
  59. package/dist/ffmpeg/hap-enums.js.map +1 -0
  60. package/dist/ffmpeg/index.d.ts +16 -9
  61. package/dist/ffmpeg/index.js +6 -0
  62. package/dist/ffmpeg/index.js.map +1 -1
  63. package/dist/ffmpeg/mp4-assembler.d.ts +120 -0
  64. package/dist/ffmpeg/mp4-assembler.js +387 -0
  65. package/dist/ffmpeg/mp4-assembler.js.map +1 -0
  66. package/dist/ffmpeg/mp4-parser.d.ts +94 -0
  67. package/dist/ffmpeg/mp4-parser.js +130 -0
  68. package/dist/ffmpeg/mp4-parser.js.map +1 -0
  69. package/dist/ffmpeg/options.d.ts +62 -149
  70. package/dist/ffmpeg/options.js +608 -499
  71. package/dist/ffmpeg/options.js.map +1 -1
  72. package/dist/ffmpeg/process.d.ts +143 -91
  73. package/dist/ffmpeg/process.js +406 -265
  74. package/dist/ffmpeg/process.js.map +1 -1
  75. package/dist/ffmpeg/record.d.ts +302 -188
  76. package/dist/ffmpeg/record.js +408 -560
  77. package/dist/ffmpeg/record.js.map +1 -1
  78. package/dist/ffmpeg/recording-process-double.d.ts +144 -0
  79. package/dist/ffmpeg/recording-process-double.js +168 -0
  80. package/dist/ffmpeg/recording-process-double.js.map +1 -0
  81. package/dist/ffmpeg/rtp-parser.d.ts +70 -0
  82. package/dist/ffmpeg/rtp-parser.js +77 -0
  83. package/dist/ffmpeg/rtp-parser.js.map +1 -0
  84. package/dist/ffmpeg/rtp.d.ts +198 -141
  85. package/dist/ffmpeg/rtp.js +473 -244
  86. package/dist/ffmpeg/rtp.js.map +1 -1
  87. package/dist/ffmpeg/settings.d.ts +5 -1
  88. package/dist/ffmpeg/settings.js +20 -2
  89. package/dist/ffmpeg/settings.js.map +1 -1
  90. package/dist/ffmpeg/stream.d.ts +57 -107
  91. package/dist/ffmpeg/stream.js +121 -148
  92. package/dist/ffmpeg/stream.js.map +1 -1
  93. package/dist/formatters.d.ts +106 -0
  94. package/dist/formatters.js +174 -0
  95. package/dist/formatters.js.map +1 -0
  96. package/dist/homebridge-enums.d.ts +30 -0
  97. package/dist/homebridge-enums.js +17 -0
  98. package/dist/homebridge-enums.js.map +1 -0
  99. package/dist/index.d.ts +12 -5
  100. package/dist/index.js +8 -2
  101. package/dist/index.js.map +1 -1
  102. package/dist/logclient/auth.d.ts +114 -0
  103. package/dist/logclient/auth.js +199 -0
  104. package/dist/logclient/auth.js.map +1 -0
  105. package/dist/logclient/cli-run.d.ts +76 -0
  106. package/dist/logclient/cli-run.js +639 -0
  107. package/dist/logclient/cli-run.js.map +1 -0
  108. package/dist/logclient/cli.d.ts +3 -0
  109. package/dist/logclient/cli.js +97 -0
  110. package/dist/logclient/cli.js.map +1 -0
  111. package/dist/logclient/client.d.ts +145 -0
  112. package/dist/logclient/client.js +600 -0
  113. package/dist/logclient/client.js.map +1 -0
  114. package/dist/logclient/config.d.ts +173 -0
  115. package/dist/logclient/config.js +199 -0
  116. package/dist/logclient/config.js.map +1 -0
  117. package/dist/logclient/endpoints.d.ts +54 -0
  118. package/dist/logclient/endpoints.js +73 -0
  119. package/dist/logclient/endpoints.js.map +1 -0
  120. package/dist/logclient/filter.d.ts +45 -0
  121. package/dist/logclient/filter.js +51 -0
  122. package/dist/logclient/filter.js.map +1 -0
  123. package/dist/logclient/frame.d.ts +93 -0
  124. package/dist/logclient/frame.js +203 -0
  125. package/dist/logclient/frame.js.map +1 -0
  126. package/dist/logclient/index.d.ts +31 -0
  127. package/dist/logclient/index.js +12 -0
  128. package/dist/logclient/index.js.map +1 -0
  129. package/dist/logclient/parser.d.ts +211 -0
  130. package/dist/logclient/parser.js +393 -0
  131. package/dist/logclient/parser.js.map +1 -0
  132. package/dist/logclient/rest.d.ts +41 -0
  133. package/dist/logclient/rest.js +111 -0
  134. package/dist/logclient/rest.js.map +1 -0
  135. package/dist/logclient/settings.d.ts +15 -0
  136. package/dist/logclient/settings.js +64 -0
  137. package/dist/logclient/settings.js.map +1 -0
  138. package/dist/logclient/socket-double.d.ts +201 -0
  139. package/dist/logclient/socket-double.js +384 -0
  140. package/dist/logclient/socket-double.js.map +1 -0
  141. package/dist/logclient/socket.d.ts +257 -0
  142. package/dist/logclient/socket.js +620 -0
  143. package/dist/logclient/socket.js.map +1 -0
  144. package/dist/logclient/stitch.d.ts +83 -0
  145. package/dist/logclient/stitch.js +146 -0
  146. package/dist/logclient/stitch.js.map +1 -0
  147. package/dist/logclient/time-expression.d.ts +42 -0
  148. package/dist/logclient/time-expression.js +181 -0
  149. package/dist/logclient/time-expression.js.map +1 -0
  150. package/dist/logclient/time-window.d.ts +38 -0
  151. package/dist/logclient/time-window.js +53 -0
  152. package/dist/logclient/time-window.js.map +1 -0
  153. package/dist/logclient/types.d.ts +107 -0
  154. package/dist/logclient/types.js +6 -0
  155. package/dist/logclient/types.js.map +1 -0
  156. package/dist/mqttClient.d.ts +287 -0
  157. package/dist/mqttClient.js +433 -0
  158. package/dist/mqttClient.js.map +1 -0
  159. package/dist/service.d.ts +64 -15
  160. package/dist/service.js +93 -66
  161. package/dist/service.js.map +1 -1
  162. package/dist/ui/featureOptions.js +870 -0
  163. package/dist/ui/featureOptions.js.map +1 -0
  164. package/dist/ui/formatters.js +174 -0
  165. package/dist/ui/formatters.js.map +1 -0
  166. package/dist/ui/pluginConfigSession.mjs +141 -0
  167. package/dist/ui/webUi-featureOptions/categoryState.mjs +135 -0
  168. package/dist/ui/webUi-featureOptions/effects/keyboard.mjs +61 -0
  169. package/dist/ui/webUi-featureOptions/effects/persist.mjs +226 -0
  170. package/dist/ui/webUi-featureOptions/effects/theme.mjs +398 -0
  171. package/dist/ui/webUi-featureOptions/effects/tokens.mjs +152 -0
  172. package/dist/ui/webUi-featureOptions/rendering.mjs +431 -0
  173. package/dist/ui/webUi-featureOptions/selectors.mjs +360 -0
  174. package/dist/ui/webUi-featureOptions/state.mjs +319 -0
  175. package/dist/ui/webUi-featureOptions/store.mjs +181 -0
  176. package/dist/ui/webUi-featureOptions/utils.mjs +200 -0
  177. package/dist/ui/webUi-featureOptions/views/connectionError.mjs +152 -0
  178. package/dist/ui/webUi-featureOptions/views/deviceInfo.mjs +80 -0
  179. package/dist/ui/webUi-featureOptions/views/header.mjs +77 -0
  180. package/dist/ui/webUi-featureOptions/views/nav.mjs +327 -0
  181. package/dist/ui/webUi-featureOptions/views/options.mjs +521 -0
  182. package/dist/ui/webUi-featureOptions/views/search.mjs +395 -0
  183. package/dist/ui/webUi-featureOptions.mjs +677 -0
  184. package/dist/ui/webUi.mjs +192 -87
  185. package/dist/util.d.ts +597 -45
  186. package/dist/util.js +787 -68
  187. package/dist/util.js.map +1 -1
  188. package/package.json +33 -15
  189. package/build/eslint-rules.mjs +0 -511
  190. package/dist/featureoptions.d.ts +0 -264
  191. package/dist/featureoptions.js +0 -480
  192. package/dist/featureoptions.js.map +0 -1
  193. package/dist/mqttclient.d.ts +0 -178
  194. package/dist/mqttclient.js +0 -310
  195. package/dist/mqttclient.js.map +0 -1
  196. package/dist/ui/featureoptions.js +0 -480
  197. package/dist/ui/featureoptions.js.map +0 -1
  198. package/dist/ui/webUi-featureoptions.mjs +0 -3765
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Shared, dependency-light type definitions for the Homebridge UI log client.
3
+ *
4
+ * This module is the single home for the log client's domain vocabulary - the record shape every parser/filter/stitch path produces and consumes, the credential
5
+ * discriminated union, and the request shapes that select a transport channel. Keeping these here (rather than scattered across the modules that use them) makes the
6
+ * vocabulary discoverable in one place and lets the pure leaf modules (`parser.ts`, `filter.ts`, `stitch.ts`) and the transports share one definition rather than
7
+ * re-declaring overlapping shapes.
8
+ *
9
+ * @module
10
+ */
11
+ import type { Nullable } from "../util.ts";
12
+ /**
13
+ * The severity level of a single log line.
14
+ *
15
+ * Severity in homebridge-config-ui-x is conveyed only by the ANSI color of the line, not by a textual label: `31` (red) is error, `33` (yellow) is warn, `90` (bright
16
+ * black) is debug, `32` (green) is success, and an uncolored line is info. When the Homebridge process runs without `FORCE_COLOR` the color is usually absent, so a
17
+ * record's level is frequently `null` (see {@link LogRecord.level}); a present level always maps to one of these five values.
18
+ *
19
+ * @category Log Client
20
+ */
21
+ export type LogLevel = "debug" | "error" | "info" | "success" | "warn";
22
+ /**
23
+ * A single parsed log line.
24
+ *
25
+ * Every field except `message` and `raw` is {@link Nullable} because the underlying log format makes them optional: the timestamp and plugin name are present only when
26
+ * the line carries the conventional `[timestamp] [Plugin Name] message` bracketed prefix, and the level is present only when ANSI color survives to the client. `raw`
27
+ * preserves the original line with all ANSI escapes intact (so a `--raw` consumer can reproduce the server's coloring), while `message` is the human-readable text with
28
+ * ANSI stripped and the bracketed prefix removed.
29
+ *
30
+ * @property level - The severity derived from the line's ANSI color, or `null` when the line carried no recognizable color (the common case under hb-service/systemd
31
+ * without `FORCE_COLOR`).
32
+ * @property message - The line's human-readable text: ANSI-stripped and with the leading `[timestamp] [Plugin Name]` brackets removed when present.
33
+ * @property plugin - The plugin name from the second bracketed field, or `null` when the line carried no plugin bracket.
34
+ * @property raw - The original line exactly as received, with ANSI escapes and the bracketed prefix intact, but with newline terminators removed.
35
+ * @property timestamp - The timestamp text from the first bracketed field, or `null` when the line carried no timestamp bracket.
36
+ *
37
+ * @category Log Client
38
+ */
39
+ export interface LogRecord {
40
+ readonly level: Nullable<LogLevel>;
41
+ readonly message: string;
42
+ readonly plugin: Nullable<string>;
43
+ readonly raw: string;
44
+ readonly timestamp: Nullable<string>;
45
+ }
46
+ /**
47
+ * The credentials used to authenticate against the homebridge-config-ui-x API, modeled as a discriminated union so invalid combinations are unrepresentable.
48
+ *
49
+ * The arms correspond to the authentication paths the server exposes: a pre-acquired bearer token (`token`), an interactive username/password login with an
50
+ * optional one-time passcode (`password`), and the no-authentication path (`noauth`) available only when the web UI is configured with `auth: "none"`. Expressing this
51
+ * as a DU rather than a bag of optional fields means password-without-username, token-plus-password, and other nonsensical mixes cannot be constructed, and the `otp`
52
+ * field has exactly one home where it is meaningful.
53
+ *
54
+ * @category Log Client
55
+ */
56
+ export type LogClientCredentials = {
57
+ readonly kind: "noauth";
58
+ } | {
59
+ readonly kind: "password";
60
+ readonly otp?: string;
61
+ readonly password: string;
62
+ readonly username: string;
63
+ } | {
64
+ readonly kind: "token";
65
+ readonly token: string;
66
+ };
67
+ /**
68
+ * How many log lines a history or seeded request should retain: an explicit count, or the sentinel `"all"` for the entire available history.
69
+ *
70
+ * The sentinel is a distinct literal rather than a magic number (e.g., `-1` or `Infinity`) so the "give me everything" intent is explicit at every call site and cannot
71
+ * be confused with a real count. The number form is interpreted as "the most recent N lines."
72
+ *
73
+ * @category Log Client
74
+ */
75
+ export type LogQuantity = number | "all";
76
+ /**
77
+ * A request describing which log content to deliver and over which channel, modeled as a discriminated union on `mode`.
78
+ *
79
+ * The modes map to the cost model: `follow` is a pure live tail over the socket (cheap, incremental); `history` is a one-shot retrieval of `quantity` past lines
80
+ * (paid via the REST whole-file download when the quantity is deep); `follow-history` seeds `quantity` past lines and then continues live, stitching the two so the
81
+ * boundary neither drops nor (beyond a bounded overlap) duplicates lines; and `window` is a time-bounded `[since, until]` query that the engine serves from the socket
82
+ * seed when the seed strictly covers the window, hedged against a parallel abortable whole-file download that wins when it cannot. Carrying `quantity` only on
83
+ * the arms that need it keeps a bare `follow` from having to invent a meaningless count.
84
+ *
85
+ * The `window` arm carries `follow` as a field rather than splitting into two modes because both the one-shot (`follow: false`) and the live (`follow: true`) windowed
86
+ * cases share the ENTIRE gate / seed / hedge cost model and differ only in termination: a one-shot terminates when the window's content has been served (a wall-clock
87
+ * quiescence terminator for the seed-served path, the finite download's natural end for the fallback path), while a `follow` window continues live indefinitely. `since`
88
+ * is the inclusive lower bound (`null` for an unbounded-below `--until`-only window, which the seed can never cover); `until` is the user's EXPLICIT upper bound (`null`
89
+ * for a bare `--since`, where the engine fills in the one-shot snapshot horizon itself rather than the request carrying an implicit "now").
90
+ *
91
+ * @category Log Client
92
+ */
93
+ export type TailRequest = {
94
+ readonly mode: "follow";
95
+ } | {
96
+ readonly mode: "follow-history";
97
+ readonly quantity: LogQuantity;
98
+ } | {
99
+ readonly mode: "history";
100
+ readonly quantity: LogQuantity;
101
+ } | {
102
+ readonly follow: boolean;
103
+ readonly mode: "window";
104
+ readonly since: Nullable<number>;
105
+ readonly until: Nullable<number>;
106
+ };
107
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,6 @@
1
+ /* Copyright(C) 2017-2026, HJD (https://github.com/hjdhjd). All rights reserved.
2
+ *
3
+ * logclient/types.ts: Shared type definitions for the Homebridge UI log client.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/logclient/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,287 @@
1
+ import type { HomebridgePluginLogging } from "./util.ts";
2
+ /**
3
+ * A handler for raw MQTT messages delivered on a subscribed topic.
4
+ *
5
+ * @param payload - The message payload as received from the broker.
6
+ *
7
+ * @category Utilities
8
+ */
9
+ export type MqttHandler = (payload: Buffer) => Promise<void> | void;
10
+ /**
11
+ * A handler invoked by {@link MqttClient.subscribeGet} when a "true" message arrives on the `/get` topic. Returns the current value as a string that will be published
12
+ * on the parent topic as the response.
13
+ *
14
+ * @category Utilities
15
+ */
16
+ export type MqttGetHandler = () => string;
17
+ /**
18
+ * A handler invoked by {@link MqttClient.subscribeSet} when a value is received on the `/set` topic.
19
+ *
20
+ * Receives three arguments:
21
+ *
22
+ * - `value` - the lowercased normalized form, convenient for comparisons against fixtures like `"true"` / `"on"`.
23
+ * - `rawValue` - the raw message string, for cases where case or surrounding whitespace matters.
24
+ * - `signal` - an {@link AbortSignal} that aborts when the subscription's connection-level signal fires or (if configured) the per-invocation timeout elapses.
25
+ * Signal-aware setters forward this to any cancellation-capable API they call (`fetch`, `events.once`, `node:timers/promises`, etc.) so the setter's work
26
+ * actually stops when the wrapper times out. Setters that ignore the signal continue to run after timeout, but the subscription slot is released either
27
+ * way; nothing is structurally blocked by a hanging setter.
28
+ *
29
+ * **Log-routing contract.** How the setter settles determines which log line `subscribeSet` emits:
30
+ *
31
+ * - **Return normally** (work completed successfully) - logs INFO `"MQTT: set message received for X: value."`.
32
+ * - **Throw a non-abort error** (work failed for a reason unrelated to cancellation) - logs ERROR `"MQTT: error setting X to value: message."`.
33
+ * - **Throw while the composed signal is already aborted** (the connection-level abort or the per-invocation timeout, whichever fired first) - logs WARN
34
+ * `"MQTT: set handler for X was cancelled before completion."`, regardless of what value is thrown. A setter that catches its own abort and returns normally
35
+ * is indistinguishable to the wrapper from a successful completion, which is why a signal-aware setter that wants cancellation reflected in the log stream
36
+ * should rethrow once it observes the signal has aborted, rather than swallow it.
37
+ *
38
+ * @category Utilities
39
+ */
40
+ export type MqttSetHandler = (value: string, rawValue: string, signal: AbortSignal) => Promise<void> | void;
41
+ /**
42
+ * Static configuration for an {@link MqttClient}. Captures the broker connection parameters and the topic-prefix convention the client applies to every topic it
43
+ * touches.
44
+ *
45
+ * @property brokerUrl - The MQTT broker URL (for example, `"mqtt://localhost:1883"`).
46
+ * @property log - Logger used for connection and publish/subscribe tracing.
47
+ * @property reconnectInterval - Seconds to wait between transient reconnect attempts. Defaults to 60.
48
+ * @property topicPrefix - Prefix prepended to every topic the client publishes or subscribes to. The caller is responsible for the remaining path structure;
49
+ * this class never reinterprets the topic beyond concatenation.
50
+ *
51
+ * @category Utilities
52
+ */
53
+ export interface MqttConfig {
54
+ brokerUrl: string;
55
+ log: HomebridgePluginLogging;
56
+ reconnectInterval?: number;
57
+ topicPrefix: string;
58
+ }
59
+ /**
60
+ * Construction-time options for {@link MqttClient}.
61
+ *
62
+ * @property signal - Optional parent {@link AbortSignal} composed with the client's internal controller. When the parent aborts, the MQTT connection ends permanently.
63
+ *
64
+ * @category Utilities
65
+ */
66
+ export interface MqttClientInit {
67
+ signal?: AbortSignal;
68
+ }
69
+ /**
70
+ * Result of routing a transport-level MQTT error through {@link routeMqttBrokerError}. Returned to the caller so the wiring layer (the `client.on("error", ...)`
71
+ * handler in {@link MqttClient}) can apply the side effect on its own state. Keeping the routing pure - logging plus a flag - lets the routing logic be tested in
72
+ * isolation against synthetic error inputs, without standing up a broker or injecting events into the underlying mqtt.js client.
73
+ *
74
+ * @property endTransport - `true` when the error code requires forcibly ending the underlying transport (the mqtt.js client should not attempt reconnect). Mirrors
75
+ * the architectural rule that ENOTFOUND is the one transport error reconnect cannot recover from.
76
+ *
77
+ * @category Utilities
78
+ */
79
+ export interface MqttBrokerErrorResult {
80
+ endTransport: boolean;
81
+ }
82
+ /**
83
+ * Route a transport-level MQTT error to the appropriate log line and signal whether the underlying transport should be ended. Pure function: no class state, no
84
+ * mqtt.js handles, no closure over the live client. The wiring layer in {@link MqttClient} forwards every `client.on("error", ...)` invocation through here and acts
85
+ * on the returned `endTransport` flag.
86
+ *
87
+ * The routing paths mirror the transport-error categories HBPU distinguishes:
88
+ *
89
+ * - `ECONNREFUSED` - the broker host is up but no listener accepts the connection. Recoverable; auto-reconnect handles it.
90
+ * - `ECONNRESET` - the broker accepted then dropped the connection. Recoverable; auto-reconnect handles it.
91
+ * - `ENOTFOUND` - DNS could not resolve the broker hostname. Non-recoverable - retrying the same hostname will keep failing - so we end the transport permanently
92
+ * and emit a standalone log line without the retry-cadence suffix.
93
+ * - default - any other error code (or none). Logged through the retry-cadence formatter with `util.inspect` of the error, so a future mqtt.js error code we
94
+ * did not anticipate still surfaces in the log stream rather than being silently swallowed.
95
+ *
96
+ * @param error - The error event payload from the underlying mqtt.js client.
97
+ * @param log - Logger used to emit the routed message.
98
+ * @param reconnectInterval - Configured reconnect interval (in seconds) used to format the retry-cadence suffix.
99
+ *
100
+ * @returns A {@link MqttBrokerErrorResult} indicating whether the wiring layer should end the transport.
101
+ *
102
+ * @category Utilities
103
+ */
104
+ export declare function routeMqttBrokerError(error: NodeJS.ErrnoException, log: HomebridgePluginLogging, reconnectInterval: number): MqttBrokerErrorResult;
105
+ /**
106
+ * Outcome of a getter-driven response publish issued by {@link MqttClient.subscribeGet}. Discriminated union: `ok: true` after a successful publish, `ok: false` with
107
+ * the captured error after a failure. Passed to {@link logGetterPublishOutcome} so the routing logic between the success and failure log lines is testable in
108
+ * isolation against synthetic outcomes - the same architectural pattern {@link routeMqttBrokerError} uses for transport-error log routing.
109
+ *
110
+ * @category Utilities
111
+ */
112
+ export type GetterPublishOutcome = {
113
+ readonly ok: true;
114
+ } | {
115
+ readonly error: unknown;
116
+ readonly ok: false;
117
+ };
118
+ /**
119
+ * Route the outcome of a `subscribeGet` response publish to the appropriate log line. Pure function: no class state, no mqtt.js handles, no closure over the live
120
+ * client. The wiring in {@link MqttClient.subscribeGet} forwards each `.then` / `.catch` settlement here, and tests cover both branches by calling the function
121
+ * directly with synthetic `{ ok: true }` and `{ ok: false, error: ... }` outcomes - bypassing the real-broker substrate where a forced QoS-0 publish failure would
122
+ * require contrived socket-level setup that is not worth the test-architecture complexity.
123
+ *
124
+ * @param log - Logger that receives the routed message.
125
+ * @param type - Human-readable label (the `type` argument the caller passed to `subscribeGet`).
126
+ * @param outcome - The publish outcome. See {@link GetterPublishOutcome}.
127
+ *
128
+ * @category Utilities
129
+ */
130
+ export declare function logGetterPublishOutcome(log: HomebridgePluginLogging, type: string, outcome: GetterPublishOutcome): void;
131
+ /**
132
+ * Per-subscription options accepted by {@link MqttClient.subscribe}, {@link MqttClient.subscribeGet}, and {@link MqttClient.subscribeSet}.
133
+ *
134
+ * @property signal - Optional {@link AbortSignal}. When it aborts, the specific handler is removed and (if it was the last handler on the topic) the underlying MQTT
135
+ * subscription is dropped. Composes with the connection-level signal: a client-level abort removes every handler regardless of per-subscription
136
+ * state.
137
+ *
138
+ * @category Utilities
139
+ */
140
+ export interface MqttSubscribeInit {
141
+ signal?: AbortSignal;
142
+ }
143
+ /**
144
+ * Per-subscription options accepted by {@link MqttClient.subscribeSet}.
145
+ *
146
+ * @property signal - Optional {@link AbortSignal} that auto-unsubscribes this handler. See {@link MqttSubscribeInit}.
147
+ * @property timeout - Optional timeout, in milliseconds, applied to each invocation of the user-supplied setter. When the setter takes longer than this, the
148
+ * invocation is cancelled and a warning is logged. Omit for no timeout - the setter still unwinds if the connection-level signal aborts, via
149
+ * {@link runWithAbort}.
150
+ *
151
+ * @category Utilities
152
+ */
153
+ export interface MqttSubscribeSetInit {
154
+ signal?: AbortSignal;
155
+ timeout?: number;
156
+ }
157
+ /**
158
+ * Per-publish options accepted by {@link MqttClient.publish}.
159
+ *
160
+ * @property signal - Optional {@link AbortSignal}. When it aborts before the broker acknowledges the publish, the returned promise rejects with `signal.reason`.
161
+ * Composes with the connection-level signal.
162
+ *
163
+ * @category Utilities
164
+ */
165
+ export interface MqttPublishInit {
166
+ signal?: AbortSignal;
167
+ }
168
+ /**
169
+ * Signal-driven MQTT client with automatic topic-prefix management, composed connection lifetime, and per-operation signal support.
170
+ *
171
+ * @example
172
+ *
173
+ * ```ts
174
+ * import { MqttClient } from "homebridge-plugin-utils";
175
+ *
176
+ * await using mqtt = new MqttClient({ brokerUrl: "mqtt://localhost:1883", log, topicPrefix: "homebridge" }, { signal: platform.signal });
177
+ *
178
+ * // A subscription that auto-unsubscribes on the per-feature signal.
179
+ * const feature = new AbortController();
180
+ *
181
+ * mqtt.subscribe("device1/status", (payload) => log.info("Status: %s.", payload.toString()), { signal: feature.signal });
182
+ *
183
+ * // Abort-aware publish.
184
+ * await mqtt.publish("device1/status", "on");
185
+ * ```
186
+ *
187
+ * @category Utilities
188
+ */
189
+ export declare class MqttClient implements AsyncDisposable {
190
+ #private;
191
+ /**
192
+ * The composed abort signal representing this client's lifetime. Aborts exactly once when {@link MqttClient.abort} is called or when the parent signal fires.
193
+ */
194
+ readonly signal: AbortSignal;
195
+ /**
196
+ * Construct and start a new MQTT client.
197
+ *
198
+ * Connection is initiated synchronously as part of construction; there is no separate `connect()` step. A synchronous failure from mqtt.js (typically an invalid
199
+ * broker URL) surfaces as an `Error` wrapping the underlying cause, so a misconfigured plugin fails loudly instead of living in a zombie state. Network-level
200
+ * failures (an unreachable broker reachable by a valid URL) do not throw - they surface asynchronously through the client's `error` event, are logged, and trigger
201
+ * mqtt.js's built-in auto-reconnect until {@link MqttClient.abort} or a parent signal ends the client for good. A pre-aborted parent signal still constructs
202
+ * a client (so `#mqtt` remains a class invariant) and then immediately runs the regular teardown path.
203
+ *
204
+ * @param config - Static broker / topic configuration. See {@link MqttConfig}.
205
+ * @param init - Optional init options. See {@link MqttClientInit}.
206
+ *
207
+ * @throws `Error` (with the underlying mqtt.js error attached as `cause`) when mqtt.js's `connect()` fails synchronously.
208
+ */
209
+ constructor(config: MqttConfig, init?: MqttClientInit);
210
+ /**
211
+ * Publish `payload` to `topic`, returning a promise that resolves when the broker acknowledges the publish, or rejects on failure or abort.
212
+ *
213
+ * The topic is prefixed with the configured {@link MqttConfig.topicPrefix} before being sent; callers supply the topic tail (for example, `"device1/status"`).
214
+ *
215
+ * @param topic - The relative topic (tail) to publish to.
216
+ * @param payload - The payload to publish. Buffers and strings are passed through unchanged.
217
+ * @param init - Optional per-publish options. See {@link MqttPublishInit}.
218
+ *
219
+ * @returns A promise that resolves once the broker acknowledges, or rejects on error or abort.
220
+ */
221
+ publish(topic: string, payload: Buffer | string, init?: MqttPublishInit): Promise<void>;
222
+ /**
223
+ * Subscribe to `topic` with the given handler. The topic is prefixed with the configured {@link MqttConfig.topicPrefix} before being registered with the broker.
224
+ * Multiple handlers may subscribe to the same topic; each gets independent delivery.
225
+ *
226
+ * @param topic - The relative topic (tail) to subscribe to.
227
+ * @param handler - Callback invoked with each received payload.
228
+ * @param init - Optional per-subscription options. See {@link MqttSubscribeInit}.
229
+ */
230
+ subscribe(topic: string, handler: MqttHandler, init?: MqttSubscribeInit): void;
231
+ /**
232
+ * Subscribe to the `/get` child of `topic`. When a `"true"` message arrives on the get topic, the provided `getValue` callback runs and its return value is
233
+ * published back on the parent topic. The classic HomeKit "get" pattern, wrapped once.
234
+ *
235
+ * @param topic - The relative topic (tail); the `/get` suffix is appended automatically.
236
+ * @param type - Human-readable label used in log messages (for example, `"Temperature"`).
237
+ * @param getValue - Callback returning the current value as a string, invoked on each incoming `"true"` message.
238
+ * @param init - Optional per-subscription options. See {@link MqttSubscribeInit}.
239
+ */
240
+ subscribeGet(topic: string, type: string, getValue: MqttGetHandler, init?: MqttSubscribeInit): void;
241
+ /**
242
+ * Subscribe to the `/set` child of `topic`. Each incoming message invokes `setValue` with the lowercased normalized value, the raw message string, and an
243
+ * {@link AbortSignal} that composes the connection-level signal with the optional per-invocation `timeout`. Signal-aware setters forward that signal to cancellation-
244
+ * capable APIs so the setter's work actually stops when the timeout elapses or the client aborts; signal-unaware setters continue to run but the subscription slot
245
+ * is released either way, so a hanging setter cannot tie up the slot indefinitely.
246
+ *
247
+ * @param topic - The relative topic (tail); the `/set` suffix is appended automatically.
248
+ * @param type - Human-readable label used in log messages.
249
+ * @param setValue - Callback invoked with each received value. Receives three arguments: `(value, rawValue, signal)`. See {@link MqttSetHandler}.
250
+ * @param init - Optional per-subscription options including a handler-invocation `timeout`. See {@link MqttSubscribeSetInit}.
251
+ */
252
+ subscribeSet(topic: string, type: string, setValue: MqttSetHandler, init?: MqttSubscribeSetInit): void;
253
+ /**
254
+ * Unsubscribe all handlers for the specified `(id, topic)` tuple. Reconstructs the topic using the configured {@link MqttConfig.topicPrefix}, removes the
255
+ * subscription from the internal map, and issues the wire-level unsubscribe. Preserved as a separate imperative verb for the mid-session feature-toggle pattern
256
+ * where the caller has the `(id, topic)` tuple but never retained a dedicated controller.
257
+ *
258
+ * Deliberately does not accept a `{ signal }` option: unsubscribe is synchronous and has nothing to cancel, and exposing a vestigial signal would suggest a
259
+ * cancellation semantic the method cannot deliver. Callers composing teardown through a signal remove handlers by aborting the per-subscription signal they passed
260
+ * to `subscribe*` instead.
261
+ *
262
+ * @param id - The device or accessory identifier portion of the topic. An empty string short-circuits the whole call.
263
+ * @param topic - The topic tail relative to the id.
264
+ */
265
+ unsubscribe(id: string, topic: string): void;
266
+ /**
267
+ * Abort the client and tear the connection down. Defaults to `HbpuAbortError("shutdown")` when no reason is supplied; explicit reasons pass through unchanged.
268
+ *
269
+ * Safe to call more than once. After this runs, every subsequent `publish`, `subscribe*`, or `unsubscribe` call is a no-op.
270
+ *
271
+ * @param reason - Optional abort reason. Typically an {@link HbpuAbortError}; platform errors also interoperate by convention.
272
+ */
273
+ abort(reason?: unknown): void;
274
+ /**
275
+ * `AsyncDisposable` implementation. Aborts the client (defaulting to `"shutdown"`), which tears the MQTT connection down and rejects any pending publishes through
276
+ * the regular teardown path.
277
+ *
278
+ * @returns A promise that resolves once teardown has been scheduled. MQTT.js's `end(true)` completes synchronously for userland purposes, so the awaited microtask
279
+ * is all the ordering the caller needs.
280
+ */
281
+ [Symbol.asyncDispose](): Promise<void>;
282
+ /**
283
+ * `true` once `this.signal` has aborted. Derived from the signal; no independent state.
284
+ */
285
+ get aborted(): boolean;
286
+ }
287
+ //# sourceMappingURL=mqttClient.d.ts.map