@camstack/types 1.2.424 → 1.2.426

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/dist/index.js CHANGED
@@ -10761,7 +10761,22 @@ var BrokerProviderInfoSchema = zod.z.object({
10761
10761
  */
10762
10762
  interactiveConnectPath: zod.z.string().min(1).optional(),
10763
10763
  /** Relative hub path to disconnect the linked account (same popup pattern). */
10764
- interactiveDisconnectPath: zod.z.string().min(1).optional()
10764
+ interactiveDisconnectPath: zod.z.string().min(1).optional(),
10765
+ /**
10766
+ * The kind signs in through a server-held interactive session instead of
10767
+ * (or before) typed credentials. `basePath` is a hub-relative route set
10768
+ * served by the owning addon (`/addon/<id>/...`) speaking the sign-in
10769
+ * contract: `POST {basePath}/start` (body: the form's settings) answers
10770
+ * `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
10771
+ * `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
10772
+ * 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
10773
+ * (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
10774
+ * existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
10775
+ * (`{ sessionId }`) drops the session. The dialog that edits a broker
10776
+ * offers it as the default path; the fields the session fills are
10777
+ * marked `filledBySignIn` in the kind's settings schema.
10778
+ */
10779
+ signIn: zod.z.object({ basePath: zod.z.string().min(1) }).optional()
10765
10780
  }))
10766
10781
  });
10767
10782
  var ListInputSchema = zod.z.object({
@@ -71578,9 +71593,9 @@ var PowerMeterStatusSchema = zod.z.object({
71578
71593
  /** Cumulative energy in kilowatt-hours since the meter was reset. */
71579
71594
  kwhTotal: zod.z.number().optional().meta(require_sleep.readingMeta("energy", { label: "Energy" })),
71580
71595
  /** Voltage in volts. */
71581
- volts: zod.z.number().optional().meta(require_sleep.readingMeta("voltage")),
71596
+ volts: zod.z.number().optional().meta(require_sleep.readingMeta("voltage", { label: "Voltage" })),
71582
71597
  /** Current in amperes. */
71583
- amps: zod.z.number().optional().meta(require_sleep.readingMeta("current")),
71598
+ amps: zod.z.number().optional().meta(require_sleep.readingMeta("current", { label: "Current" })),
71584
71599
  /** Apparent power in volt-amperes. */
71585
71600
  va: zod.z.number().optional().meta(require_sleep.readingMeta("apparent-power")),
71586
71601
  /** Power factor (0..1) if reported. */
@@ -71588,17 +71603,74 @@ var PowerMeterStatusSchema = zod.z.object({
71588
71603
  /** Ms epoch when the slice was last updated. */
71589
71604
  lastFetchedAt: zod.z.number()
71590
71605
  });
71606
+ /**
71607
+ * Loads that draw metered mains power (D951). The reading is a feature of the
71608
+ * device itself — a plug, a lamp, a fan, an air conditioner, a boiler, a
71609
+ * vacuum dock — not a separate sensor beside it. A `Sensor` stays: a clamp
71610
+ * meter or a standalone energy monitor IS the device. Cover, lock, valve,
71611
+ * camera and the like are left out: their draw is not what anyone meters.
71612
+ */
71613
+ var POWER_METER_DEVICE_TYPES = [
71614
+ require_err_msg.DeviceType.Sensor,
71615
+ require_err_msg.DeviceType.Switch,
71616
+ require_err_msg.DeviceType.Light,
71617
+ require_err_msg.DeviceType.Fan,
71618
+ require_err_msg.DeviceType.Climate,
71619
+ require_err_msg.DeviceType.Thermostat,
71620
+ require_err_msg.DeviceType.Humidifier,
71621
+ require_err_msg.DeviceType.WaterHeater,
71622
+ require_err_msg.DeviceType.MediaPlayer,
71623
+ require_err_msg.DeviceType.Washer,
71624
+ require_err_msg.DeviceType.Dryer,
71625
+ require_err_msg.DeviceType.Dishwasher,
71626
+ require_err_msg.DeviceType.Vacuum,
71627
+ require_err_msg.DeviceType.LawnMower,
71628
+ require_err_msg.DeviceType.PetFeeder
71629
+ ];
71630
+ /** Everything but a bare `Sensor`: a sensor that takes its reading from another sensor adds nothing. */
71631
+ var POWER_METER_CUSTOMIZE_DEVICE_TYPES = POWER_METER_DEVICE_TYPES.filter((type) => type !== require_err_msg.DeviceType.Sensor);
71632
+ /** One scalar target per reading; each is sourced from a device of its own (D951). */
71633
+ function powerTarget(id, unit) {
71634
+ return {
71635
+ id,
71636
+ cardinality: "scalar",
71637
+ vocabulary: {
71638
+ cap: "power-meter",
71639
+ stateField: id
71640
+ },
71641
+ deviceTypes: POWER_METER_CUSTOMIZE_DEVICE_TYPES,
71642
+ apply: "add",
71643
+ path: id,
71644
+ sources: [{
71645
+ kind: "numeric",
71646
+ requiredUnit: unit,
71647
+ transforms: [{ kind: "identity" }]
71648
+ }],
71649
+ companions: [{
71650
+ kind: "clock",
71651
+ path: "lastFetchedAt",
71652
+ when: "always"
71653
+ }],
71654
+ sourceReport: { status: "assignment-status" },
71655
+ advancedExpression: true
71656
+ };
71657
+ }
71658
+ /** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
71659
+ var powerMeterCustomize = {
71660
+ version: 1,
71661
+ targets: [
71662
+ powerTarget("watts", "W"),
71663
+ powerTarget("kwhTotal", "kWh"),
71664
+ powerTarget("volts", "V"),
71665
+ powerTarget("amps", "A")
71666
+ ]
71667
+ };
71591
71668
  var powerMeterCapability = {
71592
71669
  name: "power-meter",
71593
71670
  scope: "device",
71594
71671
  deviceNative: true,
71595
71672
  mode: "singleton",
71596
- deviceTypes: [
71597
- require_err_msg.DeviceType.Sensor,
71598
- require_err_msg.DeviceType.Washer,
71599
- require_err_msg.DeviceType.Dryer,
71600
- require_err_msg.DeviceType.Dishwasher
71601
- ],
71673
+ deviceTypes: POWER_METER_DEVICE_TYPES,
71602
71674
  methods: {},
71603
71675
  status: {
71604
71676
  schema: PowerMeterStatusSchema,
@@ -71655,7 +71727,8 @@ var powerMeterCapability = {
71655
71727
  } },
71656
71728
  /** Clock fields: written, but excluded from the compare that decides
71657
71729
  * whether persisting is worth a SQLite commit. */
71658
- volatileStateFields: ["lastFetchedAt"]
71730
+ volatileStateFields: ["lastFetchedAt"],
71731
+ customize: powerMeterCustomize
71659
71732
  };
71660
71733
  //#endregion
71661
71734
  //#region src/capabilities/presence.cap.ts
@@ -80428,7 +80501,7 @@ function convertUnitTargets(from) {
80428
80501
  //#region src/generated/customize-catalog.ts
80429
80502
  /**
80430
80503
  * Customize catalog, projected from every `*.cap.ts` `customize` block.
80431
- * 5 caps. Field keys are `runtimeState` paths. No Zod.
80504
+ * 6 caps. Field keys are `runtimeState` paths. No Zod.
80432
80505
  */
80433
80506
  var CAP_CUSTOMIZE_CATALOG = {
80434
80507
  "battery": {
@@ -80693,6 +80766,167 @@ var CAP_CUSTOMIZE_CATALOG = {
80693
80766
  ]
80694
80767
  }]
80695
80768
  },
80769
+ "power-meter": {
80770
+ version: 1,
80771
+ targets: [
80772
+ {
80773
+ id: "watts",
80774
+ cardinality: "scalar",
80775
+ deviceTypes: [
80776
+ require_err_msg.DeviceType.Switch,
80777
+ require_err_msg.DeviceType.Light,
80778
+ require_err_msg.DeviceType.Fan,
80779
+ require_err_msg.DeviceType.Climate,
80780
+ require_err_msg.DeviceType.Thermostat,
80781
+ require_err_msg.DeviceType.Humidifier,
80782
+ require_err_msg.DeviceType.WaterHeater,
80783
+ require_err_msg.DeviceType.MediaPlayer,
80784
+ require_err_msg.DeviceType.Washer,
80785
+ require_err_msg.DeviceType.Dryer,
80786
+ require_err_msg.DeviceType.Dishwasher,
80787
+ require_err_msg.DeviceType.Vacuum,
80788
+ require_err_msg.DeviceType.LawnMower,
80789
+ require_err_msg.DeviceType.PetFeeder
80790
+ ],
80791
+ apply: "add",
80792
+ vocabularyCap: "power-meter",
80793
+ vocabularyStateField: "watts",
80794
+ sources: [{
80795
+ kind: "numeric",
80796
+ requiredUnit: "W",
80797
+ transformKinds: ["identity"],
80798
+ transforms: [{ kind: "identity" }]
80799
+ }],
80800
+ sourceReport: { status: "assignment-status" },
80801
+ advancedExpression: true,
80802
+ path: "watts",
80803
+ valueKind: "number",
80804
+ nullable: false,
80805
+ companions: [{
80806
+ kind: "clock",
80807
+ path: "lastFetchedAt",
80808
+ when: "always"
80809
+ }]
80810
+ },
80811
+ {
80812
+ id: "kwhTotal",
80813
+ cardinality: "scalar",
80814
+ deviceTypes: [
80815
+ require_err_msg.DeviceType.Switch,
80816
+ require_err_msg.DeviceType.Light,
80817
+ require_err_msg.DeviceType.Fan,
80818
+ require_err_msg.DeviceType.Climate,
80819
+ require_err_msg.DeviceType.Thermostat,
80820
+ require_err_msg.DeviceType.Humidifier,
80821
+ require_err_msg.DeviceType.WaterHeater,
80822
+ require_err_msg.DeviceType.MediaPlayer,
80823
+ require_err_msg.DeviceType.Washer,
80824
+ require_err_msg.DeviceType.Dryer,
80825
+ require_err_msg.DeviceType.Dishwasher,
80826
+ require_err_msg.DeviceType.Vacuum,
80827
+ require_err_msg.DeviceType.LawnMower,
80828
+ require_err_msg.DeviceType.PetFeeder
80829
+ ],
80830
+ apply: "add",
80831
+ vocabularyCap: "power-meter",
80832
+ vocabularyStateField: "kwhTotal",
80833
+ sources: [{
80834
+ kind: "numeric",
80835
+ requiredUnit: "kWh",
80836
+ transformKinds: ["identity"],
80837
+ transforms: [{ kind: "identity" }]
80838
+ }],
80839
+ sourceReport: { status: "assignment-status" },
80840
+ advancedExpression: true,
80841
+ path: "kwhTotal",
80842
+ valueKind: "number",
80843
+ nullable: false,
80844
+ companions: [{
80845
+ kind: "clock",
80846
+ path: "lastFetchedAt",
80847
+ when: "always"
80848
+ }]
80849
+ },
80850
+ {
80851
+ id: "volts",
80852
+ cardinality: "scalar",
80853
+ deviceTypes: [
80854
+ require_err_msg.DeviceType.Switch,
80855
+ require_err_msg.DeviceType.Light,
80856
+ require_err_msg.DeviceType.Fan,
80857
+ require_err_msg.DeviceType.Climate,
80858
+ require_err_msg.DeviceType.Thermostat,
80859
+ require_err_msg.DeviceType.Humidifier,
80860
+ require_err_msg.DeviceType.WaterHeater,
80861
+ require_err_msg.DeviceType.MediaPlayer,
80862
+ require_err_msg.DeviceType.Washer,
80863
+ require_err_msg.DeviceType.Dryer,
80864
+ require_err_msg.DeviceType.Dishwasher,
80865
+ require_err_msg.DeviceType.Vacuum,
80866
+ require_err_msg.DeviceType.LawnMower,
80867
+ require_err_msg.DeviceType.PetFeeder
80868
+ ],
80869
+ apply: "add",
80870
+ vocabularyCap: "power-meter",
80871
+ vocabularyStateField: "volts",
80872
+ sources: [{
80873
+ kind: "numeric",
80874
+ requiredUnit: "V",
80875
+ transformKinds: ["identity"],
80876
+ transforms: [{ kind: "identity" }]
80877
+ }],
80878
+ sourceReport: { status: "assignment-status" },
80879
+ advancedExpression: true,
80880
+ path: "volts",
80881
+ valueKind: "number",
80882
+ nullable: false,
80883
+ companions: [{
80884
+ kind: "clock",
80885
+ path: "lastFetchedAt",
80886
+ when: "always"
80887
+ }]
80888
+ },
80889
+ {
80890
+ id: "amps",
80891
+ cardinality: "scalar",
80892
+ deviceTypes: [
80893
+ require_err_msg.DeviceType.Switch,
80894
+ require_err_msg.DeviceType.Light,
80895
+ require_err_msg.DeviceType.Fan,
80896
+ require_err_msg.DeviceType.Climate,
80897
+ require_err_msg.DeviceType.Thermostat,
80898
+ require_err_msg.DeviceType.Humidifier,
80899
+ require_err_msg.DeviceType.WaterHeater,
80900
+ require_err_msg.DeviceType.MediaPlayer,
80901
+ require_err_msg.DeviceType.Washer,
80902
+ require_err_msg.DeviceType.Dryer,
80903
+ require_err_msg.DeviceType.Dishwasher,
80904
+ require_err_msg.DeviceType.Vacuum,
80905
+ require_err_msg.DeviceType.LawnMower,
80906
+ require_err_msg.DeviceType.PetFeeder
80907
+ ],
80908
+ apply: "add",
80909
+ vocabularyCap: "power-meter",
80910
+ vocabularyStateField: "amps",
80911
+ sources: [{
80912
+ kind: "numeric",
80913
+ requiredUnit: "A",
80914
+ transformKinds: ["identity"],
80915
+ transforms: [{ kind: "identity" }]
80916
+ }],
80917
+ sourceReport: { status: "assignment-status" },
80918
+ advancedExpression: true,
80919
+ path: "amps",
80920
+ valueKind: "number",
80921
+ nullable: false,
80922
+ companions: [{
80923
+ kind: "clock",
80924
+ path: "lastFetchedAt",
80925
+ when: "always"
80926
+ }]
80927
+ }
80928
+ ]
80929
+ },
80696
80930
  "running-state": {
80697
80931
  version: 1,
80698
80932
  targets: [{
@@ -80791,7 +81025,9 @@ var CAP_RUNTIME_FIELD_UNITS = {
80791
81025
  "humidity-sensor": { percent: "%" },
80792
81026
  "power-meter": {
80793
81027
  watts: "W",
80794
- kwhTotal: "kWh"
81028
+ kwhTotal: "kWh",
81029
+ volts: "V",
81030
+ amps: "A"
80795
81031
  },
80796
81032
  "temperature-sensor": { celsius: "°C" }
80797
81033
  };
@@ -80820,7 +81056,7 @@ function isLiteral(source, expr) {
80820
81056
  }
80821
81057
  //#endregion
80822
81058
  //#region src/composition/customize/event-compile.ts
80823
- var catalog$4 = CAP_CUSTOMIZE_CATALOG;
81059
+ var catalog$5 = CAP_CUSTOMIZE_CATALOG;
80824
81060
  function compilePulseOverride(input) {
80825
81061
  const target = catalogTarget$4(input.draft.cap, input.draft.targetId);
80826
81062
  if (target === null || target.shape !== "pulse") return fail$2("target");
@@ -80952,7 +81188,7 @@ function sensorEntries(sources, device, modes) {
80952
81188
  };
80953
81189
  }
80954
81190
  function catalogTarget$4(cap, targetId) {
80955
- const entry = catalog$4[cap];
81191
+ const entry = catalog$5[cap];
80956
81192
  if (entry === void 0) return null;
80957
81193
  return entry.targets.find((target) => target.id === targetId) ?? null;
80958
81194
  }
@@ -81077,7 +81313,7 @@ function wrap$2(feature) {
81077
81313
  }
81078
81314
  //#endregion
81079
81315
  //#region src/composition/customize/scalar-compile.ts
81080
- var catalog$3 = CAP_CUSTOMIZE_CATALOG;
81316
+ var catalog$4 = CAP_CUSTOMIZE_CATALOG;
81081
81317
  function compileScalarOverride(input) {
81082
81318
  const target = catalogTarget$3(input.draft.cap, input.draft.targetId);
81083
81319
  if (target === null || target.cardinality !== "scalar" || target.path === void 0) return fail$1("target");
@@ -81107,7 +81343,7 @@ function fail$1(reason) {
81107
81343
  };
81108
81344
  }
81109
81345
  function catalogTarget$3(cap, targetId) {
81110
- const entry = catalog$3[cap];
81346
+ const entry = catalog$4[cap];
81111
81347
  if (entry === void 0) return null;
81112
81348
  return entry.targets.find((target) => target.id === targetId) ?? null;
81113
81349
  }
@@ -81244,6 +81480,83 @@ function refOf$1(draft) {
81244
81480
  };
81245
81481
  }
81246
81482
  //#endregion
81483
+ //#region src/composition/customize/scalar-merge.ts
81484
+ var catalog$3 = CAP_CUSTOMIZE_CATALOG;
81485
+ function scalarTargets(cap) {
81486
+ return (catalog$3[cap]?.targets ?? []).filter((target) => target.cardinality === "scalar" && target.path !== void 0);
81487
+ }
81488
+ /** How many scalar targets the cap declares: above one, the cap's feature is shared. */
81489
+ function scalarTargetCount(cap) {
81490
+ return scalarTargets(cap).length;
81491
+ }
81492
+ function valuePath(target) {
81493
+ return target.path ?? target.id;
81494
+ }
81495
+ function ownedPaths(target) {
81496
+ return [valuePath(target), ...(target.companions ?? []).map((companion) => companion.path)];
81497
+ }
81498
+ function find(cap, targetId) {
81499
+ return scalarTargets(cap).find((target) => target.id === targetId) ?? null;
81500
+ }
81501
+ function without(fields, paths) {
81502
+ return Object.fromEntries(Object.entries(fields).filter(([path]) => !paths.has(path)));
81503
+ }
81504
+ /**
81505
+ * The cap's feature with `compiled` (one target's own feature) merged in. A cap
81506
+ * with one scalar target is replaced whole, as before.
81507
+ */
81508
+ function mergeScalarTarget(current, compiled, cap, targetId) {
81509
+ const target = find(cap, targetId);
81510
+ if (current === null || target === null || scalarTargetCount(cap) < 2) return compiled;
81511
+ const kept = without(current.fields, new Set(ownedPaths(target)));
81512
+ return {
81513
+ ...current,
81514
+ ...compiled,
81515
+ fields: {
81516
+ ...kept,
81517
+ ...compiled.fields
81518
+ }
81519
+ };
81520
+ }
81521
+ /** The cap's feature without `targetId`'s paths; null when no target value is left. */
81522
+ function removeScalarTarget(current, cap, targetId) {
81523
+ if (current === null) return null;
81524
+ const target = find(cap, targetId);
81525
+ if (target === null || scalarTargetCount(cap) < 2) return null;
81526
+ const stillAssigned = scalarTargets(cap).filter((row) => row.id !== targetId).filter((row) => current.fields[valuePath(row)] !== void 0);
81527
+ if (stillAssigned.length === 0) return null;
81528
+ const needed = new Set(stillAssigned.flatMap((row) => ownedPaths(row)));
81529
+ const drop = new Set(ownedPaths(target).filter((path) => !needed.has(path)));
81530
+ return {
81531
+ ...current,
81532
+ fields: without(current.fields, drop)
81533
+ };
81534
+ }
81535
+ /**
81536
+ * The part of a stored feature one target owns — what a decode compares with
81537
+ * its recompiled feature. A cap with one target compares the whole feature.
81538
+ */
81539
+ function ownedSlice(stored, cap, targetId) {
81540
+ const target = find(cap, targetId);
81541
+ if (target === null || scalarTargetCount(cap) < 2) return stored;
81542
+ const owned = new Set(ownedPaths(target));
81543
+ return {
81544
+ ...stored,
81545
+ fields: Object.fromEntries(Object.entries(stored.fields).filter(([path]) => owned.has(path)))
81546
+ };
81547
+ }
81548
+ /**
81549
+ * The stored feature as ONE target sees it: null when the cap's feature holds
81550
+ * only its neighbours' readings (no assignment of this target), else the whole
81551
+ * feature. A cap with one target sees what is stored.
81552
+ */
81553
+ function targetFeature(stored, cap, targetId) {
81554
+ if (stored === null) return null;
81555
+ const target = find(cap, targetId);
81556
+ if (target === null || scalarTargetCount(cap) < 2) return stored;
81557
+ return stored.fields[valuePath(target)] === void 0 ? null : stored;
81558
+ }
81559
+ //#endregion
81247
81560
  //#region src/composition/customize/scalar-decode.ts
81248
81561
  var catalog$2 = CAP_CUSTOMIZE_CATALOG;
81249
81562
  function decodeScalarOverride(input) {
@@ -81354,7 +81667,7 @@ function reproduces$1(decoded, device, stored) {
81354
81667
  sourceUnit: decoded.sourceUnit
81355
81668
  });
81356
81669
  if (!compiled.ok) return false;
81357
- return sameFeature$1(compiled.value, stored);
81670
+ return sameFeature$1(compiled.value, ownedSlice(stored, decoded.draft.cap, decoded.draft.targetId));
81358
81671
  }
81359
81672
  function sameFeature$1(compiled, stored) {
81360
81673
  return sameStored(wrap$1(withoutEnabled(compiled)), wrap$1(withoutEnabled(stored)));
@@ -119164,6 +119477,7 @@ exports.memoizePinnedFfmpeg = memoizePinnedFfmpeg;
119164
119477
  exports.mergeClipLabels = mergeClipLabels;
119165
119478
  exports.mergeKeyedArrayItem = mergeKeyedArrayItem;
119166
119479
  exports.mergeOverrides = mergeOverrides;
119480
+ exports.mergeScalarTarget = mergeScalarTarget;
119167
119481
  exports.mergeSecretStatePaths = require_sleep.mergeSecretStatePaths;
119168
119482
  exports.mergeSettingsBags = mergeSettingsBags;
119169
119483
  exports.mergeSourceInfo = mergeSourceInfo;
@@ -119230,6 +119544,7 @@ exports.optionalMethod = require_sleep.optionalMethod;
119230
119544
  exports.osdCapability = osdCapability;
119231
119545
  exports.osdManagerCapability = osdManagerCapability;
119232
119546
  exports.overlayClusterStepSettings = overlayClusterStepSettings;
119547
+ exports.ownedSlice = ownedSlice;
119233
119548
  exports.packagePickerItems = packagePickerItems;
119234
119549
  exports.paintHex = paintHex;
119235
119550
  exports.paletteEntryLabel = paletteEntryLabel;
@@ -119360,6 +119675,7 @@ exports.reducePoints = reducePoints;
119360
119675
  exports.reducerForActive = reducerForActive;
119361
119676
  exports.registerKnownSecret = require_sleep.registerKnownSecret;
119362
119677
  exports.remapCropDetections = remapCropDetections;
119678
+ exports.removeScalarTarget = removeScalarTarget;
119363
119679
  exports.renameAlarmProfile = renameAlarmProfile;
119364
119680
  exports.renderVocabPhrase = renderVocabPhrase;
119365
119681
  exports.replacedFieldKeys = replacedFieldKeys;
@@ -119448,6 +119764,7 @@ exports.runtimeStatePolicyFor = runtimeStatePolicyFor;
119448
119764
  exports.sameDoFamily = sameDoFamily;
119449
119765
  exports.sameHelperBody = sameHelperBody;
119450
119766
  exports.sameRead = sameRead;
119767
+ exports.scalarTargetCount = scalarTargetCount;
119451
119768
  exports.sceneMonitorCapability = sceneMonitorCapability;
119452
119769
  exports.scheduleForSendTimes = scheduleForSendTimes;
119453
119770
  exports.schemaDeclaresAnyField = require_sleep.schemaDeclaresAnyField;
@@ -119563,6 +119880,7 @@ exports.systemEventSummarySplitOf = systemEventSummarySplitOf;
119563
119880
  exports.systemFamilyOfKind = systemFamilyOfKind;
119564
119881
  exports.systemRuleKindOf = systemRuleKindOf;
119565
119882
  exports.tamperCapability = tamperCapability;
119883
+ exports.targetFeature = targetFeature;
119566
119884
  exports.taskLogEntrySchema = taskLogEntrySchema;
119567
119885
  exports.taskPhaseSchema = taskPhaseSchema;
119568
119886
  exports.taskTargetSchema = taskTargetSchema;