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.
- 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 +128 -0
- package/dist/backpressure.js +273 -0
- package/dist/backpressure.js.map +1 -0
- 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 -257
- 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 +70 -4
- package/dist/ffmpeg/fmp4.js +100 -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 +143 -91
- package/dist/ffmpeg/process.js +406 -265
- package/dist/ffmpeg/process.js.map +1 -1
- package/dist/ffmpeg/record.d.ts +302 -188
- package/dist/ffmpeg/record.js +408 -560
- 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 -244
- package/dist/ffmpeg/rtp.js.map +1 -1
- package/dist/ffmpeg/settings.d.ts +5 -1
- package/dist/ffmpeg/settings.js +20 -2
- package/dist/ffmpeg/settings.js.map +1 -1
- package/dist/ffmpeg/stream.d.ts +57 -107
- package/dist/ffmpeg/stream.js +121 -148
- 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 -5
- package/dist/index.js +8 -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 +597 -45
- package/dist/util.js +787 -68
- 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
package/dist/service.js
CHANGED
|
@@ -12,7 +12,13 @@ let hasNameUUIDs = null;
|
|
|
12
12
|
// service without holding a reference to the HAP object itself. This reflection pattern extracts it from the first characteristic on any service instance, which always
|
|
13
13
|
// exists (every service has at least one required characteristic). Centralized here so the fragile cast lives in one place.
|
|
14
14
|
function getCharacteristicConstructor(service) {
|
|
15
|
-
|
|
15
|
+
// Every HAP service is constructed with at least one required characteristic, so the first slot is always populated. The explicit check satisfies
|
|
16
|
+
// `noUncheckedIndexedAccess` and throws loudly in the unreachable event that a service arrives without characteristics.
|
|
17
|
+
const [first] = service.characteristics;
|
|
18
|
+
if (!first) {
|
|
19
|
+
throw new Error("Service has no characteristics; cannot resolve the Characteristic constructor.");
|
|
20
|
+
}
|
|
21
|
+
return first.constructor;
|
|
16
22
|
}
|
|
17
23
|
/**
|
|
18
24
|
* Initializes the cached UUID Sets for service characteristic lookups.
|
|
@@ -22,48 +28,43 @@ function getCharacteristicConstructor(service) {
|
|
|
22
28
|
* @internal
|
|
23
29
|
*/
|
|
24
30
|
function initServiceUUIDSets(service) {
|
|
25
|
-
// Already initialized.
|
|
26
31
|
if (requiresConfiguredNameUUIDs) {
|
|
27
32
|
return;
|
|
28
33
|
}
|
|
29
|
-
// Grab the constructor from the instance of our service so we can access the static UUID properties.
|
|
34
|
+
// Grab the constructor from the instance of our service so we can access the static UUID properties. HAP's static service entries are populated unconditionally at
|
|
35
|
+
// module load, so the UUID lookup is total in practice. We centralize the `undefined` handling here so the individual Set contents read cleanly.
|
|
30
36
|
const ctor = service.constructor;
|
|
31
|
-
|
|
32
|
-
requiresConfiguredNameUUIDs = new Set([
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
// Services that support the ConfiguredName characteristic (includes required).
|
|
37
|
+
const uuidOf = (name) => ctor[name]?.UUID ?? "";
|
|
38
|
+
requiresConfiguredNameUUIDs = new Set(["InputSource", "Television", "WiFiRouter"].map(uuidOf));
|
|
39
|
+
// The "has" sets are supersets of the "requires" sets - any service that requires a characteristic also supports it. Call sites combine the two predicates as
|
|
40
|
+
// `!serviceRequires(...) && serviceHas(...)` to detect the optional-but-supported case.
|
|
36
41
|
hasConfiguredNameUUIDs = new Set([
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
]);
|
|
40
|
-
|
|
41
|
-
requiresNameUUIDs = new Set([
|
|
42
|
-
ctor.AccessoryInformation.UUID, ctor.Assistant.UUID, ctor.InputSource.UUID
|
|
43
|
-
]);
|
|
44
|
-
// Services that support the Name characteristic (includes required).
|
|
42
|
+
"AccessoryInformation", "ContactSensor", "InputSource", "Lightbulb", "MotionSensor", "OccupancySensor", "SmartSpeaker", "StatelessProgrammableSwitch", "Switch",
|
|
43
|
+
"Television", "Valve", "WiFiRouter"
|
|
44
|
+
].map(uuidOf));
|
|
45
|
+
requiresNameUUIDs = new Set(["AccessoryInformation", "Assistant", "InputSource"].map(uuidOf));
|
|
45
46
|
hasNameUUIDs = new Set([
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
ctor.StatelessProgrammableSwitch.UUID, ctor.Switch.UUID, ctor.TargetControl.UUID, ctor.Television.UUID, ctor.TemperatureSensor.UUID,
|
|
53
|
-
ctor.Thermostat.UUID, ctor.Valve.UUID, ctor.Window.UUID, ctor.WindowCovering.UUID
|
|
54
|
-
]);
|
|
47
|
+
"AccessoryInformation", "AirPurifier", "AirQualitySensor", "Assistant", "Battery", "CarbonDioxideSensor", "CarbonMonoxideSensor", "ContactSensor", "Door", "Doorbell",
|
|
48
|
+
"Fan", "Fanv2", "Faucet", "FilterMaintenance", "GarageDoorOpener", "HeaterCooler", "HumidifierDehumidifier", "HumiditySensor", "InputSource", "IrrigationSystem",
|
|
49
|
+
"LeakSensor", "Lightbulb", "LightSensor", "LockMechanism", "MotionSensor", "OccupancySensor", "Outlet", "SecuritySystem", "Slats", "SmartSpeaker", "SmokeSensor",
|
|
50
|
+
"StatefulProgrammableSwitch", "StatelessProgrammableSwitch", "Switch", "TargetControl", "Television", "TemperatureSensor", "Thermostat", "Valve", "Window",
|
|
51
|
+
"WindowCovering"
|
|
52
|
+
].map(uuidOf));
|
|
55
53
|
}
|
|
56
54
|
/**
|
|
57
55
|
* Utility method that either creates a new service on an accessory if needed, or returns an existing one. Optionally, it executes a callback to initialize a new
|
|
58
56
|
* service instance. Additionally, the various name characteristics of the service are set to the specified name, and optionally added if necessary.
|
|
59
57
|
*
|
|
58
|
+
* @typeParam T - The concrete Service subclass being acquired. Inferred from `serviceType` so callers receive the specific subclass type back rather than
|
|
59
|
+
* the wider `Service` type.
|
|
60
60
|
* @param accessory - The Homebridge accessory to check or modify.
|
|
61
|
-
* @param serviceType - The type of service to instantiate or retrieve.
|
|
61
|
+
* @param serviceType - The type of service to instantiate or retrieve. Must be a HAP Service subclass with the standard `(displayName?, subtype?)` constructor;
|
|
62
|
+
* see {@link AcquireServiceTarget}.
|
|
62
63
|
* @param name - Name to be displayed to the end user for this service.
|
|
63
64
|
* @param subtype - Optional service subtype to uniquely identify the service.
|
|
64
65
|
* @param onServiceCreate - Optional callback invoked only when a new service is created, receiving the new service as its argument.
|
|
65
66
|
*
|
|
66
|
-
* @returns Returns the created or retrieved service
|
|
67
|
+
* @returns Returns the created or retrieved service. Construction failures throw rather than returning `null`.
|
|
67
68
|
*
|
|
68
69
|
* @remarks
|
|
69
70
|
* This method ensures that the service's display name and available name characteristics are updated to the specified name. If `onServiceCreate` is provided,
|
|
@@ -73,10 +74,11 @@ function initServiceUUIDSets(service) {
|
|
|
73
74
|
*
|
|
74
75
|
* @example
|
|
75
76
|
* ```typescript
|
|
76
|
-
* // Example: Ensure a Lightbulb service exists with a user-friendly name, and initialize it if newly created.
|
|
77
|
-
*
|
|
77
|
+
* // Example: Ensure a Lightbulb service exists with a user-friendly name, and initialize it if newly created. The return type is narrowed to `Lightbulb | null`,
|
|
78
|
+
* // so callers can invoke subclass-specific behavior on the result without casts.
|
|
79
|
+
* const lightbulbService = acquireService(accessory, hap.Service.Lightbulb, "Living Room Lamp", undefined, (svc): void => {
|
|
78
80
|
*
|
|
79
|
-
* // Called only if the service is newly created.
|
|
81
|
+
* // Called only if the service is newly created. `svc` is typed as `Lightbulb` here.
|
|
80
82
|
* svc.setCharacteristic(hap.Characteristic.On, false);
|
|
81
83
|
* });
|
|
82
84
|
*
|
|
@@ -87,33 +89,33 @@ function initServiceUUIDSets(service) {
|
|
|
87
89
|
* }
|
|
88
90
|
* ```
|
|
89
91
|
*
|
|
90
|
-
* @see setServiceName
|
|
91
|
-
* @see validService
|
|
92
|
+
* @see setServiceName - updates the newly created (or existing) service's name-related characteristics.
|
|
93
|
+
* @see validService - validate or prune services after acquisition.
|
|
92
94
|
* @category Accessory
|
|
93
95
|
*/
|
|
94
96
|
export function acquireService(accessory, serviceType, name, subtype, onServiceCreate) {
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
//
|
|
97
|
+
// Sanitize once up front because HomeKit's strict naming rules apply both to the constructor's displayName and to the ConfiguredName / Name characteristics that
|
|
98
|
+
// setServiceName populates - same source string, same validation contract.
|
|
99
|
+
const sanitized = sanitizeName(name);
|
|
100
|
+
// Find the service, if it exists. The cast back to `T` is sound because `getService` / `getServiceById` look up by the constructor's UUID brand, and the only
|
|
101
|
+
// service registered against that UUID is one this function (or a sibling caller using the same constructor) created - i.e., an instance of `T`.
|
|
102
|
+
let service = (subtype ? accessory.getServiceById(serviceType, subtype) : accessory.getService(serviceType));
|
|
100
103
|
if (!service) {
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
service = new serviceType(
|
|
104
|
-
// Grab the Characteristic constructor from the instance of our service so we can set the individual characteristics without needing the HAP object directly.
|
|
104
|
+
// The narrow constructor signature in `AcquireServiceTarget<T>` lets us invoke `new serviceType(sanitized, subtype)` directly - no cast, no non-null assertion.
|
|
105
|
+
// The type system expresses what the runtime requires: callers pass a Service subclass with the standard `(displayName?, subtype?)` constructor.
|
|
106
|
+
service = new serviceType(sanitized, subtype);
|
|
105
107
|
const characteristic = getCharacteristicConstructor(service);
|
|
106
|
-
//
|
|
108
|
+
// HAP can pre-populate ConfiguredName in a freshly-constructed service's default optional set, so this guard prevents adding it a second time within this single
|
|
109
|
+
// construction. Re-acquisition of an already-existing service is a separate case, already gated by the `!service` check above.
|
|
107
110
|
if (!serviceRequiresConfiguredName(service) && serviceHasConfiguredName(service) &&
|
|
108
111
|
!service.optionalCharacteristics.some(x => (x.UUID === characteristic.ConfiguredName.UUID))) {
|
|
109
112
|
service.addOptionalCharacteristic(characteristic.ConfiguredName);
|
|
110
113
|
}
|
|
111
|
-
//
|
|
114
|
+
// Same duplicate-guard rationale as the ConfiguredName check above, applied to the Name characteristic.
|
|
112
115
|
if (!serviceRequiresName(service) && serviceHasName(service) && !service.optionalCharacteristics.some(x => (x.UUID === characteristic.Name.UUID))) {
|
|
113
116
|
service.addOptionalCharacteristic(characteristic.Name);
|
|
114
117
|
}
|
|
115
|
-
|
|
116
|
-
setServiceName(service, name);
|
|
118
|
+
setServiceName(service, sanitized);
|
|
117
119
|
accessory.addService(service);
|
|
118
120
|
if (onServiceCreate) {
|
|
119
121
|
onServiceCreate(service);
|
|
@@ -151,22 +153,46 @@ export function acquireService(accessory, serviceType, name, subtype, onServiceC
|
|
|
151
153
|
* validService(accessory, Service.Switch, (hasService) => hasService || config.enableSwitch);
|
|
152
154
|
* ```
|
|
153
155
|
*
|
|
154
|
-
* @see acquireService
|
|
156
|
+
* @see acquireService - to add or retrieve services.
|
|
155
157
|
* @category Accessory
|
|
156
158
|
*/
|
|
157
159
|
export function validService(accessory, serviceType, validate, subtype) {
|
|
158
|
-
// Find the service, if it exists.
|
|
159
160
|
const service = subtype ? accessory.getServiceById(serviceType, subtype) : accessory.getService(serviceType);
|
|
160
|
-
//
|
|
161
|
+
// Resolve `validate` against the current presence and remove the service when the validator votes false. The function-form receives the actual presence boolean so
|
|
162
|
+
// callers can express add-if-missing semantics like `(has) => has || config.enableSwitch`.
|
|
161
163
|
if (!((typeof validate === "function") ? validate(!!service) : validate)) {
|
|
162
164
|
if (service) {
|
|
163
165
|
accessory.removeService(service);
|
|
164
166
|
}
|
|
165
167
|
return false;
|
|
166
168
|
}
|
|
167
|
-
// We have a valid service.
|
|
168
169
|
return true;
|
|
169
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Build a `validService` predicate for a service gated on a hardware capability and a user toggle, applying an additive-eager / subtractive-conservative asymmetry
|
|
173
|
+
* between the two: the user `toggle` is absolute - when false, the service is removed - while the hardware `capability` is conservative - an existing service is kept
|
|
174
|
+
* through a transient capability-false, and a new service is created only when the capability reports.
|
|
175
|
+
*
|
|
176
|
+
* @param options - The `capability` and `toggle` inputs for the gate.
|
|
177
|
+
*
|
|
178
|
+
* @returns A `validService` function-form predicate, `(hasService) => toggle && (hasService || capability)`.
|
|
179
|
+
*
|
|
180
|
+
* @remarks
|
|
181
|
+
* Pass the result as `validService`'s `validate` argument. The asymmetry keeps a capability-gated service from being removed during a transient window in which the
|
|
182
|
+
* device under-reports its capability, while still honoring a user who disables the service. A service with no user toggle should gate on its capability directly.
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```typescript
|
|
186
|
+
* // Keep the service while its user toggle is on, add it when the capability reports, and keep an existing one through a transient capability-false.
|
|
187
|
+
* validService(accessory, Service.Switch, capabilityGate({ capability: deviceReportsFeature, toggle: config.enableSwitch }));
|
|
188
|
+
* ```
|
|
189
|
+
*
|
|
190
|
+
* @see validService - consumes the returned predicate.
|
|
191
|
+
* @category Accessory
|
|
192
|
+
*/
|
|
193
|
+
export function capabilityGate({ capability, toggle }) {
|
|
194
|
+
return hasService => toggle && (hasService || capability);
|
|
195
|
+
}
|
|
170
196
|
/**
|
|
171
197
|
* Determines whether the specified service type requires the ConfiguredName characteristic.
|
|
172
198
|
*
|
|
@@ -183,7 +209,7 @@ function serviceRequiresConfiguredName(service) {
|
|
|
183
209
|
* Determines whether the specified service type supports the ConfiguredName characteristic.
|
|
184
210
|
*
|
|
185
211
|
* @param service - The service instance to check.
|
|
186
|
-
* @returns `true` if the service type
|
|
212
|
+
* @returns `true` if the service type supports the ConfiguredName characteristic.
|
|
187
213
|
*
|
|
188
214
|
* @internal
|
|
189
215
|
*/
|
|
@@ -207,7 +233,7 @@ function serviceRequiresName(service) {
|
|
|
207
233
|
* Determines whether the specified service type supports the Name characteristic.
|
|
208
234
|
*
|
|
209
235
|
* @param service - The service instance to check.
|
|
210
|
-
* @returns `true` if the service type
|
|
236
|
+
* @returns `true` if the service type supports the Name characteristic.
|
|
211
237
|
*
|
|
212
238
|
* @internal
|
|
213
239
|
*/
|
|
@@ -216,22 +242,26 @@ function serviceHasName(service) {
|
|
|
216
242
|
return hasNameUUIDs?.has(service.UUID) ?? false;
|
|
217
243
|
}
|
|
218
244
|
/**
|
|
219
|
-
* Retrieves the primary name of a service, preferring the ConfiguredName characteristic over the Name characteristic.
|
|
245
|
+
* Retrieves the primary name of a service, preferring the ConfiguredName characteristic over the Name characteristic. This is a pure read - it never mutates the
|
|
246
|
+
* service.
|
|
220
247
|
*
|
|
221
248
|
* @param service - The service from which to retrieve the name.
|
|
222
|
-
* @returns The configured or display name of the service, or `undefined` if neither is set.
|
|
249
|
+
* @returns The configured or display name of the service, or `undefined` if neither characteristic is present or set.
|
|
223
250
|
*
|
|
224
|
-
* @see setServiceName
|
|
251
|
+
* @see setServiceName - to update the current name on a service.
|
|
225
252
|
* @category Accessory
|
|
226
253
|
*/
|
|
227
254
|
export function getServiceName(service) {
|
|
228
|
-
// No service, we're done.
|
|
229
255
|
if (!service) {
|
|
230
256
|
return undefined;
|
|
231
257
|
}
|
|
232
|
-
// Grab the Characteristic constructor from the instance of our service so we can set the individual characteristics without needing the HAP object directly.
|
|
233
258
|
const characteristic = getCharacteristicConstructor(service);
|
|
234
|
-
|
|
259
|
+
// HAP's `getCharacteristic` is get-or-create: asking for a characteristic the service does not have constructs it, attaches it to the service, and (for types
|
|
260
|
+
// outside the service's optional set) logs an "Adding anyway." warning. A name lookup must stay read-only, so we gate each read behind `testCharacteristic` - a
|
|
261
|
+
// pure existence check - and read a value only when the characteristic is already present. ConfiguredName takes precedence over Name.
|
|
262
|
+
const configuredName = service.testCharacteristic(characteristic.ConfiguredName) ? service.getCharacteristic(characteristic.ConfiguredName).value : undefined;
|
|
263
|
+
const name = service.testCharacteristic(characteristic.Name) ? service.getCharacteristic(characteristic.Name).value : undefined;
|
|
264
|
+
return (configuredName ?? name ?? undefined);
|
|
235
265
|
}
|
|
236
266
|
/**
|
|
237
267
|
* Updates the displayName and applicable name characteristics of a service to the specified value.
|
|
@@ -243,22 +273,19 @@ export function getServiceName(service) {
|
|
|
243
273
|
* This function ensures the name is validated, updates the service's `displayName`, and sets the `ConfiguredName` and `Name`
|
|
244
274
|
* characteristics when supported by the service type.
|
|
245
275
|
*
|
|
246
|
-
* @see acquireService
|
|
247
|
-
* @see getServiceName
|
|
276
|
+
* @see acquireService - to add or retrieve services.
|
|
277
|
+
* @see getServiceName - to retrieve the current name set on a service.
|
|
248
278
|
* @category Accessory
|
|
249
279
|
*/
|
|
250
280
|
export function setServiceName(service, name) {
|
|
251
|
-
// Grab the Characteristic constructor from the instance of our service so we can set the individual characteristics without needing the HAP object directly.
|
|
252
281
|
const characteristic = getCharacteristicConstructor(service);
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
// Update our name.
|
|
256
|
-
service.displayName = name;
|
|
282
|
+
const sanitized = sanitizeName(name);
|
|
283
|
+
service.displayName = sanitized;
|
|
257
284
|
if (serviceHasConfiguredName(service)) {
|
|
258
|
-
service.updateCharacteristic(characteristic.ConfiguredName,
|
|
285
|
+
service.updateCharacteristic(characteristic.ConfiguredName, sanitized);
|
|
259
286
|
}
|
|
260
287
|
if (serviceHasName(service)) {
|
|
261
|
-
service.updateCharacteristic(characteristic.Name,
|
|
288
|
+
service.updateCharacteristic(characteristic.Name, sanitized);
|
|
262
289
|
}
|
|
263
290
|
}
|
|
264
291
|
//# sourceMappingURL=service.js.map
|
package/dist/service.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
|