homebridge-plugin-utils 1.35.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.
- package/README.md +130 -2
- package/build/eslint-plugin/README.md +164 -0
- package/build/eslint-plugin/config.mjs +308 -0
- package/build/eslint-plugin/index.mjs +7 -0
- package/build/eslint-plugin/plugin.mjs +46 -0
- package/build/eslint-plugin/rules/blank-line-after-open-brace.mjs +137 -0
- package/build/eslint-plugin/rules/blank-line-after-open-brace.test.mjs +112 -0
- package/build/eslint-plugin/rules/comment-style.mjs +190 -0
- package/build/eslint-plugin/rules/comment-style.test.mjs +190 -0
- package/build/eslint-plugin/rules/enforce-node-protocol.mjs +114 -0
- package/build/eslint-plugin/rules/enforce-node-protocol.test.mjs +116 -0
- package/build/eslint-plugin/rules/paren-comparisons-in-logical.mjs +94 -0
- package/build/eslint-plugin/rules/paren-comparisons-in-logical.test.mjs +107 -0
- package/build/eslint-plugin/rules/split-type-imports.mjs +354 -0
- package/build/eslint-plugin/rules/split-type-imports.test.mjs +268 -0
- package/build/eslint-plugin/test-setup.mjs +21 -0
- package/build/fs-ops.mjs +184 -0
- package/build/tsconfig.json +18 -3
- package/dist/backpressure.d.ts +94 -45
- package/dist/backpressure.js +229 -93
- package/dist/backpressure.js.map +1 -1
- package/dist/cli/index.d.ts +95 -0
- package/dist/cli/index.js +355 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/clock-double.d.ts +93 -0
- package/dist/clock-double.js +141 -0
- package/dist/clock-double.js.map +1 -0
- package/dist/clock.d.ts +39 -0
- package/dist/clock.js +34 -0
- package/dist/clock.js.map +1 -0
- package/dist/eslint-plugin/config.d.mts +193 -0
- package/dist/eslint-plugin/index.d.mts +2 -0
- package/dist/eslint-plugin/plugin.d.mts +87 -0
- package/dist/eslint-plugin/rules/blank-line-after-open-brace.d.mts +19 -0
- package/dist/eslint-plugin/rules/comment-style.d.mts +15 -0
- package/dist/eslint-plugin/rules/enforce-node-protocol.d.mts +18 -0
- package/dist/eslint-plugin/rules/paren-comparisons-in-logical.d.mts +15 -0
- package/dist/eslint-plugin/rules/split-type-imports.d.mts +16 -0
- package/dist/featureOptions-docs.d.ts +96 -0
- package/dist/featureOptions-docs.js +193 -0
- package/dist/featureOptions-docs.js.map +1 -0
- package/dist/featureOptions.d.ts +674 -0
- package/dist/featureOptions.js +870 -0
- package/dist/featureOptions.js.map +1 -0
- package/dist/ffmpeg/codecs.d.ts +256 -72
- package/dist/ffmpeg/codecs.js +477 -262
- package/dist/ffmpeg/codecs.js.map +1 -1
- package/dist/ffmpeg/dgram-util.d.ts +46 -0
- package/dist/ffmpeg/dgram-util.js +38 -0
- package/dist/ffmpeg/dgram-util.js.map +1 -0
- package/dist/ffmpeg/exec.d.ts +83 -64
- package/dist/ffmpeg/exec.js +77 -86
- package/dist/ffmpeg/exec.js.map +1 -1
- package/dist/ffmpeg/fmp4.d.ts +49 -2
- package/dist/ffmpeg/fmp4.js +47 -11
- package/dist/ffmpeg/fmp4.js.map +1 -1
- package/dist/ffmpeg/hap-enums.d.ts +214 -0
- package/dist/ffmpeg/hap-enums.js +92 -0
- package/dist/ffmpeg/hap-enums.js.map +1 -0
- package/dist/ffmpeg/index.d.ts +16 -9
- package/dist/ffmpeg/index.js +6 -0
- package/dist/ffmpeg/index.js.map +1 -1
- package/dist/ffmpeg/mp4-assembler.d.ts +120 -0
- package/dist/ffmpeg/mp4-assembler.js +387 -0
- package/dist/ffmpeg/mp4-assembler.js.map +1 -0
- package/dist/ffmpeg/mp4-parser.d.ts +94 -0
- package/dist/ffmpeg/mp4-parser.js +130 -0
- package/dist/ffmpeg/mp4-parser.js.map +1 -0
- package/dist/ffmpeg/options.d.ts +62 -149
- package/dist/ffmpeg/options.js +608 -499
- package/dist/ffmpeg/options.js.map +1 -1
- package/dist/ffmpeg/process.d.ts +142 -96
- package/dist/ffmpeg/process.js +406 -278
- package/dist/ffmpeg/process.js.map +1 -1
- package/dist/ffmpeg/record.d.ts +302 -188
- package/dist/ffmpeg/record.js +408 -567
- package/dist/ffmpeg/record.js.map +1 -1
- package/dist/ffmpeg/recording-process-double.d.ts +144 -0
- package/dist/ffmpeg/recording-process-double.js +168 -0
- package/dist/ffmpeg/recording-process-double.js.map +1 -0
- package/dist/ffmpeg/rtp-parser.d.ts +70 -0
- package/dist/ffmpeg/rtp-parser.js +77 -0
- package/dist/ffmpeg/rtp-parser.js.map +1 -0
- package/dist/ffmpeg/rtp.d.ts +198 -141
- package/dist/ffmpeg/rtp.js +473 -251
- package/dist/ffmpeg/rtp.js.map +1 -1
- package/dist/ffmpeg/settings.d.ts +5 -2
- package/dist/ffmpeg/settings.js +20 -5
- package/dist/ffmpeg/settings.js.map +1 -1
- package/dist/ffmpeg/stream.d.ts +57 -107
- package/dist/ffmpeg/stream.js +121 -150
- package/dist/ffmpeg/stream.js.map +1 -1
- package/dist/formatters.d.ts +106 -0
- package/dist/formatters.js +174 -0
- package/dist/formatters.js.map +1 -0
- package/dist/homebridge-enums.d.ts +30 -0
- package/dist/homebridge-enums.js +17 -0
- package/dist/homebridge-enums.js.map +1 -0
- package/dist/index.d.ts +12 -6
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/logclient/auth.d.ts +114 -0
- package/dist/logclient/auth.js +199 -0
- package/dist/logclient/auth.js.map +1 -0
- package/dist/logclient/cli-run.d.ts +76 -0
- package/dist/logclient/cli-run.js +639 -0
- package/dist/logclient/cli-run.js.map +1 -0
- package/dist/logclient/cli.d.ts +3 -0
- package/dist/logclient/cli.js +97 -0
- package/dist/logclient/cli.js.map +1 -0
- package/dist/logclient/client.d.ts +145 -0
- package/dist/logclient/client.js +600 -0
- package/dist/logclient/client.js.map +1 -0
- package/dist/logclient/config.d.ts +173 -0
- package/dist/logclient/config.js +199 -0
- package/dist/logclient/config.js.map +1 -0
- package/dist/logclient/endpoints.d.ts +54 -0
- package/dist/logclient/endpoints.js +73 -0
- package/dist/logclient/endpoints.js.map +1 -0
- package/dist/logclient/filter.d.ts +45 -0
- package/dist/logclient/filter.js +51 -0
- package/dist/logclient/filter.js.map +1 -0
- package/dist/logclient/frame.d.ts +93 -0
- package/dist/logclient/frame.js +203 -0
- package/dist/logclient/frame.js.map +1 -0
- package/dist/logclient/index.d.ts +31 -0
- package/dist/logclient/index.js +12 -0
- package/dist/logclient/index.js.map +1 -0
- package/dist/logclient/parser.d.ts +211 -0
- package/dist/logclient/parser.js +393 -0
- package/dist/logclient/parser.js.map +1 -0
- package/dist/logclient/rest.d.ts +41 -0
- package/dist/logclient/rest.js +111 -0
- package/dist/logclient/rest.js.map +1 -0
- package/dist/logclient/settings.d.ts +15 -0
- package/dist/logclient/settings.js +64 -0
- package/dist/logclient/settings.js.map +1 -0
- package/dist/logclient/socket-double.d.ts +201 -0
- package/dist/logclient/socket-double.js +384 -0
- package/dist/logclient/socket-double.js.map +1 -0
- package/dist/logclient/socket.d.ts +257 -0
- package/dist/logclient/socket.js +620 -0
- package/dist/logclient/socket.js.map +1 -0
- package/dist/logclient/stitch.d.ts +83 -0
- package/dist/logclient/stitch.js +146 -0
- package/dist/logclient/stitch.js.map +1 -0
- package/dist/logclient/time-expression.d.ts +42 -0
- package/dist/logclient/time-expression.js +181 -0
- package/dist/logclient/time-expression.js.map +1 -0
- package/dist/logclient/time-window.d.ts +38 -0
- package/dist/logclient/time-window.js +53 -0
- package/dist/logclient/time-window.js.map +1 -0
- package/dist/logclient/types.d.ts +107 -0
- package/dist/logclient/types.js +6 -0
- package/dist/logclient/types.js.map +1 -0
- package/dist/mqttClient.d.ts +287 -0
- package/dist/mqttClient.js +433 -0
- package/dist/mqttClient.js.map +1 -0
- package/dist/service.d.ts +64 -15
- package/dist/service.js +93 -66
- package/dist/service.js.map +1 -1
- package/dist/ui/featureOptions.js +870 -0
- package/dist/ui/featureOptions.js.map +1 -0
- package/dist/ui/formatters.js +174 -0
- package/dist/ui/formatters.js.map +1 -0
- package/dist/ui/pluginConfigSession.mjs +141 -0
- package/dist/ui/webUi-featureOptions/categoryState.mjs +135 -0
- package/dist/ui/webUi-featureOptions/effects/keyboard.mjs +61 -0
- package/dist/ui/webUi-featureOptions/effects/persist.mjs +226 -0
- package/dist/ui/webUi-featureOptions/effects/theme.mjs +398 -0
- package/dist/ui/webUi-featureOptions/effects/tokens.mjs +152 -0
- package/dist/ui/webUi-featureOptions/rendering.mjs +431 -0
- package/dist/ui/webUi-featureOptions/selectors.mjs +360 -0
- package/dist/ui/webUi-featureOptions/state.mjs +319 -0
- package/dist/ui/webUi-featureOptions/store.mjs +181 -0
- package/dist/ui/webUi-featureOptions/utils.mjs +200 -0
- package/dist/ui/webUi-featureOptions/views/connectionError.mjs +152 -0
- package/dist/ui/webUi-featureOptions/views/deviceInfo.mjs +80 -0
- package/dist/ui/webUi-featureOptions/views/header.mjs +77 -0
- package/dist/ui/webUi-featureOptions/views/nav.mjs +327 -0
- package/dist/ui/webUi-featureOptions/views/options.mjs +521 -0
- package/dist/ui/webUi-featureOptions/views/search.mjs +395 -0
- package/dist/ui/webUi-featureOptions.mjs +677 -0
- package/dist/ui/webUi.mjs +192 -87
- package/dist/util.d.ts +602 -45
- package/dist/util.js +783 -78
- package/dist/util.js.map +1 -1
- package/package.json +33 -15
- package/build/eslint-rules.mjs +0 -511
- package/dist/featureoptions.d.ts +0 -264
- package/dist/featureoptions.js +0 -480
- package/dist/featureoptions.js.map +0 -1
- package/dist/mqttclient.d.ts +0 -178
- package/dist/mqttclient.js +0 -310
- package/dist/mqttclient.js.map +0 -1
- package/dist/ui/featureoptions.js +0 -480
- package/dist/ui/featureoptions.js.map +0 -1
- 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
|
+
};
|