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 @@
1
+ {"version":3,"file":"featureOptions.js","sourceRoot":"","sources":["../src/featureOptions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,174 @@
1
+ /* Copyright(C) 2017-2026, HJD (https://github.com/hjdhjd). All rights reserved.
2
+ *
3
+ * formatters.ts: Browser-safe magnitude and percentage formatters shared between the server-side `util.ts` surface and the browser-shipped `featureOptions.ts`
4
+ * model.
5
+ */
6
+ /**
7
+ * **Why this file exists.** `featureOptions.ts` ships into `dist/ui/` for the browser to load (via the `copyFeatureOptions` build step). The catalog's built-in
8
+ * formatter registry needs `formatBps`, `formatBytes`, `formatMs`, `formatPercent`, and `formatSeconds` at runtime - and pulling them from `util.ts` would drag in
9
+ * `util.ts`'s `node:timers/promises` import, which the browser cannot resolve. This module is the SSOT for the magnitude-rendering policy. It has zero runtime
10
+ * imports of any kind, so shipping it alongside `featureOptions.js` is safe in any runtime that can execute ES2024+ JavaScript.
11
+ *
12
+ * **Precision policy.** Whole numbers render without a trailing decimal place ("5" not "5.0"); fractional numbers render to one decimal place. Centralizing the
13
+ * precision policy in `formatMagnitude` means tightening it later - more precision, a thousands separator, locale-aware formatting - is a single-line change
14
+ * rather than a sweep across every format helper.
15
+ *
16
+ * **Consumers.** `util.ts` re-exports these for the server-side surface; `featureOptions.ts` imports directly from here to keep its browser-runnable dependency
17
+ * graph free of `util.ts`. Both consumers share one implementation - the file is the join point.
18
+ *
19
+ * @module
20
+ */
21
+ // Shared magnitude-rendering helper used by every magnitude-based formatter, applying the module's precision policy (see the module doc): whole numbers render with
22
+ // no trailing decimal place, fractional numbers to one decimal place.
23
+ function formatMagnitude(value) {
24
+ return ((value % 1) === 0 ? value.toFixed(0) : value.toFixed(1));
25
+ }
26
+ /**
27
+ * Format a bitrate value into a human-readable form as bps, kbps, or Mbps.
28
+ *
29
+ * @param value - The bitrate value to convert, in bits per second.
30
+ *
31
+ * @returns Returns the value as a human-readable string.
32
+ *
33
+ * @example
34
+ *
35
+ * ```ts
36
+ * formatBps(500); // "500 bps".
37
+ * formatBps(2000); // "2 kbps".
38
+ * formatBps(15000); // "15 kbps".
39
+ * formatBps(2560); // "2.6 kbps".
40
+ * formatBps(1000000); // "1 Mbps".
41
+ * formatBps(2560000); // "2.6 Mbps".
42
+ * ```
43
+ *
44
+ * @category Utilities
45
+ */
46
+ export function formatBps(value) {
47
+ if (value < 1_000) {
48
+ return value.toString() + " bps";
49
+ }
50
+ if (value < 1_000_000) {
51
+ return formatMagnitude(value / 1_000) + " kbps";
52
+ }
53
+ return formatMagnitude(value / 1_000_000) + " Mbps";
54
+ }
55
+ /**
56
+ * Format a byte count into a human-readable form as bytes, KB, MB, GB, or TB. Uses 1024-based thresholds matching the convention every operating system uses for
57
+ * displaying file and buffer sizes.
58
+ *
59
+ * @param value - The byte count to convert.
60
+ *
61
+ * @returns Returns the value as a human-readable string.
62
+ *
63
+ * @example
64
+ *
65
+ * ```ts
66
+ * formatBytes(512); // "512 bytes".
67
+ * formatBytes(2048); // "2 KB".
68
+ * formatBytes(1536); // "1.5 KB".
69
+ * formatBytes(1_048_576); // "1 MB".
70
+ * formatBytes(2_621_440); // "2.5 MB".
71
+ * formatBytes(1_073_741_824); // "1 GB".
72
+ * formatBytes(1_099_511_627_776); // "1 TB".
73
+ * ```
74
+ *
75
+ * @category Utilities
76
+ */
77
+ export function formatBytes(value) {
78
+ if (value < 1_024) {
79
+ return value.toString() + " bytes";
80
+ }
81
+ if (value < 1_048_576) {
82
+ return formatMagnitude(value / 1_024) + " KB";
83
+ }
84
+ if (value < 1_073_741_824) {
85
+ return formatMagnitude(value / 1_048_576) + " MB";
86
+ }
87
+ if (value < 1_099_511_627_776) {
88
+ return formatMagnitude(value / 1_073_741_824) + " GB";
89
+ }
90
+ return formatMagnitude(value / 1_099_511_627_776) + " TB";
91
+ }
92
+ /**
93
+ * Format a millisecond duration into a human-readable form as ms, s, min, or hr. Tiered thresholds match how operators naturally read elapsed time: sub-second
94
+ * values stay in milliseconds for precision, longer durations promote to seconds, minutes, and hours.
95
+ *
96
+ * @param value - The duration to convert, in milliseconds.
97
+ *
98
+ * @returns Returns the value as a human-readable string.
99
+ *
100
+ * @example
101
+ *
102
+ * ```ts
103
+ * formatMs(250); // "250 ms".
104
+ * formatMs(1500); // "1.5 s".
105
+ * formatMs(15000); // "15 s".
106
+ * formatMs(90000); // "1.5 min".
107
+ * formatMs(5_400_000); // "1.5 hr".
108
+ * ```
109
+ *
110
+ * @category Utilities
111
+ */
112
+ export function formatMs(value) {
113
+ if (value < 1_000) {
114
+ return value.toString() + " ms";
115
+ }
116
+ if (value < 60_000) {
117
+ return formatMagnitude(value / 1_000) + " s";
118
+ }
119
+ if (value < 3_600_000) {
120
+ return formatMagnitude(value / 60_000) + " min";
121
+ }
122
+ return formatMagnitude(value / 3_600_000) + " hr";
123
+ }
124
+ /**
125
+ * Format a numeric percentage value into a human-readable form with a trailing percent sign. Applies the same precision policy as the magnitude-based formatters
126
+ * via the shared internal helper: whole numbers render without a trailing decimal, fractional numbers render to one decimal place.
127
+ *
128
+ * @param value - The percentage value to convert. Treated as already-scaled into percent units (50 means 50%, not 0.5).
129
+ *
130
+ * @returns Returns the value as a human-readable string ending in `%`.
131
+ *
132
+ * @example
133
+ *
134
+ * ```ts
135
+ * formatPercent(0); // "0%".
136
+ * formatPercent(50); // "50%".
137
+ * formatPercent(100); // "100%".
138
+ * formatPercent(33.333); // "33.3%".
139
+ * ```
140
+ *
141
+ * @category Utilities
142
+ */
143
+ export function formatPercent(value) {
144
+ return formatMagnitude(value) + "%";
145
+ }
146
+ /**
147
+ * Format a second-resolution duration into a human-readable form as s, min, or hr. Same tier semantics as {@link formatMs}, scaled for inputs that arrive already
148
+ * in seconds rather than milliseconds.
149
+ *
150
+ * @param value - The duration to convert, in seconds.
151
+ *
152
+ * @returns Returns the value as a human-readable string.
153
+ *
154
+ * @example
155
+ *
156
+ * ```ts
157
+ * formatSeconds(45); // "45 s".
158
+ * formatSeconds(90); // "1.5 min".
159
+ * formatSeconds(1800); // "30 min".
160
+ * formatSeconds(5400); // "1.5 hr".
161
+ * ```
162
+ *
163
+ * @category Utilities
164
+ */
165
+ export function formatSeconds(value) {
166
+ if (value < 60) {
167
+ return value.toString() + " s";
168
+ }
169
+ if (value < 3_600) {
170
+ return formatMagnitude(value / 60) + " min";
171
+ }
172
+ return formatMagnitude(value / 3_600) + " hr";
173
+ }
174
+ //# sourceMappingURL=formatters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatters.js","sourceRoot":"","sources":["../src/formatters.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;;GAcG;AAEH,oKAAoK;AACpK,sEAAsE;AACtE,SAAS,eAAe,CAAC,KAAa;IAEpC,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,SAAS,CAAC,KAAa;IAErC,IAAG,KAAK,GAAG,KAAK,EAAE,CAAC;QAEjB,OAAO,KAAK,CAAC,QAAQ,EAAE,GAAG,MAAM,CAAC;IACnC,CAAC;IAED,IAAG,KAAK,GAAG,SAAS,EAAE,CAAC;QAErB,OAAO,eAAe,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC;IAClD,CAAC;IAED,OAAO,eAAe,CAAC,KAAK,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC;AACtD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IAEvC,IAAG,KAAK,GAAG,KAAK,EAAE,CAAC;QAEjB,OAAO,KAAK,CAAC,QAAQ,EAAE,GAAG,QAAQ,CAAC;IACrC,CAAC;IAED,IAAG,KAAK,GAAG,SAAS,EAAE,CAAC;QAErB,OAAO,eAAe,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC;IAChD,CAAC;IAED,IAAG,KAAK,GAAG,aAAa,EAAE,CAAC;QAEzB,OAAO,eAAe,CAAC,KAAK,GAAG,SAAS,CAAC,GAAG,KAAK,CAAC;IACpD,CAAC;IAED,IAAG,KAAK,GAAG,iBAAiB,EAAE,CAAC;QAE7B,OAAO,eAAe,CAAC,KAAK,GAAG,aAAa,CAAC,GAAG,KAAK,CAAC;IACxD,CAAC;IAED,OAAO,eAAe,CAAC,KAAK,GAAG,iBAAiB,CAAC,GAAG,KAAK,CAAC;AAC5D,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAa;IAEpC,IAAG,KAAK,GAAG,KAAK,EAAE,CAAC;QAEjB,OAAO,KAAK,CAAC,QAAQ,EAAE,GAAG,KAAK,CAAC;IAClC,CAAC;IAED,IAAG,KAAK,GAAG,MAAM,EAAE,CAAC;QAElB,OAAO,eAAe,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC;IAC/C,CAAC;IAED,IAAG,KAAK,GAAG,SAAS,EAAE,CAAC;QAErB,OAAO,eAAe,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC;IAClD,CAAC;IAED,OAAO,eAAe,CAAC,KAAK,GAAG,SAAS,CAAC,GAAG,KAAK,CAAC;AACpD,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IAEzC,OAAO,eAAe,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC;AACtC,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IAEzC,IAAG,KAAK,GAAG,EAAE,EAAE,CAAC;QAEd,OAAO,KAAK,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC;IACjC,CAAC;IAED,IAAG,KAAK,GAAG,KAAK,EAAE,CAAC;QAEjB,OAAO,eAAe,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC;IAC9C,CAAC;IAED,OAAO,eAAe,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC;AAChD,CAAC"}
@@ -0,0 +1,141 @@
1
+ /* Copyright(C) 2017-2026, HJD (https://github.com/hjdhjd). All rights reserved.
2
+ *
3
+ * pluginConfigSession.mjs: Session-scoped owner of the persisted plugin configuration.
4
+ */
5
+ "use strict";
6
+
7
+ /**
8
+ * PluginConfigSession - the single session-scoped accessor to the persisted plugin configuration, holding a coherent replica of the host config.
9
+ *
10
+ * The webUI needs to read its plugin configuration at several lifecycle points (routing, the first-run flow, the feature-options page) and to write it at two
11
+ * (first-run credential capture, feature-option saves). Left to themselves, each of those sites would call `homebridge.getPluginConfig` independently and at least
12
+ * two would call `homebridge.updatePluginConfig` independently - several conduits to the same host config, each free to read it at a different moment and to drift
13
+ * from the others. This owner collapses that to one: every read and every write of the host config goes through this single accessor, so the held array is the one
14
+ * copy the session reasons about.
15
+ *
16
+ * The host config is the ultimate source of truth; this class is not a second source but the one correct accessor to the first, holding a replica that is coherent
17
+ * as of its last reference-advancing operation. The held replica advances only through {@link sync} (the read-direction advance, re-reading the host config) and
18
+ * {@link commit} (the write-direction advance, persisting an edit). Routing, the first-run hooks, and the feature-options page all receive their config from here, and
19
+ * nothing else calls the host config endpoints.
20
+ *
21
+ * Because the host config can change underneath the session while the page is hidden (the Settings tab edits the same in-memory model), the replica is not assumed
22
+ * frozen. The feature-options page re-syncs on every entry ({@link sync} at its `show()` chokepoint), so the replica is re-read against any external Settings-tab
23
+ * edit before the page renders against it. {@link commit} advances the reference transactionally - it moves only after the host write resolves, so a failed write
24
+ * leaves the prior replica intact. This mirrors how Homebridge models its own config: read, edit, save - re-read on the next visit.
25
+ *
26
+ * @example
27
+ *
28
+ * const session = await PluginConfigSession.open({ host: homebridge, name: "My Platform" });
29
+ *
30
+ * if(!session.platform.controllers?.length) {
31
+ *
32
+ * await session.commit({ controllers: [ { address, password, username } ] });
33
+ * }
34
+ */
35
+ export class PluginConfigSession {
36
+
37
+ // The held config array - the session's coherent replica of the plugin configuration. Read through the getters; advanced by sync() (read) and commit() (write).
38
+ #config;
39
+
40
+ // The Homebridge UI host (or a test stub matching the {getPluginConfig, updatePluginConfig} surface). The session is the only place that calls its config endpoints.
41
+ #host;
42
+
43
+ // The platform name used to seed the minimum config shape when the host has none. Preserved on the primary entry across commits.
44
+ #name;
45
+
46
+ /**
47
+ * Open a configuration session: read the host config into the replica via the initial {@link sync} and seed a minimal primary platform entry when it is absent, so
48
+ * every downstream reader sees a well-formed entry rather than having to guard for the empty-first-run case. Subsequent entries re-sync the replica, so this opening
49
+ * read establishes the replica rather than freezing it.
50
+ *
51
+ * @param {Object} args
52
+ * @param {{getPluginConfig: () => Promise<Object[]>, updatePluginConfig: (config: readonly Object[]) => Promise<unknown>}} args.host - The Homebridge bridge.
53
+ * @param {string} [args.name] - The platform name used to seed an empty configuration.
54
+ * @returns {Promise<PluginConfigSession>} The opened session.
55
+ */
56
+ static async open({ host, name }) {
57
+
58
+ const session = new PluginConfigSession(host, name);
59
+
60
+ await session.sync();
61
+
62
+ return session;
63
+ }
64
+
65
+ /**
66
+ * @param {Object} host - The Homebridge bridge.
67
+ * @param {string} [name] - The platform name used to seed an empty configuration.
68
+ */
69
+ constructor(host, name) {
70
+
71
+ this.#config = [];
72
+ this.#host = host;
73
+ this.#name = name;
74
+ }
75
+
76
+ /**
77
+ * The full configuration array, exactly as it will be written back to the host. Exposed for the feature-options page, which preserves the sibling entries [1..]
78
+ * when it overlays the live edited options for its editing-buffer view.
79
+ *
80
+ * @returns {readonly Object[]} The plugin-config array.
81
+ */
82
+ get entries() {
83
+
84
+ return this.#config;
85
+ }
86
+
87
+ /**
88
+ * The primary platform-config entry (config[0]). The live reference the orchestrator injects into every plugin hook; reads happen against this.
89
+ *
90
+ * @returns {Object} The primary platform-config entry.
91
+ */
92
+ get platform() {
93
+
94
+ return this.#config[0];
95
+ }
96
+
97
+ /**
98
+ * Merge a patch into the primary platform entry and persist the whole array (sibling entries preserved), advancing the held reference only after the host write
99
+ * resolves. Every configuration write funnels through this method; it is the write-direction counterpart of {@link sync}.
100
+ *
101
+ * Transactional by construction: the next array is built and written before it replaces the held reference, so a rejected write throws without moving the session
102
+ * off its last-good state. Callers that need to surface the failure (the persist effect's rollback path) catch the rejection; the session itself stays consistent
103
+ * either way.
104
+ *
105
+ * @param {Object} patch - Fields to merge onto the primary platform entry (e.g. `{ controllers }` or `{ options }`). The primary entry's other fields are preserved.
106
+ * @returns {Promise<void>}
107
+ */
108
+ async commit(patch) {
109
+
110
+ const next = [ { ...this.#config[0], ...patch }, ...this.#config.slice(1) ];
111
+
112
+ await this.#host.updatePluginConfig(next);
113
+
114
+ this.#config = next;
115
+ }
116
+
117
+ /**
118
+ * Re-read the host config into the replica and seed the minimum shape. Every configuration read funnels through this method, pairing with {@link commit} as the
119
+ * read-direction half.
120
+ *
121
+ * Called on every page entry so the replica re-reads against any external Settings-tab edit before the page renders against it. An empty host result yields a
122
+ * single bare entry; in both cases we ensure the primary entry carries the platform name so a later commit persists a well-formed block. The seed is held only -
123
+ * never eagerly written - so a fresh install that is opened and abandoned never leaves a bare platform entry staged on the host; the first real commit persists the
124
+ * name alongside actual data.
125
+ *
126
+ * Built like {@link commit} for symmetry and clarity: the read happens into a local, the local is seeded, and a single trailing assignment advances the held
127
+ * reference. (The build-then-assign is not load-bearing against a torn write here - the only I/O is the first statement - but it keeps this method's shape
128
+ * consistent with {@link commit}.)
129
+ *
130
+ * @returns {Promise<void>}
131
+ */
132
+ async sync() {
133
+
134
+ const loaded = await this.#host.getPluginConfig();
135
+ const next = loaded.length ? loaded : [{}];
136
+
137
+ (next[0] ??= { name: this.#name }).name ??= this.#name;
138
+
139
+ this.#config = next;
140
+ }
141
+ }
@@ -0,0 +1,135 @@
1
+ /* Copyright(C) 2017-2026, HJD (https://github.com/hjdhjd). All rights reserved.
2
+ *
3
+ * webUi-featureOptions/categoryState.mjs: Per-context category expansion-state persistence for the feature options webUI.
4
+ */
5
+ "use strict";
6
+
7
+ /**
8
+ * FeatureOptionsCategoryState - Per-context UI-state store with a localStorage projection.
9
+ *
10
+ * A small store keyed by an arbitrary caller-supplied context string, backed by a single localStorage key namespaced under the plugin's platform identifier. The
11
+ * store is intentionally DOM-agnostic: callers serialize their UI state into a plain object before calling {@link set}, and read it back through {@link get}. DOM
12
+ * walking is the orchestrator's job (via `captureCategoryStates` / `applyCategoryStates` in `webUi-featureOptions/utils.mjs`), which keeps this component a pure
13
+ * persistence concern - reusable for any per-context JSON-serializable state, not just category collapse.
14
+ *
15
+ * Persistence is best-effort: read failures (corrupt JSON, storage unavailable) fall back to an empty map; write failures are silently swallowed because the
16
+ * canonical config lives in the Homebridge plugin config store. The category cache exists only to spare the user from re-expanding the same sections on every visit.
17
+ * The constructor loads the persisted snapshot once at instantiation; {@link set} updates both the in-memory map and the disk projection in one step.
18
+ *
19
+ * The in-memory map is a null-prototype object ({@link Object.create}(`null`)) so property accesses (`get`, `set`, `delete`'s `in` check) only ever see own
20
+ * properties. Prototype names like `"toString"`, `"hasOwnProperty"`, or `"__proto__"` cannot leak in via `Object.prototype`, regardless of what context keys the
21
+ * caller chooses or what JSON happens to be in localStorage.
22
+ */
23
+ export class FeatureOptionsCategoryState {
24
+
25
+ // In-memory map of context-key -> arbitrary JSON-serializable state shape. Loaded from localStorage at construction; updated by set(); read by get().
26
+ #map;
27
+
28
+ // Computed once at construction so the storage-key shape is the SSOT for this instance. Includes the platform identifier so plugins coexisting in a single
29
+ // Homebridge install don't trample one another's UI state.
30
+ #storageKey;
31
+
32
+ /**
33
+ * @param {string|undefined} platform - The Homebridge plugin platform identifier. Falls back to a generic "plugin" suffix when omitted so plugin configs that
34
+ * pre-date platform-keyed storage still get a working (if non-isolated) cache.
35
+ */
36
+ constructor(platform) {
37
+
38
+ this.#storageKey = "homebridge-" + (platform ?? "plugin") + "-category-states";
39
+ this.#map = this.#load();
40
+ }
41
+
42
+ /**
43
+ * Return any persisted state for the given context key, or undefined when none exists. Callers receive a reference into the in-memory map - treat it as
44
+ * read-only; mutating it bypasses {@link set} and skips the localStorage write.
45
+ *
46
+ * @param {string} contextKey - The caller-supplied identifier for the current view.
47
+ * @returns {Object|undefined} The persisted state for this context, or undefined.
48
+ */
49
+ get(contextKey) {
50
+
51
+ return this.#map[contextKey];
52
+ }
53
+
54
+ /**
55
+ * Persist the supplied state under the given context key. The store performs no shape validation - the caller is responsible for handing in something this
56
+ * store should round-trip via JSON. Pairs with {@link get}.
57
+ *
58
+ * @param {string} contextKey - Identifier for the current view.
59
+ * @param {Object} state - JSON-serializable state to persist.
60
+ */
61
+ set(contextKey, state) {
62
+
63
+ this.#map[contextKey] = state;
64
+ this.#persist();
65
+ }
66
+
67
+ /**
68
+ * Drop the persisted state for the given context key. The disk projection is updated immediately; subsequent {@link get} calls for the same key return undefined.
69
+ * No-op when the key is absent. Pairs with {@link set} to complete the symmetric read/write/remove triad.
70
+ *
71
+ * Lazy key-shape migrations rely on this: a caller that finds data under a legacy key writes it under the new key via {@link set} and removes the legacy entry
72
+ * via {@link delete} in one read/write/remove sequence, leaving disk in the new shape after every migrated visit.
73
+ *
74
+ * @param {string} contextKey - Identifier to remove.
75
+ */
76
+ delete(contextKey) {
77
+
78
+ if(contextKey in this.#map) {
79
+
80
+ delete this.#map[contextKey];
81
+ this.#persist();
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Load the persisted snapshot from localStorage into a null-prototype map. Returns an empty map on absent, corrupt, or otherwise unreadable storage so callers
87
+ * always operate against a usable object - persistence failure should never wedge the UI on a bad localStorage entry. The null prototype eliminates the
88
+ * possibility of an own-vs-inherited mismatch on any access path: `get`, `set`, and the `in` check in `delete` see only own keys regardless of what context
89
+ * strings or JSON-stored keys appear.
90
+ *
91
+ * @returns {Object} The loaded map (always a null-prototype object), or an empty null-prototype object on failure.
92
+ * @private
93
+ */
94
+ #load() {
95
+
96
+ try {
97
+
98
+ const stored = window.localStorage.getItem(this.#storageKey);
99
+ const parsed = stored ? JSON.parse(stored) : null;
100
+
101
+ // Plain-object guard. `JSON.parse` happily returns `null`, arrays, and primitives. Null and non-object primitives would crash the first downstream
102
+ // get/set on a non-indexable value, while an array is indexable but would round-trip incorrectly through JSON.stringify and lose its array semantics
103
+ // on the next reconstruction. The shape check matches the catch-block's graceful-degrade contract: any deviation from "this is a plain object"
104
+ // resets the cache to an empty map and lets the UI continue. The valid-shape branch copies the parsed entries into a null-prototype container so
105
+ // prototype names cannot leak in via `JSON.parse`'s regular-Object output.
106
+ if((parsed !== null) && (typeof parsed === "object") && !Array.isArray(parsed)) {
107
+
108
+ return Object.assign(Object.create(null), parsed);
109
+ }
110
+ } catch {
111
+
112
+ // Storage corrupted, unavailable, or contains malformed JSON. Fall through to the empty-map default below.
113
+ }
114
+
115
+ return Object.create(null);
116
+ }
117
+
118
+ /**
119
+ * Persist the current in-memory map to localStorage. Failures are silently swallowed because localStorage may be unavailable in private browsing or sandboxed
120
+ * contexts, or quota-exceeded under heavy use; the category-state cache is purely UI ergonomics - the canonical config remains intact in the Homebridge plugin
121
+ * config store.
122
+ *
123
+ * @private
124
+ */
125
+ #persist() {
126
+
127
+ try {
128
+
129
+ window.localStorage.setItem(this.#storageKey, JSON.stringify(this.#map));
130
+ } catch {
131
+
132
+ // Persistence failure is non-fatal. See the docblock for the rationale.
133
+ }
134
+ }
135
+ }
@@ -0,0 +1,61 @@
1
+ /* Copyright(C) 2017-2026, HJD (https://github.com/hjdhjd). All rights reserved.
2
+ *
3
+ * webUi-featureOptions/effects/keyboard.mjs: Global keyboard shortcuts for the feature options webUI.
4
+ */
5
+ "use strict";
6
+
7
+ /**
8
+ * Register the global keyboard shortcuts for the feature options webUI.
9
+ *
10
+ * The registered shortcuts:
11
+ *
12
+ * - **Cmd/Ctrl + F** focuses the search input. Preempts the browser's native find behavior so users can search the feature options rather than the page's raw
13
+ * text. Only acts when the search panel is mounted and visible - otherwise falls through to the browser's default handling.
14
+ * - **Escape on the search input** clears the search query. Dispatches `filter:changed` with an empty query so subscribers (the search view, projection,
15
+ * status bar) re-derive from the unfiltered state.
16
+ *
17
+ * Both shortcuts are handled by a single keydown listener bound to the supplied AbortSignal; aborting cleanly removes it.
18
+ *
19
+ * @param {Object} args
20
+ * @param {AbortSignal} args.signal - Lifecycle signal. Aborting removes the listeners.
21
+ * @param {import("../store.mjs").FeatureOptionsStore} args.store - The store the Escape handler dispatches against.
22
+ */
23
+ export const registerKeyboardEffect = ({ signal, store }) => {
24
+
25
+ if(signal.aborted) {
26
+
27
+ return;
28
+ }
29
+
30
+ document.addEventListener("keydown", (event) => {
31
+
32
+ // Cmd/Ctrl + F: focus the search input when the search panel is visible. The visibility check uses the DOM directly because "is the search panel mounted and
33
+ // visible right now?" is genuinely a DOM-state question - state.status doesn't carry it (the search view's visibility is a function of the view's mount
34
+ // status, not the store's lifecycle).
35
+ if((event.ctrlKey || event.metaKey) && (event.key === "f")) {
36
+
37
+ const searchInput = document.getElementById("searchInput");
38
+ const searchPanel = document.getElementById("search");
39
+
40
+ if(!searchInput || !searchPanel || (searchPanel.style.display === "none")) {
41
+
42
+ return;
43
+ }
44
+
45
+ event.preventDefault();
46
+ searchInput.focus();
47
+ searchInput.select();
48
+
49
+ return;
50
+ }
51
+
52
+ // Escape on the search input: clear the query. Pre-condition: the focused element IS the search input (event.target's id), so the shortcut only fires when the
53
+ // user is actively typing in search. The id check is sufficient: the document-level listener receives bubbled events from any element, but only the search
54
+ // input has id="searchInput" in the page DOM.
55
+ if((event.key === "Escape") && (event.target?.id === "searchInput")) {
56
+
57
+ event.target.value = "";
58
+ store.dispatch({ query: "", type: "filter:changed" });
59
+ }
60
+ }, { signal });
61
+ };