homebridge-plugin-utils 1.35.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. package/README.md +130 -2
  2. package/build/eslint-plugin/README.md +164 -0
  3. package/build/eslint-plugin/config.mjs +308 -0
  4. package/build/eslint-plugin/index.mjs +7 -0
  5. package/build/eslint-plugin/plugin.mjs +46 -0
  6. package/build/eslint-plugin/rules/blank-line-after-open-brace.mjs +137 -0
  7. package/build/eslint-plugin/rules/blank-line-after-open-brace.test.mjs +112 -0
  8. package/build/eslint-plugin/rules/comment-style.mjs +190 -0
  9. package/build/eslint-plugin/rules/comment-style.test.mjs +190 -0
  10. package/build/eslint-plugin/rules/enforce-node-protocol.mjs +114 -0
  11. package/build/eslint-plugin/rules/enforce-node-protocol.test.mjs +116 -0
  12. package/build/eslint-plugin/rules/paren-comparisons-in-logical.mjs +94 -0
  13. package/build/eslint-plugin/rules/paren-comparisons-in-logical.test.mjs +107 -0
  14. package/build/eslint-plugin/rules/split-type-imports.mjs +354 -0
  15. package/build/eslint-plugin/rules/split-type-imports.test.mjs +268 -0
  16. package/build/eslint-plugin/test-setup.mjs +21 -0
  17. package/build/fs-ops.mjs +184 -0
  18. package/build/tsconfig.json +18 -3
  19. package/dist/backpressure.d.ts +94 -45
  20. package/dist/backpressure.js +229 -93
  21. package/dist/backpressure.js.map +1 -1
  22. package/dist/cli/index.d.ts +166 -0
  23. package/dist/cli/index.js +551 -0
  24. package/dist/cli/index.js.map +1 -0
  25. package/dist/clock-double.d.ts +93 -0
  26. package/dist/clock-double.js +141 -0
  27. package/dist/clock-double.js.map +1 -0
  28. package/dist/clock.d.ts +39 -0
  29. package/dist/clock.js +34 -0
  30. package/dist/clock.js.map +1 -0
  31. package/dist/disposable-stack.d.ts +59 -0
  32. package/dist/disposable-stack.js +155 -0
  33. package/dist/disposable-stack.js.map +1 -0
  34. package/dist/docChrome.d.ts +260 -0
  35. package/dist/docChrome.js +361 -0
  36. package/dist/docChrome.js.map +1 -0
  37. package/dist/eslint-plugin/config.d.mts +193 -0
  38. package/dist/eslint-plugin/index.d.mts +2 -0
  39. package/dist/eslint-plugin/plugin.d.mts +87 -0
  40. package/dist/eslint-plugin/rules/blank-line-after-open-brace.d.mts +19 -0
  41. package/dist/eslint-plugin/rules/comment-style.d.mts +15 -0
  42. package/dist/eslint-plugin/rules/enforce-node-protocol.d.mts +18 -0
  43. package/dist/eslint-plugin/rules/paren-comparisons-in-logical.d.mts +15 -0
  44. package/dist/eslint-plugin/rules/split-type-imports.d.mts +16 -0
  45. package/dist/featureOptions-docs.d.ts +96 -0
  46. package/dist/featureOptions-docs.js +193 -0
  47. package/dist/featureOptions-docs.js.map +1 -0
  48. package/dist/featureOptions.d.ts +674 -0
  49. package/dist/featureOptions.js +870 -0
  50. package/dist/featureOptions.js.map +1 -0
  51. package/dist/ffmpeg/codecs.d.ts +256 -72
  52. package/dist/ffmpeg/codecs.js +477 -262
  53. package/dist/ffmpeg/codecs.js.map +1 -1
  54. package/dist/ffmpeg/dgram-util.d.ts +46 -0
  55. package/dist/ffmpeg/dgram-util.js +38 -0
  56. package/dist/ffmpeg/dgram-util.js.map +1 -0
  57. package/dist/ffmpeg/exec.d.ts +83 -64
  58. package/dist/ffmpeg/exec.js +77 -86
  59. package/dist/ffmpeg/exec.js.map +1 -1
  60. package/dist/ffmpeg/fmp4.d.ts +49 -2
  61. package/dist/ffmpeg/fmp4.js +47 -11
  62. package/dist/ffmpeg/fmp4.js.map +1 -1
  63. package/dist/ffmpeg/hap-enums.d.ts +214 -0
  64. package/dist/ffmpeg/hap-enums.js +92 -0
  65. package/dist/ffmpeg/hap-enums.js.map +1 -0
  66. package/dist/ffmpeg/index.d.ts +16 -9
  67. package/dist/ffmpeg/index.js +6 -0
  68. package/dist/ffmpeg/index.js.map +1 -1
  69. package/dist/ffmpeg/mp4-assembler.d.ts +161 -0
  70. package/dist/ffmpeg/mp4-assembler.js +424 -0
  71. package/dist/ffmpeg/mp4-assembler.js.map +1 -0
  72. package/dist/ffmpeg/mp4-parser.d.ts +94 -0
  73. package/dist/ffmpeg/mp4-parser.js +130 -0
  74. package/dist/ffmpeg/mp4-parser.js.map +1 -0
  75. package/dist/ffmpeg/options.d.ts +62 -149
  76. package/dist/ffmpeg/options.js +608 -499
  77. package/dist/ffmpeg/options.js.map +1 -1
  78. package/dist/ffmpeg/process.d.ts +142 -96
  79. package/dist/ffmpeg/process.js +406 -278
  80. package/dist/ffmpeg/process.js.map +1 -1
  81. package/dist/ffmpeg/record.d.ts +325 -186
  82. package/dist/ffmpeg/record.js +418 -565
  83. package/dist/ffmpeg/record.js.map +1 -1
  84. package/dist/ffmpeg/recording-process-double.d.ts +157 -0
  85. package/dist/ffmpeg/recording-process-double.js +190 -0
  86. package/dist/ffmpeg/recording-process-double.js.map +1 -0
  87. package/dist/ffmpeg/rtp-parser.d.ts +70 -0
  88. package/dist/ffmpeg/rtp-parser.js +77 -0
  89. package/dist/ffmpeg/rtp-parser.js.map +1 -0
  90. package/dist/ffmpeg/rtp.d.ts +198 -141
  91. package/dist/ffmpeg/rtp.js +474 -251
  92. package/dist/ffmpeg/rtp.js.map +1 -1
  93. package/dist/ffmpeg/settings.d.ts +5 -2
  94. package/dist/ffmpeg/settings.js +20 -5
  95. package/dist/ffmpeg/settings.js.map +1 -1
  96. package/dist/ffmpeg/stream.d.ts +57 -107
  97. package/dist/ffmpeg/stream.js +121 -150
  98. package/dist/ffmpeg/stream.js.map +1 -1
  99. package/dist/formatters.d.ts +106 -0
  100. package/dist/formatters.js +174 -0
  101. package/dist/formatters.js.map +1 -0
  102. package/dist/homebridge-enums.d.ts +30 -0
  103. package/dist/homebridge-enums.js +17 -0
  104. package/dist/homebridge-enums.js.map +1 -0
  105. package/dist/index.d.ts +13 -6
  106. package/dist/index.js +8 -2
  107. package/dist/index.js.map +1 -1
  108. package/dist/logclient/auth.d.ts +114 -0
  109. package/dist/logclient/auth.js +199 -0
  110. package/dist/logclient/auth.js.map +1 -0
  111. package/dist/logclient/cli-run.d.ts +76 -0
  112. package/dist/logclient/cli-run.js +639 -0
  113. package/dist/logclient/cli-run.js.map +1 -0
  114. package/dist/logclient/cli.d.ts +3 -0
  115. package/dist/logclient/cli.js +97 -0
  116. package/dist/logclient/cli.js.map +1 -0
  117. package/dist/logclient/client.d.ts +145 -0
  118. package/dist/logclient/client.js +600 -0
  119. package/dist/logclient/client.js.map +1 -0
  120. package/dist/logclient/config.d.ts +173 -0
  121. package/dist/logclient/config.js +199 -0
  122. package/dist/logclient/config.js.map +1 -0
  123. package/dist/logclient/endpoints.d.ts +54 -0
  124. package/dist/logclient/endpoints.js +73 -0
  125. package/dist/logclient/endpoints.js.map +1 -0
  126. package/dist/logclient/filter.d.ts +45 -0
  127. package/dist/logclient/filter.js +51 -0
  128. package/dist/logclient/filter.js.map +1 -0
  129. package/dist/logclient/frame.d.ts +93 -0
  130. package/dist/logclient/frame.js +203 -0
  131. package/dist/logclient/frame.js.map +1 -0
  132. package/dist/logclient/index.d.ts +31 -0
  133. package/dist/logclient/index.js +12 -0
  134. package/dist/logclient/index.js.map +1 -0
  135. package/dist/logclient/parser.d.ts +211 -0
  136. package/dist/logclient/parser.js +393 -0
  137. package/dist/logclient/parser.js.map +1 -0
  138. package/dist/logclient/rest.d.ts +41 -0
  139. package/dist/logclient/rest.js +111 -0
  140. package/dist/logclient/rest.js.map +1 -0
  141. package/dist/logclient/settings.d.ts +15 -0
  142. package/dist/logclient/settings.js +64 -0
  143. package/dist/logclient/settings.js.map +1 -0
  144. package/dist/logclient/socket-double.d.ts +201 -0
  145. package/dist/logclient/socket-double.js +384 -0
  146. package/dist/logclient/socket-double.js.map +1 -0
  147. package/dist/logclient/socket.d.ts +257 -0
  148. package/dist/logclient/socket.js +620 -0
  149. package/dist/logclient/socket.js.map +1 -0
  150. package/dist/logclient/stitch.d.ts +83 -0
  151. package/dist/logclient/stitch.js +146 -0
  152. package/dist/logclient/stitch.js.map +1 -0
  153. package/dist/logclient/time-expression.d.ts +42 -0
  154. package/dist/logclient/time-expression.js +181 -0
  155. package/dist/logclient/time-expression.js.map +1 -0
  156. package/dist/logclient/time-window.d.ts +38 -0
  157. package/dist/logclient/time-window.js +53 -0
  158. package/dist/logclient/time-window.js.map +1 -0
  159. package/dist/logclient/types.d.ts +107 -0
  160. package/dist/logclient/types.js +6 -0
  161. package/dist/logclient/types.js.map +1 -0
  162. package/dist/mqttClient.d.ts +287 -0
  163. package/dist/mqttClient.js +433 -0
  164. package/dist/mqttClient.js.map +1 -0
  165. package/dist/service.d.ts +64 -15
  166. package/dist/service.js +93 -66
  167. package/dist/service.js.map +1 -1
  168. package/dist/ui/featureOptions.js +870 -0
  169. package/dist/ui/featureOptions.js.map +1 -0
  170. package/dist/ui/formatters.js +174 -0
  171. package/dist/ui/formatters.js.map +1 -0
  172. package/dist/ui/pluginConfigSession.mjs +141 -0
  173. package/dist/ui/webUi-featureOptions/categoryState.mjs +135 -0
  174. package/dist/ui/webUi-featureOptions/effects/keyboard.mjs +61 -0
  175. package/dist/ui/webUi-featureOptions/effects/persist.mjs +226 -0
  176. package/dist/ui/webUi-featureOptions/effects/theme.mjs +398 -0
  177. package/dist/ui/webUi-featureOptions/effects/tokens.mjs +152 -0
  178. package/dist/ui/webUi-featureOptions/rendering.mjs +431 -0
  179. package/dist/ui/webUi-featureOptions/selectors.mjs +360 -0
  180. package/dist/ui/webUi-featureOptions/state.mjs +319 -0
  181. package/dist/ui/webUi-featureOptions/store.mjs +181 -0
  182. package/dist/ui/webUi-featureOptions/utils.mjs +213 -0
  183. package/dist/ui/webUi-featureOptions/views/connectionError.mjs +152 -0
  184. package/dist/ui/webUi-featureOptions/views/deviceInfo.mjs +80 -0
  185. package/dist/ui/webUi-featureOptions/views/header.mjs +77 -0
  186. package/dist/ui/webUi-featureOptions/views/nav.mjs +341 -0
  187. package/dist/ui/webUi-featureOptions/views/options.mjs +521 -0
  188. package/dist/ui/webUi-featureOptions/views/search.mjs +395 -0
  189. package/dist/ui/webUi-featureOptions.mjs +702 -0
  190. package/dist/ui/webUi.mjs +225 -88
  191. package/dist/util.d.ts +679 -45
  192. package/dist/util.js +830 -77
  193. package/dist/util.js.map +1 -1
  194. package/package.json +33 -15
  195. package/build/eslint-rules.mjs +0 -511
  196. package/dist/featureoptions.d.ts +0 -264
  197. package/dist/featureoptions.js +0 -480
  198. package/dist/featureoptions.js.map +0 -1
  199. package/dist/mqttclient.d.ts +0 -178
  200. package/dist/mqttclient.js +0 -310
  201. package/dist/mqttclient.js.map +0 -1
  202. package/dist/ui/featureoptions.js +0 -480
  203. package/dist/ui/featureoptions.js.map +0 -1
  204. package/dist/ui/webUi-featureoptions.mjs +0 -3765
@@ -0,0 +1,674 @@
1
+ /**
2
+ * A hierarchical feature option system for plugins and applications.
3
+ *
4
+ * The module exports two complementary surfaces:
5
+ *
6
+ * - **Pure functional core.** Catalog and config indices ({@link CatalogIndex}, {@link ConfigIndex}) carry every derived view of the catalog and configured options;
7
+ * pure builders ({@link buildCatalogIndex}, {@link buildConfigIndex}) construct them from raw inputs; pure transforms ({@link applySetOption},
8
+ * {@link applyClearOption}) compute new configured-options arrays without mutation; pure queries ({@link resolveScope}, {@link getDefaultValue},
9
+ * {@link isValueOption}, {@link optionExists}, {@link isDependencyMet}, {@link expandOption}) answer scope-aware questions over those indices. This is the
10
+ * single source of truth for option-array semantics, consumed wherever immutable state is the discipline (reducer-driven UIs, server-side renderers, time-travel
11
+ * debuggers, future consumers we have not built yet).
12
+ *
13
+ * - **Imperative class façade.** {@link FeatureOptions} bundles a {@link CatalogIndex}, a configured-options array, and a {@link ConfigIndex} into one object whose
14
+ * mutating methods (`setOption` / `clearOption` / the setters) delegate to the pure transforms internally. This is the legacy-friendly surface used by every
15
+ * plugin's Node-side code; the class's public API surface is identical to the pure-function core it delegates to.
16
+ *
17
+ * Two surfaces, one set of semantics. The class is a convenience over the pure functions, not a parallel implementation.
18
+ *
19
+ * @module
20
+ */
21
+ import type { HomebridgePluginLogging, Nullable } from "./util.ts";
22
+ /**
23
+ * Named built-in formatters available to {@link FeatureOptionEntry.render}. The string literals double as discoverable, autocomplete-friendly names and as the
24
+ * lookup keys into the registry that resolves them at catalog-rebuild time. Storing the catalog's renderer declaration as a string (rather than a function reference)
25
+ * preserves the catalog's data-only shape so it stays JSON-serializable when every option uses a named formatter; the function escape hatch on `render` remains
26
+ * available for bespoke needs that the registry does not cover.
27
+ *
28
+ * The set targets the unit categories that recur across plugin catalogs: bitrate (in either of the two common storage conventions), data size, percentages, and
29
+ * durations. Extend the union when a new format is genuinely shared across multiple plugins. Resist adding a formatter speculatively - the function escape
30
+ * hatch already covers one-off needs, and an unused formatter is dead surface that downstream plugins still see in their IDE autocomplete.
31
+ *
32
+ * @category Feature Options
33
+ */
34
+ export type FeatureOptionFormatter = "bps" | "bytes" | "kbps" | "ms" | "percent" | "seconds";
35
+ /**
36
+ * Entry describing a feature option.
37
+ *
38
+ * @property default - Default enabled/disabled state for this feature option.
39
+ * @property defaultValue - Optional. Default value for value-based feature options.
40
+ * @property description - Description of the feature option for display or documentation.
41
+ * @property group - Optional. Grouping/category for the feature option.
42
+ * @property inputSize - Optional. Width of the input field for a value-based feature option. Defaults to 5 characters.
43
+ * @property meta - Optional. An opaque, plugin-private annotation channel the core never interprets. HBPU's types deliberately cannot see inside `TMeta`;
44
+ * the value is carried verbatim through the catalog and forwarded to the documentation renderer's closures (the only surface that knows its
45
+ * concrete shape). This mirrors the OpenAPI `x-*` extension discipline, made type-safe: a plugin parameterizes the entry with its own
46
+ * annotation type, the core treats it as `unknown`, and the round-trip stays structurally unchanged rather than a naming convention.
47
+ * @property name - Name of the feature option (used in option strings).
48
+ * @property render - Optional. Maps the raw stored value of a value-centric option to a display string. Either a {@link FeatureOptionFormatter} string naming
49
+ * a built-in formatter (preferred when the format already exists in the registry, since this keeps the enclosing catalog JSON-serializable
50
+ * and lets every plugin share one implementation) or an inline function for bespoke formatting the registry does not cover. Consulted by
51
+ * {@link FeatureOptions.logFeature} when emitting deviation lines so the catalog stays the single source of truth for how an option's
52
+ * value renders; ignored for plain boolean options. When absent, values render as the raw string returned by {@link FeatureOptions.value}.
53
+ * An unrecognized formatter name throws at catalog-rebuild time, surfacing the misconfiguration loudly rather than silently producing the
54
+ * raw-value fallback.
55
+ *
56
+ * @typeParam TMeta - The concrete type of the opaque {@link FeatureOptionEntry.meta} annotation. Defaults to `unknown`, so a bare `FeatureOptionEntry` (the form every
57
+ * existing core consumer uses) resolves to `FeatureOptionEntry<unknown>` and stays assignable to the parameterized form, keeping the core non-generic.
58
+ */
59
+ export interface FeatureOptionEntry<TMeta = unknown> {
60
+ default: boolean;
61
+ defaultValue?: number | string;
62
+ description: string;
63
+ group?: string;
64
+ inputSize?: number;
65
+ meta?: TMeta;
66
+ name: string;
67
+ render?: FeatureOptionFormatter | ((value: string) => string);
68
+ }
69
+ /**
70
+ * Entry describing a feature option category.
71
+ *
72
+ * @property description - Description of the category.
73
+ * @property meta - Optional. An opaque, plugin-private annotation channel the core never interprets, mirroring {@link FeatureOptionEntry.meta} so the
74
+ * category side carries the same typed extension path; the documentation renderer forwards it to the category-scope closure, and the
75
+ * core treats it as `unknown` throughout.
76
+ * @property name - Name of the category.
77
+ *
78
+ * @typeParam TMeta - The concrete type of the opaque {@link FeatureCategoryEntry.meta} annotation. Defaults to `unknown` for the same backward-compatibility reason as
79
+ * {@link FeatureOptionEntry}: a bare `FeatureCategoryEntry` resolves to `FeatureCategoryEntry<unknown>` and stays assignable to the typed form.
80
+ */
81
+ export interface FeatureCategoryEntry<TMeta = unknown> {
82
+ description: string;
83
+ meta?: TMeta;
84
+ name: string;
85
+ }
86
+ /**
87
+ * Describes all possible scope hierarchy locations for a feature option.
88
+ */
89
+ export type OptionScope = "controller" | "device" | "global" | "none";
90
+ /**
91
+ * Resolved view of a feature option through the scope hierarchy. Captures the scope where the option was found, whether it's enabled, and the raw string value for
92
+ * value-centric options. This single traversal result serves both boolean queries and value queries, eliminating duplicate scope walks. Returned by
93
+ * {@link resolveScope}.
94
+ *
95
+ * @property enabled - The resolved enabled state at the highest-precedence scope where the option was found.
96
+ * @property optionValue - The raw string value when a value-centric option was set with an explicit value at the resolved scope. Absent otherwise.
97
+ * @property scope - The scope where the option resolved, or "none" when no explicit entry was found at any scope.
98
+ */
99
+ export interface ResolvedOptionEntry {
100
+ enabled: boolean;
101
+ optionValue?: string;
102
+ scope: OptionScope;
103
+ }
104
+ /**
105
+ * Immutable derived index over the catalog inputs ({@link FeatureCategoryEntry}[] + the options map). Every field except `categories` / `options` is derived from
106
+ * those two; the index bundles them with their derivations so a single value carries everything any caller needs to make catalog-level decisions in O(1).
107
+ *
108
+ * The index is built once per catalog at {@link buildCatalogIndex}; it is unchanged across configured-options mutations, so a consumer that holds a stable
109
+ * reference can rely on its query results until the catalog itself changes. The {@link FeatureOptions} class holds one internally; consumers driving reducers
110
+ * directly hold it as state and reuse it across every dispatch that does not touch the catalog.
111
+ *
112
+ * @property categories - The raw category list, preserved for callers that need to iterate it (rendering, validation, log enumeration).
113
+ * @property defaults - Lowercased-key map from canonical option name (the form {@link expandOption} produces) to its catalog-declared default.
114
+ * @property groupParents - Reverse index from a child option's expanded name to its parent group's expanded name. Catalog case preserved on the keys.
115
+ * @property groups - Forward index from a parent group's expanded name to its child options' expanded names.
116
+ * @property options - The raw options map, preserved alongside categories for the same reason.
117
+ * @property renderers - Lowercased-key map from canonical option name to its resolved value renderer (built-in or inline function). Built-in names
118
+ * that fail to resolve throw at index-build time rather than degrading silently at log time.
119
+ * @property sortedValueOptionNames - The keys of `valueOptions`, sorted longest-first, cached so the parser can do its greedy-prefix match without re-sorting on
120
+ * every Enable-entry parse.
121
+ * @property valueOptions - Lowercased-key map from canonical option name to its declared default value. The presence of a key in this map is the SSOT
122
+ * for "this option is value-centric."
123
+ */
124
+ export interface CatalogIndex {
125
+ readonly categories: readonly FeatureCategoryEntry[];
126
+ readonly defaults: Readonly<Record<string, boolean>>;
127
+ readonly groupParents: Readonly<Record<string, string>>;
128
+ readonly groups: Readonly<Record<string, readonly string[]>>;
129
+ readonly options: Readonly<Record<string, readonly FeatureOptionEntry[]>>;
130
+ readonly renderers: Readonly<Record<string, (value: string) => string>>;
131
+ readonly sortedValueOptionNames: readonly string[];
132
+ readonly valueOptions: Readonly<Record<string, number | string | undefined>>;
133
+ }
134
+ /**
135
+ * Immutable lookup index over the configured-options array. Each lookup key is either the raw lowercased tail of an Enable/Disable entry (always present) or a
136
+ * derived value-key for value-centric Enable entries that carry a trailing value segment. First-write-wins semantics on collision so the earliest entry in the
137
+ * configured-options array takes precedence over later duplicates - a user hand-editing config and accidentally listing an option twice gets the natural
138
+ * "first one is canonical" semantic.
139
+ *
140
+ * Built by {@link buildConfigIndex} from a `CatalogIndex` plus the configured-options array; consumed by {@link resolveScope} and {@link optionExists} to answer
141
+ * scope-aware questions in O(1).
142
+ */
143
+ export type ConfigIndex = ReadonlyMap<string, Readonly<{
144
+ enabled: boolean;
145
+ value?: string;
146
+ }>>;
147
+ /**
148
+ * Arguments for {@link applySetOption} and {@link FeatureOptions.setOption}. Carries the full mutation intent: the option key, optional scope id, enabled state,
149
+ * and optional value for value-centric options.
150
+ *
151
+ * @property enabled - True to enable, false to disable.
152
+ * @property id - Optional device or controller scope identifier. Omit to address the global scope.
153
+ * @property option - Feature option to set (case-insensitive).
154
+ * @property value - Optional value for value-centric options. Honored only when `enabled` is true and the option is value-centric.
155
+ */
156
+ export interface SetOptionArgs {
157
+ enabled: boolean;
158
+ id?: string;
159
+ option: string;
160
+ value?: number | string;
161
+ }
162
+ /**
163
+ * Arguments for {@link applyClearOption} and {@link FeatureOptions.clearOption}. Carries the addressing intent: the option key and optional scope id, with no
164
+ * enabled state or value because the operation forgets every entry addressing the target regardless of what they encoded.
165
+ *
166
+ * @property id - Optional device or controller scope identifier. Omit to address the global scope.
167
+ * @property option - Feature option to clear (case-insensitive).
168
+ */
169
+ export interface ClearOptionArgs {
170
+ id?: string;
171
+ option: string;
172
+ }
173
+ /**
174
+ * Compose a fully formed feature option string from a category and an option. Accepts either raw strings or the catalog entry objects, mirroring how the catalog
175
+ * is iterated at build time. The result is the canonical key shape every other helper consumes - lowercase the result to derive lookup-index keys, preserve the
176
+ * caller's casing to compose entry strings.
177
+ *
178
+ * @param category - Feature option category entry or category name string.
179
+ * @param option - Feature option entry or option name string.
180
+ *
181
+ * @returns The fully formed feature option in the form of `category.option`, or `category` alone when the option name is empty, or the empty string when the
182
+ * category name is empty.
183
+ */
184
+ export declare function expandOption(category: FeatureCategoryEntry | string, option: FeatureOptionEntry | string): string;
185
+ /**
186
+ * Build the catalog-derived index from raw categories + options. The result carries the raw inputs alongside every derivation needed for O(1) catalog queries -
187
+ * defaults, value-options registry, groups (both directions), renderers, and the longest-first cache the entry parser consumes. Throws when a built-in formatter
188
+ * name on a `render` declaration does not resolve, surfacing the misconfiguration at load time rather than silently degrading the log-emission path.
189
+ *
190
+ * The index is the catalog-side input to every other pure helper in this module. Build it once per catalog; reuse it across every configured-options mutation
191
+ * because the catalog is unchanged across those mutations. Categories without an entry in the options map are skipped silently (a plugin defines a category for
192
+ * future expansion before any option has migrated into it).
193
+ *
194
+ * @param categories - The raw category list.
195
+ * @param options - The raw options map keyed by category name.
196
+ *
197
+ * @returns The immutable catalog index.
198
+ */
199
+ export declare function buildCatalogIndex(categories: readonly FeatureCategoryEntry[], options: Readonly<Record<string, readonly FeatureOptionEntry[]>>): CatalogIndex;
200
+ /**
201
+ * Build the configured-options lookup index from a catalog index + the configured-options array. Each entry contributes one or two lookup keys via the shared
202
+ * `parseEntry`: the raw tail (always) and an extracted value key (for value-centric Enable entries). First-write-wins on collision so the earliest entry in
203
+ * the array takes precedence over later duplicates - users hand-editing config and accidentally listing an option twice get the natural "first one is canonical"
204
+ * semantic.
205
+ *
206
+ * Rebuild whenever the configured-options array changes; reuse across reads.
207
+ *
208
+ * @param catalog - The catalog index that defines what counts as a value-centric option.
209
+ * @param configuredOptions - The array of configured option strings.
210
+ *
211
+ * @returns The immutable lookup index.
212
+ */
213
+ export declare function buildConfigIndex(catalog: CatalogIndex, configuredOptions: readonly string[]): ConfigIndex;
214
+ /**
215
+ * Compute the new configured-options array after setting an option's enabled state (and optionally its value) at a given scope. Drops any prior entry addressing
216
+ * the same option-at-scope so the new entry is the sole survivor, then appends the freshly composed entry string. Pure: does not mutate the input array; the
217
+ * returned array is a fresh allocation.
218
+ *
219
+ * The composed entry's action segment is canonical "Enable" / "Disable"; the option and id segments preserve the caller's casing for readability since the
220
+ * lookup-index keys are case-insensitive anyway. Value tails are emitted only when meaningful - disabled or non-value options never carry one - so a subsequent
221
+ * {@link applyClearOption} or {@link applySetOption} addressing the same scope cleanly replaces whatever was there.
222
+ *
223
+ * @param options
224
+ * @param options.args - The mutation intent: option key, optional scope id, enabled state, optional value. See {@link SetOptionArgs}.
225
+ * @param options.catalog - The catalog index that defines what counts as a value-centric option (which determines whether to emit a value segment).
226
+ * @param options.configuredOptions - The current configured-options array.
227
+ *
228
+ * @returns The new configured-options array. A fresh allocation, never a shared reference with the input.
229
+ */
230
+ export declare function applySetOption({ args, catalog, configuredOptions }: {
231
+ args: SetOptionArgs;
232
+ catalog: CatalogIndex;
233
+ configuredOptions: readonly string[];
234
+ }): string[];
235
+ /**
236
+ * Compute the new configured-options array after clearing every entry addressing an option at a given scope. The match is value-aware: for value-centric options
237
+ * it covers both the bare scoped entry and any entry carrying a single trailing value segment, so a subsequent {@link applySetOption} cleanly replaces whatever
238
+ * was there.
239
+ *
240
+ * Pure: does not mutate the input array. When no entry matched the target, returns the input array reference unchanged so reference-equality consumers can detect
241
+ * a no-op without a contents comparison.
242
+ *
243
+ * @param options
244
+ * @param options.args - The addressing intent: option key, optional scope id. See {@link ClearOptionArgs}.
245
+ * @param options.catalog - The catalog index that defines what counts as a value-centric option (which the matcher consults via the shared parser).
246
+ * @param options.configuredOptions - The current configured-options array.
247
+ *
248
+ * @returns The new configured-options array, or the input array reference itself when nothing matched.
249
+ */
250
+ export declare function applyClearOption({ args, catalog, configuredOptions }: {
251
+ args: ClearOptionArgs;
252
+ catalog: CatalogIndex;
253
+ configuredOptions: readonly string[];
254
+ }): readonly string[];
255
+ /**
256
+ * Resolve a feature option through the scope hierarchy in a single traversal. Returns the scope where the option was found, its enabled state, and the raw value
257
+ * for value-centric options. This is the core resolution primitive that every higher-level query builds on - {@link FeatureOptions.test}, {@link FeatureOptions.scope},
258
+ * {@link FeatureOptions.value}, and {@link FeatureOptions.logFeature} all consume the same `ResolvedOptionEntry` shape from one walk.
259
+ *
260
+ * Resolution precedence: device beats controller beats global beats default. An explicit entry at a higher-precedence scope short-circuits the lookup, so the
261
+ * cost is O(1) in the configured-options array size.
262
+ *
263
+ * @param args
264
+ * @param args.catalog - The catalog index (consulted for the default when no scope matched).
265
+ * @param args.configIndex - The configured-options lookup index.
266
+ * @param args.controller - Optional controller scope identifier.
267
+ * @param args.defaultReturnValue - Fallback for options that don't appear in the catalog's defaults. Defaults to false.
268
+ * @param args.device - Optional device scope identifier.
269
+ * @param args.option - The option key to resolve (case-insensitive).
270
+ *
271
+ * @returns The resolved view: scope, enabled state, optional raw value.
272
+ */
273
+ export declare function resolveScope({ catalog, configIndex, controller, defaultReturnValue, device, option }: {
274
+ catalog: CatalogIndex;
275
+ configIndex: ConfigIndex;
276
+ controller?: string;
277
+ defaultReturnValue?: boolean;
278
+ device?: string;
279
+ option: string;
280
+ }): ResolvedOptionEntry;
281
+ /**
282
+ * Return the catalog-declared default for a feature option, falling back to a caller-supplied default for options that don't appear in the catalog at all.
283
+ *
284
+ * @param args
285
+ * @param args.catalog - The catalog index.
286
+ * @param args.defaultReturnValue - Fallback when the option is not in the catalog's defaults map. Defaults to false.
287
+ * @param args.option - The option key (case-insensitive).
288
+ *
289
+ * @returns The default value: catalog declaration if present, fallback otherwise.
290
+ */
291
+ export declare function getDefaultValue({ catalog, defaultReturnValue, option }: {
292
+ catalog: CatalogIndex;
293
+ defaultReturnValue?: boolean;
294
+ option: string;
295
+ }): boolean;
296
+ /**
297
+ * Return whether a feature option is value-centric (carries a `defaultValue` in its catalog declaration). The presence of the option's lowercased key in the
298
+ * catalog's `valueOptions` map is the SSOT for this predicate.
299
+ *
300
+ * @param catalog - The catalog index.
301
+ * @param option - The option key (case-insensitive). Empty string returns false.
302
+ *
303
+ * @returns True for value-centric options, false otherwise.
304
+ */
305
+ export declare function isValueOption(catalog: CatalogIndex, option: string): boolean;
306
+ /**
307
+ * Return whether an option has been explicitly configured at the given scope. Distinct from {@link resolveScope}, which walks the hierarchy; this predicate
308
+ * answers only "did the user set this entry at THIS scope?" without consulting any higher or lower scopes.
309
+ *
310
+ * @param args
311
+ * @param args.configIndex - The configured-options lookup index.
312
+ * @param args.id - Optional scope identifier (device or controller). Omit to address the global scope.
313
+ * @param args.option - The option key (case-insensitive).
314
+ *
315
+ * @returns True when an explicit entry addresses this option-at-scope.
316
+ */
317
+ export declare function optionExists({ configIndex, id, option }: {
318
+ configIndex: ConfigIndex;
319
+ id?: string;
320
+ option: string;
321
+ }): boolean;
322
+ /**
323
+ * Return whether a grouped option's parent is currently enabled at the given scope. For options that aren't grouped (no `group` property in the catalog entry),
324
+ * always returns `true` - there is no dependency to fail. For grouped options, traverses the scope hierarchy via {@link resolveScope} to evaluate the parent's
325
+ * effective state at the requested device + controller view.
326
+ *
327
+ * This is the SSOT for "is this option's row currently usable?" Every caller that wants to know whether to render a grouped option's row, count it as visible,
328
+ * or honor its dependency-hidden state asks this function rather than reconstructing the parent path themselves. The reverse-lookup from option to parent uses
329
+ * the pre-built `catalog.groupParents` index, so the predicate is O(1) regardless of option-key length.
330
+ *
331
+ * @param args
332
+ * @param args.catalog - The catalog index.
333
+ * @param args.configIndex - The configured-options lookup index.
334
+ * @param args.controller - Optional controller scope identifier.
335
+ * @param args.defaultReturnValue - Fallback default for options not in the catalog. Defaults to false.
336
+ * @param args.device - Optional device scope identifier.
337
+ * @param args.option - Fully-qualified feature option string (e.g., `"Motion.Sensitivity"`). Case-insensitive.
338
+ *
339
+ * @returns `true` when the option has no dependency or its parent is currently enabled at the requested scope; `false` when the parent is currently disabled.
340
+ */
341
+ export declare function isDependencyMet({ catalog, configIndex, controller, defaultReturnValue, device, option }: {
342
+ catalog: CatalogIndex;
343
+ configIndex: ConfigIndex;
344
+ controller?: string;
345
+ defaultReturnValue?: boolean;
346
+ device?: string;
347
+ option: string;
348
+ }): boolean;
349
+ /**
350
+ * FeatureOptions provides a hierarchical feature option system for plugins and applications.
351
+ *
352
+ * Supports global, controller, and device-level configuration, value-centric feature options, grouping, and category management.
353
+ *
354
+ * This class is the imperative façade over the pure functional core exposed by this module ({@link buildCatalogIndex}, {@link applySetOption},
355
+ * {@link applyClearOption}, {@link resolveScope}, etc.). Reducer-driven consumers that want immutable state should call the pure functions directly; imperative
356
+ * Node-side plugin code uses this class for the same semantics with mutation-friendly ergonomics.
357
+ *
358
+ * @example
359
+ *
360
+ * ```ts
361
+ * // Define categories and options.
362
+ * const categories = [
363
+ *
364
+ * { name: "motion", description: "Motion Options" },
365
+ * { name: "audio", description: "Audio Options" }
366
+ * ];
367
+ *
368
+ * const options = {
369
+ *
370
+ * motion: [
371
+ * { name: "detect", default: true, description: "Enable motion detection." }
372
+ * ],
373
+ *
374
+ * audio: [
375
+ * { name: "volume", default: false, defaultValue: 50, description: "Audio volume." }
376
+ * ]
377
+ * };
378
+ *
379
+ * // Instantiate FeatureOptions.
380
+ * const featureOpts = new FeatureOptions(categories, options, ["Enable.motion.detect"]);
381
+ *
382
+ * // Check if a feature is enabled.
383
+ * const motionEnabled = featureOpts.test("motion.detect");
384
+ *
385
+ * // Get a value-centric feature option.
386
+ * const volume = featureOpts.value("audio.volume");
387
+ * ```
388
+ *
389
+ * @see FeatureOptionEntry
390
+ * @see FeatureCategoryEntry
391
+ * @see OptionScope
392
+ */
393
+ export declare class FeatureOptions {
394
+ #private;
395
+ /**
396
+ * Default return value for unknown options (defaults to false).
397
+ */
398
+ defaultReturnValue: boolean;
399
+ /**
400
+ * Create a new FeatureOptions instance.
401
+ *
402
+ * @param categories - Array of feature option categories.
403
+ * @param options - Dictionary mapping category names to arrays of feature options.
404
+ * @param configuredOptions - Optional. Array of currently configured option strings.
405
+ *
406
+ * @example
407
+ *
408
+ * ```ts
409
+ * const featureOpts = new FeatureOptions(categories, options, ["Enable.motion.detect"]);
410
+ * ```
411
+ */
412
+ constructor(categories: FeatureCategoryEntry[], options: Record<string, FeatureOptionEntry[]>, configuredOptions?: string[]);
413
+ /**
414
+ * Return the default value for an option.
415
+ *
416
+ * @param option - Feature option to check.
417
+ *
418
+ * @returns Returns true or false, depending on the option default.
419
+ */
420
+ defaultValue(option: string): boolean;
421
+ /**
422
+ * Return whether the option explicitly exists in the list of configured options.
423
+ *
424
+ * @param option - Feature option to check.
425
+ * @param id - Optional device or controller scope identifier to check.
426
+ *
427
+ * @returns Returns true if the option has been explicitly configured, false otherwise.
428
+ */
429
+ exists(option: string, id?: string): boolean;
430
+ /**
431
+ * Return whether a grouped option's parent is currently enabled at the given scope. For options that aren't grouped (no `group` property in the catalog entry),
432
+ * always returns `true` - there is no dependency to fail. For grouped options, traverses the scope hierarchy via {@link resolveScope} to evaluate the parent's
433
+ * effective state at the requested device + controller view.
434
+ *
435
+ * This is the SSOT for "is this option's row currently usable?" Every caller that wants to know whether to render a grouped option's row, count it as visible,
436
+ * or honor its dependency-hidden state asks the model rather than reconstructing the parent path themselves. The reverse-lookup from option to parent uses the
437
+ * pre-built {@link CatalogIndex.groupParents} index, so the predicate is O(1) regardless of option-key length.
438
+ *
439
+ * @param option - Fully-qualified feature option string (e.g., `"Motion.Sensitivity"`). Case-insensitive.
440
+ * @param device - Optional device scope identifier, forwarded to {@link resolveScope}.
441
+ * @param controller - Optional controller scope identifier, forwarded to {@link resolveScope}.
442
+ *
443
+ * @returns `true` when the option has no dependency or its parent is currently enabled at the requested scope; `false` when the parent is currently disabled.
444
+ */
445
+ isDependencyMet(option: string, device?: string, controller?: string): boolean;
446
+ /**
447
+ * Return a fully formed feature option string.
448
+ *
449
+ * @param category - Feature option category entry or category name string.
450
+ * @param option - Feature option entry of option name string.
451
+ *
452
+ * @returns Returns a fully formed feature option in the form of `category.option`.
453
+ */
454
+ expandOption(category: FeatureCategoryEntry | string, option: FeatureOptionEntry | string): string;
455
+ /**
456
+ * Parse a floating point feature option value.
457
+ *
458
+ * @param option - Feature option to check.
459
+ * @param device - Optional device scope identifier.
460
+ * @param controller - Optional controller scope identifier.
461
+ *
462
+ * @returns Returns the value of a value-centric option as a floating point number, `undefined` if it doesn't exist or couldn't be parsed, and `null` if disabled.
463
+ */
464
+ getFloat(option: string, device?: string, controller?: string): Nullable<number | undefined>;
465
+ /**
466
+ * Parse an integer feature option value.
467
+ *
468
+ * @param option - Feature option to check.
469
+ * @param device - Optional device scope identifier.
470
+ * @param controller - Optional controller scope identifier.
471
+ *
472
+ * @returns Returns the value of a value-centric option as an integer, `undefined` if it doesn't exist or couldn't be parsed, and `null` if disabled.
473
+ */
474
+ getInteger(option: string, device?: string, controller?: string): Nullable<number | undefined>;
475
+ /**
476
+ * Return whether an option has been set in either the device or controller scope context.
477
+ *
478
+ * @param option - Feature option to check.
479
+ *
480
+ * @returns Returns true if the option is set at the device or controller level and false otherwise.
481
+ */
482
+ isScopeDevice(option: string, device: string): boolean;
483
+ /**
484
+ * Return whether an option has been set in the global scope context.
485
+ *
486
+ * @param option - Feature option to check.
487
+ *
488
+ * @returns Returns true if the option is set globally and false otherwise.
489
+ */
490
+ isScopeGlobal(option: string): boolean;
491
+ /**
492
+ * Return whether an option is value-centric or not.
493
+ *
494
+ * @param option - Feature option entry or string to check.
495
+ *
496
+ * @returns Returns true if it is a value-centric option and false otherwise.
497
+ */
498
+ isValue(option: string): boolean;
499
+ /**
500
+ * Emit an INFO-level log line for a feature option, but only when the user's effective configuration deviates from the declared default.
501
+ *
502
+ * This is the executable form of the project-wide startup-log convention: restating a default is log noise, and deviations should be reported in both directions - a
503
+ * default-off feature the user turned on, a default-on feature the user turned off, and a value the user customized away from the registered default. Callers pass
504
+ * the option key and a human-readable label; this method handles the direction detection and the message synthesis so every plugin emits the same shape from one
505
+ * place. If the convention ever evolves, every call site picks up the change without any source modification.
506
+ *
507
+ * Polymorphic over option type, mirroring how {@link FeatureOptions.test} and {@link FeatureOptions.value} already dispatch on whether the option is value-centric.
508
+ * The distinct emitted-line shapes, across these state combinations:
509
+ *
510
+ * | Option type | User state vs. default | Emitted line |
511
+ * |------------------|---------------------------------------------------------|------------------------------------|
512
+ * | Boolean | matches default | (silent) |
513
+ * | Boolean | default off, enabled | `<label> enabled.` |
514
+ * | Boolean | default on, disabled | `<label> disabled.` |
515
+ * | Value-centric | both axes match | (silent) |
516
+ * | Value-centric | default on, disabled | `<label> disabled.` |
517
+ * | Value-centric | default off, enabled (value matches or differs) | `<label> enabled at <value>.` |
518
+ * | Value-centric | default on, enabled, value differs from declared default | `<label> set to <value>.` |
519
+ *
520
+ * A value-centric option enabled with no resolvable value anywhere - no catalog-declared default and no explicit value at any scope - collapses to the plain
521
+ * `<label> enabled.` line above rather than the `enabled at <value>` form, since there is nothing meaningful to render after "at" (see the defensive fallback in
522
+ * the implementation below).
523
+ *
524
+ * Value rendering consults the catalog-declared {@link FeatureOptionEntry.render} when present; otherwise the raw string returned by {@link FeatureOptions.value}
525
+ * is used. The renderer may be either a {@link FeatureOptionFormatter} string naming a built-in formatter from the shared registry (preferred when the format exists
526
+ * there, since this keeps the catalog JSON-serializable and lets every plugin share one implementation) or an inline function for bespoke cases. Declaring the
527
+ * renderer at the option's catalog entry keeps display formatting a single source of truth shared by `logFeature` and any future surface that displays the value.
528
+ *
529
+ * Scope precedence matches {@link FeatureOptions.test}: device wins over controller wins over global wins over default. Pass the scope arguments that describe the
530
+ * vantage point you want to log from - typically a device identifier for accessory-level configuration, optionally with a controller identifier when the plugin's
531
+ * controller scope is meaningful (e.g., UniFi Protect controllers).
532
+ *
533
+ * @param option - Feature option to check (same key shape as {@link FeatureOptions.test}; case-insensitive).
534
+ * @param label - Human-readable label that prefixes the emitted message. Used verbatim as the first `%s` argument; should be a noun phrase like "Motion sensor"
535
+ * or "Read-only mode" so the rendered line reads naturally ("Motion sensor enabled." / "Read-only mode disabled.").
536
+ * @param log - The plugin's logger. The emitted message is INFO-level; debug-level enumeration of the full feature surface is a separate concern handled by
537
+ * the caller.
538
+ * @param device - Optional device scope identifier, forwarded to {@link FeatureOptions.test}.
539
+ * @param controller - Optional controller scope identifier, forwarded to {@link FeatureOptions.test}.
540
+ *
541
+ * @example
542
+ *
543
+ * ```ts
544
+ * // Boolean option, inside a plugin's `configureMotion()` for a specific device:
545
+ * featureOptions.logFeature("Motion", "Motion sensor", log, device.mac);
546
+ *
547
+ * // Value-centric option - the message shape adapts to which axis (boolean, value, or both) deviated:
548
+ * featureOptions.logFeature("Stream.Bandwidth", "Bandwidth", log, device.mac);
549
+ *
550
+ * // With a controller scope:
551
+ * featureOptions.logFeature("HKSV.Record", "HKSV recording", log, device.mac, controller.id);
552
+ * ```
553
+ */
554
+ logFeature(option: string, label: string, log: HomebridgePluginLogging, device?: string, controller?: string): void;
555
+ /**
556
+ * Remove every configured-options entry addressing the given option at the given scope.
557
+ *
558
+ * Callers express intent ("forget any configuration for option X at scope Y") and the model owns the entry-format end-to-end. The match is value-aware: for
559
+ * value-centric options it covers both the bare scoped entry and any entry carrying a single trailing value segment, so a subsequent {@link setOption} cleanly
560
+ * replaces whatever was there. No-op when no entry addresses the target scope, so callers can treat this as a repeatable reset.
561
+ *
562
+ * @param args - The addressing intent: option key and optional scope id. See {@link ClearOptionArgs}.
563
+ *
564
+ * @example
565
+ *
566
+ * ```ts
567
+ * // Remove any configured value for "Audio.Volume" on device ABC123 (drops both `Enable.Audio.Volume.ABC123` and `Enable.Audio.Volume.ABC123.50`).
568
+ * featureOpts.clearOption({ option: "Audio.Volume", id: "ABC123" });
569
+ * ```
570
+ */
571
+ clearOption(args: ClearOptionArgs): void;
572
+ /**
573
+ * Set the enabled state (and optionally the value) for an option at a given scope, replacing any prior entry for the same option-at-scope.
574
+ *
575
+ * This is the single mutation primitive for individual feature options. Callers express intent ("enable option X at scope Y, with value Z") and the model owns
576
+ * both the encoding and the prior-entry replacement - the configured-options array is canonical, the lookup index is rebuilt automatically, and the entry-string
577
+ * format never leaks past this method. Value segments are emitted only when `enabled` is true and the option is value-centric; passing `value` for a non-value or
578
+ * disabled option is silently dropped because the resulting entry would be meaningless under the resolution rules.
579
+ *
580
+ * @param args - The mutation intent: option key, optional scope id, enabled state, and optional value. See {@link SetOptionArgs}.
581
+ *
582
+ * @example
583
+ *
584
+ * ```ts
585
+ * // Disable "Motion.Detect" globally.
586
+ * featureOpts.setOption({ enabled: false, option: "Motion.Detect" });
587
+ *
588
+ * // Enable "Audio.Volume" on device ABC123 with value 50, replacing any prior device-scoped entry for the same option.
589
+ * featureOpts.setOption({ enabled: true, id: "ABC123", option: "Audio.Volume", value: 50 });
590
+ * ```
591
+ */
592
+ setOption(args: SetOptionArgs): void;
593
+ /**
594
+ * Return the scope hierarchy location of an option.
595
+ *
596
+ * @param option - Feature option to check.
597
+ * @param device - Optional device scope identifier.
598
+ * @param controller - Optional controller scope identifier.
599
+ *
600
+ * @returns Returns the location in the scope hierarchy of `option`.
601
+ */
602
+ scope(option: string, device?: string, controller?: string): OptionScope;
603
+ /**
604
+ * Return the current state of a feature option, traversing the scope hierarchy.
605
+ *
606
+ * @param option - Feature option to check.
607
+ * @param device - Optional device scope identifier.
608
+ * @param controller - Optional controller scope identifier.
609
+ *
610
+ * @returns Returns true if the option is enabled, and false otherwise.
611
+ */
612
+ test(option: string, device?: string, controller?: string): boolean;
613
+ /**
614
+ * Return the value associated with a value-centric feature option, traversing the scope hierarchy.
615
+ *
616
+ * @param option - Feature option to check.
617
+ * @param device - Optional device scope identifier.
618
+ * @param controller - Optional controller scope identifier.
619
+ *
620
+ * @returns Returns the current value associated with `option` if the feature option is enabled, `null` if disabled (or not a value-centric feature option), or
621
+ * `undefined` if it's not specified.
622
+ */
623
+ value(option: string, device?: string, controller?: string): Nullable<string | undefined>;
624
+ /**
625
+ * Return the list of available feature option categories.
626
+ *
627
+ * @returns Returns the current list of available feature option categories.
628
+ */
629
+ get categories(): FeatureCategoryEntry[];
630
+ /**
631
+ * Set the list of available feature option categories.
632
+ *
633
+ * @param category - Array of available categories.
634
+ */
635
+ set categories(category: FeatureCategoryEntry[]);
636
+ /**
637
+ * Return the list of currently configured feature options.
638
+ *
639
+ * @returns Returns the currently configured list of feature options.
640
+ */
641
+ get configuredOptions(): string[];
642
+ /**
643
+ * Set the list of currently configured feature options.
644
+ *
645
+ * @param options - Array of configured feature options.
646
+ */
647
+ set configuredOptions(options: string[] | null | undefined);
648
+ /**
649
+ * Return a reverse index mapping each child option to its parent group. This provides O(1) child-to-parent lookups, complementing the forward `groups` map that maps
650
+ * parents to their children.
651
+ *
652
+ * @returns Returns a record mapping child option names to their parent group names.
653
+ */
654
+ get groupParents(): Record<string, string>;
655
+ /**
656
+ * Return the list of available feature option groups.
657
+ *
658
+ * @returns Returns the current list of available feature option groups.
659
+ */
660
+ get groups(): Record<string, string[]>;
661
+ /**
662
+ * Return the list of available feature options.
663
+ *
664
+ * @returns Returns the current list of available feature options.
665
+ */
666
+ get options(): Record<string, FeatureOptionEntry[]>;
667
+ /**
668
+ * Set the list of available feature options.
669
+ *
670
+ * @param options - Array of available feature options.
671
+ */
672
+ set options(options: Record<string, FeatureOptionEntry[]> | null | undefined);
673
+ }
674
+ //# sourceMappingURL=featureOptions.d.ts.map