@camstack/types 1.2.405 → 1.2.407

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 (69) hide show
  1. package/dist/addon.js +21 -2
  2. package/dist/addon.mjs +21 -2
  3. package/dist/capabilities/battery.cap.d.ts +46 -0
  4. package/dist/capabilities/capability-definition.d.ts +8 -0
  5. package/dist/capabilities/consumables.cap.d.ts +110 -0
  6. package/dist/capabilities/customize-catalog.d.ts +72 -0
  7. package/dist/capabilities/customize-spec.d.ts +202 -0
  8. package/dist/capabilities/doorbell.cap.d.ts +39 -0
  9. package/dist/capabilities/index.d.ts +6 -4
  10. package/dist/capabilities/motion.cap.d.ts +39 -0
  11. package/dist/capabilities/notification-rules.cap.d.ts +3 -78
  12. package/dist/capabilities/osd-manager.cap.d.ts +0 -18
  13. package/dist/capabilities/running-state.cap.d.ts +140 -0
  14. package/dist/catalogs/sensor-active-state.d.ts +1 -1
  15. package/dist/client.js +11 -63
  16. package/dist/client.mjs +11 -63
  17. package/dist/composition/customize/__fixtures__/refs.d.ts +27 -0
  18. package/dist/composition/customize/__fixtures__/stored-cases.d.ts +13 -0
  19. package/dist/composition/customize/event-compile.d.ts +20 -0
  20. package/dist/composition/customize/event-decode.d.ts +19 -0
  21. package/dist/composition/customize/event-eval.d.ts +35 -0
  22. package/dist/composition/customize/event-status.d.ts +49 -0
  23. package/dist/composition/customize/field-source.d.ts +5 -0
  24. package/dist/composition/customize/keyed-array-compile.d.ts +26 -0
  25. package/dist/composition/customize/keyed-array-decode.d.ts +20 -0
  26. package/dist/composition/customize/keyed-array-expr.d.ts +10 -0
  27. package/dist/composition/customize/keyed-array-status.d.ts +22 -0
  28. package/dist/composition/customize/normalize.d.ts +4 -0
  29. package/dist/composition/customize/override-draft.d.ts +311 -0
  30. package/dist/composition/customize/scalar-compile.d.ts +13 -0
  31. package/dist/composition/customize/scalar-decode.d.ts +17 -0
  32. package/dist/composition/customize/scalar-expr.d.ts +33 -0
  33. package/dist/composition/customize/scalar-status.d.ts +31 -0
  34. package/dist/composition/customize/stored.d.ts +15 -0
  35. package/dist/composition/index.d.ts +0 -1
  36. package/dist/{composition-CB6PMT9p.mjs → composition-BJ8iAZb3.mjs} +87 -3
  37. package/dist/{composition-eoYYVfOp.js → composition-CSLSFGTO.js} +87 -3
  38. package/dist/device/cap-vocabulary/entries/appliances.d.ts +1 -1
  39. package/dist/enums/event-category.d.ts +4 -0
  40. package/dist/enums.js +1 -1
  41. package/dist/enums.mjs +1 -1
  42. package/dist/{event-category-fDPduoeC.mjs → event-category-Ceif8n-v.mjs} +4 -0
  43. package/dist/{event-category-CXrwjC3e.js → event-category-DG6Vir8Z.js} +4 -0
  44. package/dist/expression/builtins.d.ts +7 -18
  45. package/dist/expression/expression-source.d.ts +14 -2
  46. package/dist/generated/addon-api.d.ts +14 -0
  47. package/dist/generated/addon-cap-facts.d.ts +1 -1
  48. package/dist/generated/cap-status-types.d.ts +3 -1
  49. package/dist/generated/capability-router-map.d.ts +5 -2
  50. package/dist/generated/customize-catalog.d.ts +229 -0
  51. package/dist/generated/device-local-state.d.ts +3 -0
  52. package/dist/generated/device-proxy.d.ts +3 -0
  53. package/dist/generated/device-scoped-caps.d.ts +1 -1
  54. package/dist/generated/history-catalog.d.ts +1 -1
  55. package/dist/generated/method-access-map.d.ts +1 -1
  56. package/dist/generated/method-device-selectors.d.ts +1 -1
  57. package/dist/generated/runtime-state-durability.d.ts +1 -1
  58. package/dist/index.d.ts +16 -0
  59. package/dist/index.js +2385 -173
  60. package/dist/index.mjs +2351 -171
  61. package/dist/interfaces/config-ui.d.ts +69 -2
  62. package/dist/node.js +1 -1
  63. package/dist/node.mjs +1 -1
  64. package/dist/running-state/defaults.d.ts +6 -0
  65. package/dist/running-state/from-operation.d.ts +14 -0
  66. package/dist/{sleep-CHIEEJkY.mjs → sleep-CYfIZzGv.mjs} +7 -3
  67. package/dist/{sleep-BKS4OPMo.js → sleep-UP964hNP.js} +7 -3
  68. package/package.json +1 -1
  69. package/dist/composition/presets/doorbell-feature.d.ts +0 -20
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_sleep = require("./sleep-BKS4OPMo.js");
3
- const require_event_category = require("./event-category-CXrwjC3e.js");
4
- const require_composition = require("./composition-eoYYVfOp.js");
2
+ const require_sleep = require("./sleep-UP964hNP.js");
3
+ const require_event_category = require("./event-category-DG6Vir8Z.js");
4
+ const require_composition = require("./composition-CSLSFGTO.js");
5
5
  const require_node_color = require("./node-color.js");
6
6
  const require_err_msg = require("./err-msg-BhVbr0NX.js");
7
7
  const require_enums = require("./enums.js");
@@ -12871,7 +12871,15 @@ var BUILTIN_RESULT_KINDS = Object.freeze({
12871
12871
  kind: "fixed",
12872
12872
  result: ["number", "null"]
12873
12873
  },
12874
- count: NUMBER
12874
+ count: NUMBER,
12875
+ dwell: {
12876
+ kind: "fixed",
12877
+ result: ["boolean", "null"]
12878
+ },
12879
+ latchedAt: {
12880
+ kind: "fixed",
12881
+ result: ["number", "null"]
12882
+ }
12875
12883
  });
12876
12884
  var KindInferenceError = class extends Error {};
12877
12885
  function kindOfValue(value) {
@@ -43726,9 +43734,6 @@ var NcSystemEventKindSchema = zod.z.enum([
43726
43734
  "device-battery-normal",
43727
43735
  "device-consumable-low",
43728
43736
  "device-consumable-normal",
43729
- "device-tank-low",
43730
- "device-tank-full",
43731
- "device-tank-normal",
43732
43737
  "stream-online",
43733
43738
  "stream-offline",
43734
43739
  "node-online",
@@ -43775,18 +43780,19 @@ var NcSystemEventKindSchema = zod.z.enum([
43775
43780
  "camera-enabled"
43776
43781
  ]);
43777
43782
  /** The legacy tail of {@link NcSystemEventKindSchema} — see its docblock. */
43778
- var NC_LEGACY_SYSTEM_EVENT_KINDS = new Set([
43783
+ var NC_LEGACY_SYSTEM_EVENT_KINDS = [
43779
43784
  "camera-online",
43780
43785
  "camera-offline",
43781
43786
  "camera-disabled",
43782
43787
  "camera-enabled"
43783
- ]);
43788
+ ];
43789
+ var NC_LEGACY_SYSTEM_EVENT_KIND_SET = new Set(NC_LEGACY_SYSTEM_EVENT_KINDS);
43784
43790
  /**
43785
43791
  * The kinds a rule may be AUTHORED with — every schema member except the
43786
43792
  * legacy tail. Editors render THIS list; the schema still parses the tail so a
43787
43793
  * durable row (and an unmigrated rule) survives being read.
43788
43794
  */
43789
- var NC_AUTHORABLE_SYSTEM_EVENT_KINDS = NcSystemEventKindSchema.options.filter((kind) => !NC_LEGACY_SYSTEM_EVENT_KINDS.has(kind));
43795
+ var NC_AUTHORABLE_SYSTEM_EVENT_KINDS = NcSystemEventKindSchema.options.filter((kind) => !NC_LEGACY_SYSTEM_EVENT_KIND_SET.has(kind));
43790
43796
  /**
43791
43797
  * The panel's transitions, as ONE list.
43792
43798
  *
@@ -43831,12 +43837,6 @@ var NC_BATTERY_CONSUMABLE_SYSTEM_EVENT_KINDS = [
43831
43837
  * and both editors read it.
43832
43838
  */
43833
43839
  var NC_CONSUMABLE_SYSTEM_EVENT_KINDS = ["device-consumable-low", "device-consumable-normal"];
43834
- /** A vacuum's tank alerts (D642) — raised on the provider's own verdict. */
43835
- var NC_TANK_SYSTEM_EVENT_KINDS = [
43836
- "device-tank-low",
43837
- "device-tank-full",
43838
- "device-tank-normal"
43839
- ];
43840
43840
  /**
43841
43841
  * The consumable threshold a rule that does not state one judges at (D642).
43842
43842
  * The operator's number ("default 15 %, configurable on the rule"), and the
@@ -45072,18 +45072,18 @@ var NcRuleSchema = NcRuleInputSchema.extend({
45072
45072
  * `addon-updates` the addons that are behind (D708 split them). `backups-exports` and `alarm` are not sections — a completed
45073
45073
  * job is not an open state, and the alarm stays instant.
45074
45074
  */
45075
- var NcStateSummarySectionIdSchema = zod.z.enum([
45075
+ var NC_STATE_SUMMARY_SECTION_IDS = [
45076
45076
  "device-state",
45077
45077
  "streams",
45078
45078
  "battery",
45079
45079
  "consumables",
45080
- "tanks",
45081
45080
  "detection-blind",
45082
45081
  "nodes",
45083
45082
  "addons",
45084
45083
  "addon-updates",
45085
45084
  "updates"
45086
- ]);
45085
+ ];
45086
+ var NcStateSummarySectionIdSchema = zod.z.enum(NC_STATE_SUMMARY_SECTION_IDS);
45087
45087
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
45088
45088
  var NcStateSummaryPreviewSectionSchema = zod.z.object({
45089
45089
  id: NcStateSummarySectionIdSchema,
@@ -45460,18 +45460,6 @@ var NC_CONDITION_CATALOG = [
45460
45460
  value: "device-consumable-normal",
45461
45461
  label: "Consumable replaced"
45462
45462
  },
45463
- {
45464
- value: "device-tank-low",
45465
- label: "Tank low (water, detergent)"
45466
- },
45467
- {
45468
- value: "device-tank-full",
45469
- label: "Tank full (dirty water, dust)"
45470
- },
45471
- {
45472
- value: "device-tank-normal",
45473
- label: "Tank back to normal"
45474
- },
45475
45463
  {
45476
45464
  value: "export-completed",
45477
45465
  label: "Export completed"
@@ -60338,20 +60326,68 @@ var BatteryStatusSchema = zod.z.object({
60338
60326
  */
60339
60327
  binary: zod.z.boolean().optional()
60340
60328
  });
60329
+ var BATTERY_DEVICE_TYPES = [
60330
+ require_err_msg.DeviceType.Camera,
60331
+ require_err_msg.DeviceType.Sensor,
60332
+ require_err_msg.DeviceType.Button,
60333
+ require_err_msg.DeviceType.Switch,
60334
+ require_err_msg.DeviceType.PetFeeder,
60335
+ require_err_msg.DeviceType.Container,
60336
+ require_err_msg.DeviceType.Thermostat
60337
+ ];
60338
+ /** Generic Customize target for the percentage reading (D936). */
60339
+ var batteryCustomize = {
60340
+ version: 1,
60341
+ targets: [{
60342
+ id: "percentage",
60343
+ cardinality: "scalar",
60344
+ vocabulary: {
60345
+ cap: "battery",
60346
+ stateField: "percentage"
60347
+ },
60348
+ deviceTypes: BATTERY_DEVICE_TYPES,
60349
+ apply: "add-or-replace",
60350
+ path: "percentage",
60351
+ sources: [{
60352
+ kind: "field",
60353
+ valueKinds: ["number", "string"],
60354
+ transforms: [{ kind: "identity" }, {
60355
+ kind: "linear",
60356
+ defaultScale: 1,
60357
+ defaultOffset: 0,
60358
+ clampMin: 0,
60359
+ clampMax: 100
60360
+ }]
60361
+ }],
60362
+ companions: [
60363
+ {
60364
+ kind: "constant",
60365
+ path: "charging",
60366
+ value: "unknown",
60367
+ when: "add"
60368
+ },
60369
+ {
60370
+ kind: "constant",
60371
+ path: "sleeping",
60372
+ value: false,
60373
+ when: "add"
60374
+ },
60375
+ {
60376
+ kind: "clock",
60377
+ path: "lastUpdated",
60378
+ when: "add"
60379
+ }
60380
+ ],
60381
+ sourceReport: { status: "assignment-status" },
60382
+ advancedExpression: true
60383
+ }]
60384
+ };
60341
60385
  var batteryCapability = {
60342
60386
  name: "battery",
60343
60387
  scope: "device",
60344
60388
  deviceNative: true,
60345
60389
  mode: "singleton",
60346
- deviceTypes: [
60347
- require_err_msg.DeviceType.Camera,
60348
- require_err_msg.DeviceType.Sensor,
60349
- require_err_msg.DeviceType.Button,
60350
- require_err_msg.DeviceType.Switch,
60351
- require_err_msg.DeviceType.PetFeeder,
60352
- require_err_msg.DeviceType.Container,
60353
- require_err_msg.DeviceType.Thermostat
60354
- ],
60390
+ deviceTypes: BATTERY_DEVICE_TYPES,
60355
60391
  methods: {
60356
60392
  /**
60357
60393
  * Explicitly wake the camera from low-power sleep ahead of a
@@ -60435,6 +60471,7 @@ onStatusChanged: { data: zod.z.object({
60435
60471
  kind: "gauge",
60436
60472
  unit: "%"
60437
60473
  } } },
60474
+ customize: batteryCustomize,
60438
60475
  /** Clock fields: written, but excluded from the compare that decides
60439
60476
  * whether persisting is worth a SQLite commit. */
60440
60477
  volatileStateFields: ["lastUpdated"]
@@ -61633,6 +61670,106 @@ var ConsumablesStatusSchema = zod.z.object({
61633
61670
  items: zod.z.array(ConsumableItemSchema),
61634
61671
  lastChangedAt: zod.z.number()
61635
61672
  });
61673
+ /** Synthesize seed for a link-built status (no native provider).
61674
+ *
61675
+ * ⚠ NO LIVE CALLER since 2026-08-08 (device-links deleted; see
61676
+ * `CapabilityStatusSchema.empty`). The wiring guidance below was written for
61677
+ * exactly the case the operator is asking about again — a Dreame's HA
61678
+ * consumable-life sensors — so it is kept for that conversation, not because
61679
+ * anything reads it today. */
61680
+ var EMPTY_STATUS = {
61681
+ items: [],
61682
+ lastChangedAt: 0
61683
+ };
61684
+ /** Seed for a NEW link-built consumable item. `key`/`label` are overwritten
61685
+ * with the link's `itemKey` (see `status.itemArray`), so the placeholder
61686
+ * empty strings never survive into a validated item. Link-built items are
61687
+ * not resettable — there is no native provider to receive `reset()`.
61688
+ *
61689
+ * Wiring guidance (HA vacuum consumable-life sensors):
61690
+ * - a percent-remaining source (`numeric-sensor`, unit '%') → `level` via
61691
+ * `identity` (or `linear` scale 1 offset 0 clamp [0,100] to be safe);
61692
+ * - an hours-remaining source (e.g. Dreame 'Main Brush Time Left', unit 'h')
61693
+ * → `level` via `linear` with scale = 100 / max-hours for that item
61694
+ * (e.g. main brush 300 h → scale 0.3333) + clamp [0,100];
61695
+ * - a discrete source (`enum-sensor`, e.g. mop pad 'installed') → `status`
61696
+ * via `enum-map` (e.g. { installed: 'ok', missing: 'replace' }).
61697
+ * A numeric→'replace' THRESHOLD (level < 10 → 'replace') is NOT expressible
61698
+ * with the current transform kinds — leave `status` null (valid) until the
61699
+ * expression transform lands. */
61700
+ /** Generic Customize target for one consumable item (D936). Native rows stay read-only. */
61701
+ var consumablesCustomize = {
61702
+ version: 1,
61703
+ targets: [{
61704
+ id: "items",
61705
+ cardinality: "keyedArray",
61706
+ vocabulary: { cap: "consumables" },
61707
+ deviceTypes: Object.values(require_err_msg.DeviceType),
61708
+ apply: "add",
61709
+ path: "items",
61710
+ keyField: "key",
61711
+ labelField: "label",
61712
+ itemSchema: ConsumableItemSchema,
61713
+ nativeItems: "read-only",
61714
+ sourceReport: { status: "assignment-status" },
61715
+ fields: [
61716
+ {
61717
+ path: "level",
61718
+ sources: [{
61719
+ kind: "numeric",
61720
+ transforms: [{ kind: "identity" }, {
61721
+ kind: "linear",
61722
+ defaultScale: 1,
61723
+ defaultOffset: 0,
61724
+ clampMin: 0,
61725
+ clampMax: 100
61726
+ }]
61727
+ }]
61728
+ },
61729
+ {
61730
+ path: "remaining.value",
61731
+ sources: [{
61732
+ kind: "numeric",
61733
+ transforms: [{ kind: "identity" }]
61734
+ }],
61735
+ literals: [{
61736
+ path: "remaining.unit",
61737
+ values: [...ConsumableRemainingUnitSchema.options]
61738
+ }]
61739
+ },
61740
+ {
61741
+ path: "status",
61742
+ sources: [{
61743
+ kind: "enum",
61744
+ transforms: [{
61745
+ kind: "enum-map",
61746
+ outputValues: [...ConsumableStatusSchema.options],
61747
+ unmapped: null
61748
+ }]
61749
+ }]
61750
+ }
61751
+ ],
61752
+ traits: [{
61753
+ path: "kind",
61754
+ values: [...ConsumableKindSchema.options],
61755
+ defaultValue: "wear"
61756
+ }, {
61757
+ path: "form",
61758
+ values: [...ConsumableFormSchema.options],
61759
+ defaultValue: "part"
61760
+ }],
61761
+ companions: [{
61762
+ kind: "clock",
61763
+ path: "lastChangedAt",
61764
+ when: "add"
61765
+ }, {
61766
+ kind: "clock",
61767
+ path: "lastFetchedAt",
61768
+ when: "add"
61769
+ }],
61770
+ advancedExpression: true
61771
+ }]
61772
+ };
61636
61773
  var consumablesCapability = {
61637
61774
  name: "consumables",
61638
61775
  scope: "device",
@@ -61670,10 +61807,7 @@ reset: require_sleep.method(zod.z.object({
61670
61807
  status: {
61671
61808
  schema: ConsumablesStatusSchema,
61672
61809
  kind: "push",
61673
- empty: {
61674
- items: [],
61675
- lastChangedAt: 0
61676
- },
61810
+ empty: EMPTY_STATUS,
61677
61811
  itemArray: {
61678
61812
  path: "items",
61679
61813
  keyField: "key",
@@ -61709,6 +61843,7 @@ reset: require_sleep.method(zod.z.object({
61709
61843
  * brush's remaining life and a dishwasher's salt are each recorded the moment
61710
61844
  * their provider reports them; an item that appears later gets its series.
61711
61845
  */
61846
+ customize: consumablesCustomize,
61712
61847
  history: {
61713
61848
  fields: {},
61714
61849
  items: {
@@ -62511,6 +62646,38 @@ var dishwasherCapability = {
62511
62646
  };
62512
62647
  //#endregion
62513
62648
  //#region src/capabilities/doorbell.cap.ts
62649
+ /** A rise closer than this to the previous one is the same press (D671). */
62650
+ var DOORBELL_RISE_DEBOUNCE_MS = 2e3;
62651
+ /** Pulse override: a rising edge advances `lastPressedAt` and the press count. */
62652
+ var doorbellCustomize = {
62653
+ version: 1,
62654
+ targets: [{
62655
+ id: "pressed",
62656
+ cardinality: "event",
62657
+ shape: "pulse",
62658
+ vocabulary: {
62659
+ cap: "doorbell",
62660
+ eventName: "onPressed"
62661
+ },
62662
+ deviceTypes: [require_err_msg.DeviceType.Camera],
62663
+ apply: "add",
62664
+ applyAuthority: { kind: "composition-claim" },
62665
+ eventName: "onPressed",
62666
+ edges: ["rising"],
62667
+ timestampPath: "lastPressedAt",
62668
+ counterPath: "pressCountSinceStart",
62669
+ highWater: "composer-advance",
62670
+ combine: "any",
62671
+ debounce: {
62672
+ kind: "rising-edge",
62673
+ defaultDebounceMs: DOORBELL_RISE_DEBOUNCE_MS,
62674
+ changedAtRequired: true
62675
+ },
62676
+ sources: [{ kind: "binary" }, { kind: "switch" }],
62677
+ sourceReport: { status: "assignment-status" },
62678
+ advancedExpression: true
62679
+ }]
62680
+ };
62514
62681
  var DoorbellStatusSchema = zod.z.object({
62515
62682
  /** Ms epoch of the last press. null = never observed since this provider started. */
62516
62683
  lastPressedAt: zod.z.number().nullable(),
@@ -62577,7 +62744,8 @@ onPressed: {
62577
62744
  /**
62578
62745
  * History (D850): none — `pressCountSinceStart` resets with the addon, so it is not a monotonic meter; presses live in the events ledger.
62579
62746
  */
62580
- history: "none"
62747
+ history: "none",
62748
+ customize: doorbellCustomize
62581
62749
  };
62582
62750
  //#endregion
62583
62751
  //#region src/capabilities/enum-sensor.cap.ts
@@ -65324,6 +65492,44 @@ authKey: zod.z.string().optional() }), zod.z.object({
65324
65492
  //#endregion
65325
65493
  //#region src/capabilities/motion.cap.ts
65326
65494
  /**
65495
+ * Span timeout for a camera's attached sensors. This is the pipeline-runner
65496
+ * `motionCooldownMs` default: the window after which a heartbeat-only edge
65497
+ * no longer counts. The span does not declare a separate cooldown.
65498
+ */
65499
+ var MOTION_SPAN_TIMEOUT_MS = 3e4;
65500
+ /** Span override: start on a rising edge, end on a fall or this timeout. */
65501
+ var motionCustomize = {
65502
+ version: 1,
65503
+ targets: [{
65504
+ id: "detected",
65505
+ cardinality: "event",
65506
+ shape: "span",
65507
+ vocabulary: {
65508
+ cap: "motion",
65509
+ eventName: "onMotionChanged"
65510
+ },
65511
+ deviceTypes: [require_err_msg.DeviceType.Camera],
65512
+ apply: "replace",
65513
+ applyAuthority: {
65514
+ kind: "camera-sensors",
65515
+ timeoutField: "motionCooldownMs"
65516
+ },
65517
+ eventName: "onMotionChanged",
65518
+ start: "rising-edge",
65519
+ end: "falling-edge-or-timeout",
65520
+ timeoutMs: MOTION_SPAN_TIMEOUT_MS,
65521
+ combine: "any",
65522
+ sourceModes: [
65523
+ "in-addition",
65524
+ "confirm",
65525
+ "replace"
65526
+ ],
65527
+ sources: [{ kind: "binary" }, { kind: "switch" }],
65528
+ sourceReport: { status: "assignment-status" },
65529
+ advancedExpression: false
65530
+ }]
65531
+ };
65532
+ /**
65327
65533
  * Hardware / firmware motion sensor cap — binary detected state plus
65328
65534
  * a timestamp of the last observation. Distinct from
65329
65535
  * `motion-detection.cap.ts` which owns the LOCAL ML motion pipeline;
@@ -65487,7 +65693,8 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
65487
65693
  history: { fields: { detected: {
65488
65694
  kind: "boolean",
65489
65695
  excludeDeviceTypes: [require_err_msg.DeviceType.Camera]
65490
- } } }
65696
+ } } },
65697
+ customize: motionCustomize
65491
65698
  };
65492
65699
  //#endregion
65493
65700
  //#region src/capabilities/motion-trigger.cap.ts
@@ -69601,6 +69808,138 @@ var ptzAutotrackCapability = {
69601
69808
  history: "none"
69602
69809
  };
69603
69810
  //#endregion
69811
+ //#region src/running-state/defaults.ts
69812
+ var RUNNING_POWER_THRESHOLD_WATTS = 5;
69813
+ var RUNNING_POWER_START_DELAY_MS = 3e4;
69814
+ var RUNNING_POWER_STOP_DELAY_MS = 18e4;
69815
+ /** Before any provider reading — all fields unknown (D933). */
69816
+ var RUNNING_STATE_COLD = {
69817
+ running: null,
69818
+ since: null,
69819
+ source: "native",
69820
+ phase: null,
69821
+ lastFetchedAt: null
69822
+ };
69823
+ //#endregion
69824
+ //#region src/capabilities/running-state.cap.ts
69825
+ var RunningStateSourceSchema = zod.z.enum(["native", "assigned"]);
69826
+ var RunningStateStatusSchema = zod.z.object({
69827
+ /** null = unknown — never coerced to false (D393). */
69828
+ running: zod.z.boolean().nullable(),
69829
+ /** Epoch ms the current boolean began; null while `running` is null. */
69830
+ since: zod.z.number().nullable(),
69831
+ source: RunningStateSourceSchema,
69832
+ phase: zod.z.string().nullable(),
69833
+ /** null until a reading has been published (D393). */
69834
+ lastFetchedAt: zod.z.number().nullable()
69835
+ });
69836
+ var RunningFlipEventDataSchema = zod.z.object({
69837
+ deviceId: zod.z.number(),
69838
+ since: zod.z.number().nullable(),
69839
+ phase: zod.z.string().nullable()
69840
+ });
69841
+ var RUNNING_DEVICE_TYPES = Object.values(require_err_msg.DeviceType);
69842
+ /** Generic Customize target for the running boolean (D936). */
69843
+ var runningCustomize = {
69844
+ version: 1,
69845
+ targets: [{
69846
+ id: "running",
69847
+ cardinality: "scalar",
69848
+ vocabulary: {
69849
+ cap: "running-state",
69850
+ stateField: "running"
69851
+ },
69852
+ deviceTypes: [
69853
+ require_err_msg.DeviceType.Dishwasher,
69854
+ require_err_msg.DeviceType.Vacuum,
69855
+ require_err_msg.DeviceType.LawnMower,
69856
+ require_err_msg.DeviceType.MediaPlayer,
69857
+ require_err_msg.DeviceType.WaterHeater,
69858
+ require_err_msg.DeviceType.Humidifier,
69859
+ require_err_msg.DeviceType.Fan,
69860
+ require_err_msg.DeviceType.Climate,
69861
+ require_err_msg.DeviceType.Thermostat,
69862
+ require_err_msg.DeviceType.PetFeeder
69863
+ ],
69864
+ apply: "add-or-replace",
69865
+ path: "running",
69866
+ sources: [
69867
+ {
69868
+ kind: "switch",
69869
+ transforms: [{ kind: "identity" }]
69870
+ },
69871
+ {
69872
+ kind: "binary",
69873
+ transforms: [{ kind: "identity" }, { kind: "invert" }]
69874
+ },
69875
+ {
69876
+ kind: "numeric",
69877
+ requiredUnit: "W",
69878
+ transforms: [{
69879
+ kind: "threshold",
69880
+ comparison: "gte",
69881
+ defaultThreshold: 5,
69882
+ defaultStartDwellMs: RUNNING_POWER_START_DELAY_MS,
69883
+ defaultStopDwellMs: RUNNING_POWER_STOP_DELAY_MS,
69884
+ thresholdUnit: "W"
69885
+ }]
69886
+ }
69887
+ ],
69888
+ companions: [
69889
+ {
69890
+ kind: "constant",
69891
+ path: "source",
69892
+ value: "assigned",
69893
+ when: "always"
69894
+ },
69895
+ {
69896
+ kind: "constant",
69897
+ path: "phase",
69898
+ value: null,
69899
+ when: "always"
69900
+ },
69901
+ {
69902
+ kind: "clock",
69903
+ path: "lastFetchedAt",
69904
+ when: "always"
69905
+ },
69906
+ {
69907
+ kind: "transition-time",
69908
+ path: "since",
69909
+ sourceChangedAt: "prefer"
69910
+ }
69911
+ ],
69912
+ sourceReport: {
69913
+ status: "assignment-status",
69914
+ runtimeField: "source",
69915
+ nativeValue: "native",
69916
+ assignedValue: "assigned"
69917
+ },
69918
+ advancedExpression: true
69919
+ }]
69920
+ };
69921
+ var runningStateCapability = {
69922
+ name: "running-state",
69923
+ scope: "device",
69924
+ deviceNative: true,
69925
+ mode: "singleton",
69926
+ deviceTypes: RUNNING_DEVICE_TYPES,
69927
+ methods: {},
69928
+ events: {
69929
+ onStarted: { data: RunningFlipEventDataSchema },
69930
+ onFinished: { data: RunningFlipEventDataSchema }
69931
+ },
69932
+ status: {
69933
+ schema: RunningStateStatusSchema,
69934
+ kind: "push"
69935
+ },
69936
+ runtimeState: RunningStateStatusSchema,
69937
+ durability: "restored",
69938
+ history: { fields: { running: { kind: "boolean" } } },
69939
+ volatileStateFields: ["lastFetchedAt"],
69940
+ customize: runningCustomize
69941
+ };
69942
+ //#endregion
69604
69943
  //#region src/capabilities/reboot.cap.ts
69605
69944
  /**
69606
69945
  * reboot — device-scoped capability for "soft" device reboots (firmware
@@ -75827,6 +76166,60 @@ var PIPELINE_OWNER_CAPABILITY_NAMES = [
75827
76166
  "pipeline-runner"
75828
76167
  ];
75829
76168
  //#endregion
76169
+ //#region src/running-state/from-operation.ts
76170
+ function programStartFromRemaining(running, remainingSeconds, fetchedAt) {
76171
+ if (!running || remainingSeconds === null || remainingSeconds === void 0) return null;
76172
+ if (remainingSeconds <= 0) return null;
76173
+ return fetchedAt - remainingSeconds * 1e3;
76174
+ }
76175
+ function resolveSince(running, previous, transitionAtMs, bootstrapSinceMs) {
76176
+ if (running === null) return null;
76177
+ const prevRunning = previous?.running ?? null;
76178
+ if (prevRunning === null) return bootstrapSinceMs;
76179
+ if (prevRunning !== running) return transitionAtMs;
76180
+ return previous?.since ?? null;
76181
+ }
76182
+ function nativeSlice(running, phase, previous, transitionAtMs, fetchedAt, bootstrapSinceMs) {
76183
+ return {
76184
+ running,
76185
+ since: resolveSince(running, previous, transitionAtMs, bootstrapSinceMs),
76186
+ source: "native",
76187
+ phase: running === null ? null : phase,
76188
+ lastFetchedAt: fetchedAt
76189
+ };
76190
+ }
76191
+ function runningFromDishwasherOperation(operation, program, previous, fetchedAt, remainingSeconds, transitionAt) {
76192
+ const transitionAtMs = transitionAt ?? fetchedAt;
76193
+ if (operation === null) return nativeSlice(null, null, previous, transitionAtMs, fetchedAt, null);
76194
+ if (operation === "Run" || operation === "Aborting") {
76195
+ const bootstrap = programStartFromRemaining(true, remainingSeconds, fetchedAt);
76196
+ return nativeSlice(true, program ?? operation, previous, transitionAtMs, fetchedAt, bootstrap);
76197
+ }
76198
+ if (operation === "Pause") return nativeSlice(false, "Pause", previous, transitionAtMs, fetchedAt, null);
76199
+ return nativeSlice(false, operation, previous, transitionAtMs, fetchedAt, null);
76200
+ }
76201
+ function runningFromVacuumState(state, previous, fetchedAt, transitionAt) {
76202
+ const transitionAtMs = transitionAt ?? fetchedAt;
76203
+ if (state === null) return nativeSlice(null, null, previous, transitionAtMs, fetchedAt, null);
76204
+ if (state === "cleaning" || state === "returning" || state === "drying") return nativeSlice(true, state, previous, transitionAtMs, fetchedAt, null);
76205
+ if (state === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
76206
+ return nativeSlice(false, state, previous, transitionAtMs, fetchedAt, null);
76207
+ }
76208
+ function runningFromLawnMower(activity, previous, fetchedAt, transitionAt) {
76209
+ const transitionAtMs = transitionAt ?? fetchedAt;
76210
+ if (activity === null) return nativeSlice(null, null, previous, transitionAtMs, fetchedAt, null);
76211
+ if (activity === "mowing") return nativeSlice(true, activity, previous, transitionAtMs, fetchedAt, null);
76212
+ if (activity === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
76213
+ return nativeSlice(false, activity, previous, transitionAtMs, fetchedAt, null);
76214
+ }
76215
+ function runningFromMediaPlayer(state, previous, fetchedAt, transitionAt) {
76216
+ const transitionAtMs = transitionAt ?? fetchedAt;
76217
+ if (state === null) return nativeSlice(null, null, previous, transitionAtMs, fetchedAt, null);
76218
+ if (state === "playing" || state === "buffering") return nativeSlice(true, state, previous, transitionAtMs, fetchedAt, null);
76219
+ if (state === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
76220
+ return nativeSlice(false, state, previous, transitionAtMs, fetchedAt, null);
76221
+ }
76222
+ //#endregion
75830
76223
  //#region src/clips/clip-event-labels.ts
75831
76224
  /**
75832
76225
  * Which of OUR object detections a clip window holds — the ONE overlap rule
@@ -76470,11 +76863,12 @@ function expressionOutcome(source, read, now, stateful) {
76470
76863
  return unavailable;
76471
76864
  }
76472
76865
  const deadlines = [];
76866
+ const hooks = {
76867
+ noteDeadline: (at) => deadlines.push(at),
76868
+ convert: (value, from, to) => tryConvertUnit(value, normalizeUnit(from) ?? from, normalizeUnit(to) ?? to) ?? null
76869
+ };
76473
76870
  const result = require_composition.evaluateExpressionSource(source.expr, values, now, {
76474
- hooks: {
76475
- noteDeadline: (at) => deadlines.push(at),
76476
- convert: (value, from, to) => tryConvertUnit(value, normalizeUnit(from) ?? from, normalizeUnit(to) ?? to) ?? null
76477
- },
76871
+ hooks,
76478
76872
  ...stateful === void 0 ? {} : { invokeStateful: (invocation) => require_composition.evaluateStatefulExpressionCall(stateful.callPathPrefix === void 0 ? invocation : {
76479
76873
  ...invocation,
76480
76874
  path: `${stateful.callPathPrefix}@${invocation.path}`
@@ -76482,7 +76876,7 @@ function expressionOutcome(source, read, now, stateful) {
76482
76876
  currentOutput: stateful.currentOutput,
76483
76877
  startedAtMs: stateful.startedAtMs,
76484
76878
  nowMs: now
76485
- }) }
76879
+ }, hooks) }
76486
76880
  });
76487
76881
  if (!result.ok) return {
76488
76882
  state: "unavailable",
@@ -76715,74 +77109,6 @@ function feederCustomizationExample(sources) {
76715
77109
  });
76716
77110
  }
76717
77111
  //#endregion
76718
- //#region src/composition/presets/doorbell-feature.ts
76719
- /**
76720
- * The doorbell of a camera as a customization (D671). ONE builder: the admin
76721
- * UI's Customize → Doorbell card writes every doorbell feature through it, and
76722
- * edits one only when it is exactly what this builds (`isDoorbellPresetFeature`)
76723
- * — a composed doorbell has one canonical shape.
76724
- */
76725
- /** A rise closer than this to the previous one is the same press (D671). */
76726
- var DOORBELL_RISE_DEBOUNCE_MS = 2e3;
76727
- /** Every source cap of `source` that `SOURCE_CAP_ACTIVE_FIELD` knows AND the device has bound. */
76728
- function doorbellFeatureSources(source, boundCaps) {
76729
- return Object.keys(require_composition.SOURCE_CAP_ACTIVE_FIELD).filter((cap) => Object.hasOwn(require_composition.SOURCE_CAP_CHANGED_AT_FIELD, cap) && boundCaps.includes(cap)).toSorted().flatMap((cap) => {
76730
- const activeField = require_composition.SOURCE_CAP_ACTIVE_FIELD[cap];
76731
- const changedAtField = require_composition.SOURCE_CAP_CHANGED_AT_FIELD[cap];
76732
- return activeField === void 0 || changedAtField === void 0 ? [] : [{
76733
- source,
76734
- cap,
76735
- activeField,
76736
- changedAtField
76737
- }];
76738
- });
76739
- }
76740
- /** The canonical D671 doorbell feature. Throws on zero sources. */
76741
- function buildDoorbellCompositionFeature(input) {
76742
- const sources = [...input.sources].toSorted((a, b) => `${a.source.addonId}/${a.source.stableId}#${a.cap}`.localeCompare(`${b.source.addonId}/${b.source.stableId}#${b.cap}`));
76743
- if (sources.length === 0) throw new Error("doorbell composition needs at least one source");
76744
- const edgeBindings = {};
76745
- sources.forEach((entry, index) => {
76746
- edgeBindings[`active${index}`] = {
76747
- kind: "from",
76748
- source: entry.source,
76749
- cap: entry.cap,
76750
- fieldPath: entry.activeField
76751
- };
76752
- edgeBindings[`changed${index}`] = {
76753
- kind: "from",
76754
- source: entry.source,
76755
- cap: entry.cap,
76756
- fieldPath: entry.changedAtField
76757
- };
76758
- });
76759
- return {
76760
- kind: "fields",
76761
- cap: "doorbell",
76762
- enabled: input.enabled,
76763
- fields: {
76764
- lastPressedAt: {
76765
- kind: "expression",
76766
- expr: `latest(${sources.map((_, index) => `rose(active${index}, changed${index}, ${DOORBELL_RISE_DEBOUNCE_MS})`).join(", ")})`,
76767
- bindings: edgeBindings
76768
- },
76769
- pressCountSinceStart: {
76770
- kind: "expression",
76771
- expr: "count(lastPressedAt)",
76772
- bindings: { lastPressedAt: {
76773
- kind: "from",
76774
- source: {
76775
- addonId: input.camera.addonId,
76776
- stableId: input.camera.stableId
76777
- },
76778
- cap: "doorbell",
76779
- fieldPath: "lastPressedAt"
76780
- } }
76781
- }
76782
- }
76783
- };
76784
- }
76785
- //#endregion
76786
77112
  //#region src/composition/presets/numeric-transforms.ts
76787
77113
  /**
76788
77114
  * Self-only invert / unit-convert composition features (D663). The Numeric
@@ -77434,6 +77760,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
77434
77760
  ptzAutotrack: ptzAutotrackCapability,
77435
77761
  recordingOnboard: recordingOnboardCapability,
77436
77762
  recordingSignal: recordingSignalCapability,
77763
+ runningState: runningStateCapability,
77437
77764
  sceneMonitor: sceneMonitorCapability,
77438
77765
  scriptRunner: scriptRunnerCapability,
77439
77766
  smoke: smokeCapability,
@@ -87017,6 +87344,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
87017
87344
  access: "create",
87018
87345
  role: "admin"
87019
87346
  },
87347
+ "runningState.getStatus": {
87348
+ capName: "running-state",
87349
+ capScope: "device",
87350
+ addonId: null,
87351
+ access: "view",
87352
+ role: "viewer"
87353
+ },
87020
87354
  "sceneMonitor.captureReference": {
87021
87355
  capName: "scene-monitor",
87022
87356
  capScope: "device",
@@ -89306,6 +89640,7 @@ var KNOWN_CAP_NAMES = [
89306
89640
  "recording-onboard",
89307
89641
  "recording-signal",
89308
89642
  "records",
89643
+ "running-state",
89309
89644
  "scene-monitor",
89310
89645
  "script-runner",
89311
89646
  "server-management",
@@ -89420,6 +89755,7 @@ var DEVICE_CAP_NAMES = [
89420
89755
  "recording",
89421
89756
  "recording-onboard",
89422
89757
  "recording-signal",
89758
+ "running-state",
89423
89759
  "scene-monitor",
89424
89760
  "script-runner",
89425
89761
  "smoke",
@@ -92104,6 +92440,32 @@ var APPLIANCE_CAP_VOCABULARY = {
92104
92440
  }],
92105
92441
  events: { onSent: { notOperatorFacing: "a delivery receipt of a send this system made — not a fact about the world" } }
92106
92442
  },
92443
+ "running-state": {
92444
+ scope: "device",
92445
+ noun: t("Running", "In funzione"),
92446
+ state: [{
92447
+ kind: "boolean",
92448
+ field: "running",
92449
+ label: t("Running", "In funzione"),
92450
+ whenTrue: t("When {device} starts", "Quando {device} inizia"),
92451
+ whenFalse: t("When {device} finishes", "Quando {device} finisce"),
92452
+ icon: "play"
92453
+ }],
92454
+ events: {
92455
+ onStarted: {
92456
+ category: require_event_category.EventCategory.RunningStarted,
92457
+ label: t("Started running", "Ha iniziato a funzionare"),
92458
+ phrase: t("When {device} starts running", "Quando {device} inizia a funzionare"),
92459
+ icon: "play"
92460
+ },
92461
+ onFinished: {
92462
+ category: require_event_category.EventCategory.RunningFinished,
92463
+ label: t("Finished", "Ha finito"),
92464
+ phrase: t("When {device} finishes", "Quando {device} finisce"),
92465
+ icon: "square"
92466
+ }
92467
+ }
92468
+ },
92107
92469
  update: {
92108
92470
  scope: "device",
92109
92471
  noun: t("Firmware update", "Aggiornamento firmware"),
@@ -95044,6 +95406,7 @@ var CAP_NAMES_WITH_STATUS = [
95044
95406
  "recording-archive",
95045
95407
  "recording-onboard",
95046
95408
  "recording-signal",
95409
+ "running-state",
95047
95410
  "scene-monitor",
95048
95411
  "script-runner",
95049
95412
  "smoke",
@@ -95199,6 +95562,7 @@ var CAPABILITY_NAMES = {
95199
95562
  recordingOnboard: "recording-onboard",
95200
95563
  recordingSignal: "recording-signal",
95201
95564
  records: "records",
95565
+ runningState: "running-state",
95202
95566
  sceneMonitor: "scene-monitor",
95203
95567
  scriptRunner: "script-runner",
95204
95568
  serverManagement: "server-management",
@@ -95792,6 +96156,10 @@ var CAPABILITY_ROUTER_KEYS = [
95792
96156
  key: "records",
95793
96157
  name: "records"
95794
96158
  },
96159
+ {
96160
+ key: "runningState",
96161
+ name: "running-state"
96162
+ },
95795
96163
  {
95796
96164
  key: "sceneMonitor",
95797
96165
  name: "scene-monitor"
@@ -96108,6 +96476,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
96108
96476
  recordingOnboardCapability,
96109
96477
  recordingSignalCapability,
96110
96478
  recordsCapability,
96479
+ runningStateCapability,
96111
96480
  sceneMonitorCapability,
96112
96481
  scriptRunnerCapability,
96113
96482
  serverManagementCapability,
@@ -98424,6 +98793,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
98424
98793
  form: "single",
98425
98794
  optional: true
98426
98795
  }],
98796
+ "runningState.getStatus": [{
98797
+ name: "deviceId",
98798
+ form: "single",
98799
+ optional: false
98800
+ }],
98427
98801
  "sceneMonitor.captureReference": [{
98428
98802
  name: "deviceId",
98429
98803
  form: "single",
@@ -99125,7 +99499,7 @@ function getCapsByProviderKind(kind) {
99125
99499
  //#region src/generated/runtime-state-durability.ts
99126
99500
  /**
99127
99501
  * Per-cap runtime-state policy, projected from every `*.cap.ts` that declares
99128
- * `runtimeState`. 71 caps: 37 `restored`, 34 `session`.
99502
+ * `runtimeState`. 72 caps: 38 `restored`, 34 `session`.
99129
99503
  *
99130
99504
  * A cap absent from this map has no runtime-state slice at all. A cap PRESENT
99131
99505
  * with `durability: 'session'` has one and has decided not to keep it.
@@ -99343,6 +99717,10 @@ var RUNTIME_STATE_POLICY = {
99343
99717
  durability: "session",
99344
99718
  volatileFields: []
99345
99719
  },
99720
+ "running-state": {
99721
+ durability: "restored",
99722
+ volatileFields: ["lastFetchedAt"]
99723
+ },
99346
99724
  "scene-monitor": {
99347
99725
  durability: "session",
99348
99726
  volatileFields: []
@@ -99465,6 +99843,7 @@ var RESTORED_CAP_NAMES = [
99465
99843
  "pressure-sensor",
99466
99844
  "privacy-mask",
99467
99845
  "recording-onboard",
99846
+ "running-state",
99468
99847
  "smoke",
99469
99848
  "stream-catalog",
99470
99849
  "stream-params",
@@ -99580,7 +99959,7 @@ var BucketAccumulator = class {
99580
99959
  //#region src/generated/history-catalog.ts
99581
99960
  /**
99582
99961
  * Cap history catalog, projected from every `*.cap.ts` `history` block.
99583
- * 40 caps with series (73 series), 30 caps answered `'none'`.
99962
+ * 41 caps with series (74 series), 30 caps answered `'none'`.
99584
99963
  * Field keys are `runtimeState` paths (`a.b` into fixed objects only).
99585
99964
  */
99586
99965
  var HISTORY_CATALOG = {
@@ -99857,6 +100236,7 @@ var HISTORY_CATALOG = {
99857
100236
  unit: "hPa",
99858
100237
  deadband: .1
99859
100238
  } },
100239
+ "running-state": { "running": { kind: "boolean" } },
99860
100240
  "smoke": { "detected": { kind: "boolean" } },
99861
100241
  "stream-params": {
99862
100242
  "main.bitrate": {
@@ -100002,6 +100382,1852 @@ function historyFieldsFor(capName) {
100002
100382
  return HISTORY_CATALOG[capName] ?? {};
100003
100383
  }
100004
100384
  //#endregion
100385
+ //#region src/generated/customize-catalog.ts
100386
+ /**
100387
+ * Customize catalog, projected from every `*.cap.ts` `customize` block.
100388
+ * 5 caps. Field keys are `runtimeState` paths. No Zod.
100389
+ */
100390
+ var CAP_CUSTOMIZE_CATALOG = {
100391
+ "battery": {
100392
+ version: 1,
100393
+ targets: [{
100394
+ id: "percentage",
100395
+ cardinality: "scalar",
100396
+ deviceTypes: [
100397
+ require_err_msg.DeviceType.Camera,
100398
+ require_err_msg.DeviceType.Sensor,
100399
+ require_err_msg.DeviceType.Button,
100400
+ require_err_msg.DeviceType.Switch,
100401
+ require_err_msg.DeviceType.PetFeeder,
100402
+ require_err_msg.DeviceType.Container,
100403
+ require_err_msg.DeviceType.Thermostat
100404
+ ],
100405
+ apply: "add-or-replace",
100406
+ vocabularyCap: "battery",
100407
+ vocabularyStateField: "percentage",
100408
+ sources: [{
100409
+ kind: "field",
100410
+ valueKinds: ["number", "string"],
100411
+ transformKinds: ["identity", "linear"]
100412
+ }],
100413
+ sourceReport: { status: "assignment-status" },
100414
+ advancedExpression: true,
100415
+ path: "percentage",
100416
+ valueKind: "number",
100417
+ nullable: true,
100418
+ companions: [
100419
+ {
100420
+ kind: "constant",
100421
+ path: "charging",
100422
+ value: "unknown",
100423
+ when: "add"
100424
+ },
100425
+ {
100426
+ kind: "constant",
100427
+ path: "sleeping",
100428
+ value: false,
100429
+ when: "add"
100430
+ },
100431
+ {
100432
+ kind: "clock",
100433
+ path: "lastUpdated",
100434
+ when: "add"
100435
+ }
100436
+ ]
100437
+ }]
100438
+ },
100439
+ "consumables": {
100440
+ version: 1,
100441
+ targets: [{
100442
+ id: "items",
100443
+ cardinality: "keyedArray",
100444
+ deviceTypes: [
100445
+ require_err_msg.DeviceType.Camera,
100446
+ require_err_msg.DeviceType.Hub,
100447
+ require_err_msg.DeviceType.Light,
100448
+ require_err_msg.DeviceType.Siren,
100449
+ require_err_msg.DeviceType.Switch,
100450
+ require_err_msg.DeviceType.Sensor,
100451
+ require_err_msg.DeviceType.Thermostat,
100452
+ require_err_msg.DeviceType.Climate,
100453
+ require_err_msg.DeviceType.Button,
100454
+ require_err_msg.DeviceType.EventEmitter,
100455
+ require_err_msg.DeviceType.Update,
100456
+ require_err_msg.DeviceType.Generic,
100457
+ require_err_msg.DeviceType.Notifier,
100458
+ require_err_msg.DeviceType.Script,
100459
+ require_err_msg.DeviceType.Automation,
100460
+ require_err_msg.DeviceType.Lock,
100461
+ require_err_msg.DeviceType.Cover,
100462
+ require_err_msg.DeviceType.Valve,
100463
+ require_err_msg.DeviceType.Humidifier,
100464
+ require_err_msg.DeviceType.WaterHeater,
100465
+ require_err_msg.DeviceType.Fan,
100466
+ require_err_msg.DeviceType.MediaPlayer,
100467
+ require_err_msg.DeviceType.AlarmPanel,
100468
+ require_err_msg.DeviceType.Control,
100469
+ require_err_msg.DeviceType.Presence,
100470
+ require_err_msg.DeviceType.Weather,
100471
+ require_err_msg.DeviceType.Vacuum,
100472
+ require_err_msg.DeviceType.LawnMower,
100473
+ require_err_msg.DeviceType.Container,
100474
+ require_err_msg.DeviceType.Image,
100475
+ require_err_msg.DeviceType.PetFeeder,
100476
+ require_err_msg.DeviceType.Dishwasher
100477
+ ],
100478
+ apply: "add",
100479
+ vocabularyCap: "consumables",
100480
+ sources: [],
100481
+ sourceReport: { status: "assignment-status" },
100482
+ advancedExpression: true,
100483
+ path: "items",
100484
+ keyField: "key",
100485
+ labelField: "label",
100486
+ nativeItems: "read-only",
100487
+ fields: [
100488
+ {
100489
+ path: "level",
100490
+ valueKind: "number",
100491
+ nullable: true,
100492
+ sources: [{
100493
+ kind: "numeric",
100494
+ transformKinds: ["identity", "linear"]
100495
+ }]
100496
+ },
100497
+ {
100498
+ path: "remaining.value",
100499
+ valueKind: "number",
100500
+ nullable: true,
100501
+ sources: [{
100502
+ kind: "numeric",
100503
+ transformKinds: ["identity"]
100504
+ }],
100505
+ literals: [{
100506
+ path: "remaining.unit",
100507
+ values: [
100508
+ "days",
100509
+ "hours",
100510
+ "cycles"
100511
+ ]
100512
+ }]
100513
+ },
100514
+ {
100515
+ path: "status",
100516
+ valueKind: "enum",
100517
+ nullable: true,
100518
+ enumValues: [
100519
+ "ok",
100520
+ "low",
100521
+ "empty",
100522
+ "full",
100523
+ "replace"
100524
+ ],
100525
+ sources: [{
100526
+ kind: "enum",
100527
+ transformKinds: ["enum-map"]
100528
+ }]
100529
+ }
100530
+ ],
100531
+ traits: [{
100532
+ path: "kind",
100533
+ values: [
100534
+ "wear",
100535
+ "supply",
100536
+ "waste"
100537
+ ],
100538
+ defaultValue: "wear"
100539
+ }, {
100540
+ path: "form",
100541
+ values: [
100542
+ "part",
100543
+ "tank",
100544
+ "product",
100545
+ "bin"
100546
+ ],
100547
+ defaultValue: "part"
100548
+ }],
100549
+ companions: [{
100550
+ kind: "clock",
100551
+ path: "lastChangedAt",
100552
+ when: "add"
100553
+ }, {
100554
+ kind: "clock",
100555
+ path: "lastFetchedAt",
100556
+ when: "add"
100557
+ }]
100558
+ }]
100559
+ },
100560
+ "doorbell": {
100561
+ version: 1,
100562
+ targets: [{
100563
+ id: "pressed",
100564
+ cardinality: "event",
100565
+ deviceTypes: [require_err_msg.DeviceType.Camera],
100566
+ apply: "add",
100567
+ vocabularyCap: "doorbell",
100568
+ vocabularyEvent: "onPressed",
100569
+ sources: [{
100570
+ kind: "binary",
100571
+ transformKinds: []
100572
+ }, {
100573
+ kind: "switch",
100574
+ transformKinds: []
100575
+ }],
100576
+ sourceReport: { status: "assignment-status" },
100577
+ advancedExpression: true,
100578
+ shape: "pulse",
100579
+ applyAuthority: { kind: "composition-claim" },
100580
+ eventName: "onPressed",
100581
+ combine: "any",
100582
+ edges: ["rising"],
100583
+ timestampPath: "lastPressedAt",
100584
+ counterPath: "pressCountSinceStart",
100585
+ highWater: "composer-advance",
100586
+ debounceMs: 2e3
100587
+ }]
100588
+ },
100589
+ "motion": {
100590
+ version: 1,
100591
+ targets: [{
100592
+ id: "detected",
100593
+ cardinality: "event",
100594
+ deviceTypes: [require_err_msg.DeviceType.Camera],
100595
+ apply: "replace",
100596
+ vocabularyCap: "motion",
100597
+ vocabularyEvent: "onMotionChanged",
100598
+ sources: [{
100599
+ kind: "binary",
100600
+ transformKinds: []
100601
+ }, {
100602
+ kind: "switch",
100603
+ transformKinds: []
100604
+ }],
100605
+ sourceReport: { status: "assignment-status" },
100606
+ advancedExpression: false,
100607
+ shape: "span",
100608
+ applyAuthority: {
100609
+ kind: "camera-sensors",
100610
+ timeoutField: "motionCooldownMs"
100611
+ },
100612
+ eventName: "onMotionChanged",
100613
+ combine: "any",
100614
+ start: "rising-edge",
100615
+ end: "falling-edge-or-timeout",
100616
+ timeoutMs: 3e4,
100617
+ sourceModes: [
100618
+ "in-addition",
100619
+ "confirm",
100620
+ "replace"
100621
+ ]
100622
+ }]
100623
+ },
100624
+ "running-state": {
100625
+ version: 1,
100626
+ targets: [{
100627
+ id: "running",
100628
+ cardinality: "scalar",
100629
+ deviceTypes: [
100630
+ require_err_msg.DeviceType.Dishwasher,
100631
+ require_err_msg.DeviceType.Vacuum,
100632
+ require_err_msg.DeviceType.LawnMower,
100633
+ require_err_msg.DeviceType.MediaPlayer,
100634
+ require_err_msg.DeviceType.WaterHeater,
100635
+ require_err_msg.DeviceType.Humidifier,
100636
+ require_err_msg.DeviceType.Fan,
100637
+ require_err_msg.DeviceType.Climate,
100638
+ require_err_msg.DeviceType.Thermostat,
100639
+ require_err_msg.DeviceType.PetFeeder
100640
+ ],
100641
+ apply: "add-or-replace",
100642
+ vocabularyCap: "running-state",
100643
+ vocabularyStateField: "running",
100644
+ sources: [
100645
+ {
100646
+ kind: "switch",
100647
+ transformKinds: ["identity"]
100648
+ },
100649
+ {
100650
+ kind: "binary",
100651
+ transformKinds: ["identity", "invert"]
100652
+ },
100653
+ {
100654
+ kind: "numeric",
100655
+ requiredUnit: "W",
100656
+ transformKinds: ["threshold"]
100657
+ }
100658
+ ],
100659
+ sourceReport: {
100660
+ status: "assignment-status",
100661
+ runtimeField: "source",
100662
+ nativeValue: "native",
100663
+ assignedValue: "assigned"
100664
+ },
100665
+ advancedExpression: true,
100666
+ path: "running",
100667
+ valueKind: "boolean",
100668
+ nullable: true,
100669
+ companions: [
100670
+ {
100671
+ kind: "constant",
100672
+ path: "source",
100673
+ value: "assigned",
100674
+ when: "always"
100675
+ },
100676
+ {
100677
+ kind: "constant",
100678
+ path: "phase",
100679
+ value: null,
100680
+ when: "always"
100681
+ },
100682
+ {
100683
+ kind: "clock",
100684
+ path: "lastFetchedAt",
100685
+ when: "always"
100686
+ },
100687
+ {
100688
+ kind: "transition-time",
100689
+ path: "since",
100690
+ sourceChangedAt: "prefer"
100691
+ }
100692
+ ]
100693
+ }]
100694
+ }
100695
+ };
100696
+ //#endregion
100697
+ //#region src/composition/customize/override-draft.ts
100698
+ /**
100699
+ * A saved Customize assignment (D936). The schema is the type: callers use
100700
+ * `z.infer`, they do not restate the shape.
100701
+ */
100702
+ var OverrideSourceSchema = zod.z.object({
100703
+ addonId: zod.z.string().min(1),
100704
+ stableId: zod.z.string().min(1),
100705
+ cap: zod.z.string().min(1),
100706
+ fieldPath: zod.z.string().min(1)
100707
+ });
100708
+ var IdentityTransformDraftSchema = zod.z.object({ kind: zod.z.literal("identity") });
100709
+ var InvertTransformDraftSchema = zod.z.object({ kind: zod.z.literal("invert") });
100710
+ var ThresholdTransformDraftSchema = zod.z.object({
100711
+ kind: zod.z.literal("threshold"),
100712
+ comparison: zod.z.enum(["gte", "lte"]),
100713
+ threshold: zod.z.number(),
100714
+ startDwellMs: zod.z.number().nonnegative(),
100715
+ stopDwellMs: zod.z.number().nonnegative()
100716
+ });
100717
+ var LinearTransformDraftSchema = zod.z.object({
100718
+ kind: zod.z.literal("linear"),
100719
+ scale: zod.z.number(),
100720
+ offset: zod.z.number(),
100721
+ clampMin: zod.z.number().optional(),
100722
+ clampMax: zod.z.number().optional()
100723
+ });
100724
+ var EnumMapTransformDraftSchema = zod.z.object({
100725
+ kind: zod.z.literal("enum-map"),
100726
+ mapping: zod.z.record(zod.z.string(), zod.z.string().nullable())
100727
+ });
100728
+ var NumberBridgeTransformDraftSchema = zod.z.object({ kind: zod.z.literal("number") });
100729
+ var CustomizeTransformDraftSchema = zod.z.discriminatedUnion("kind", [
100730
+ IdentityTransformDraftSchema,
100731
+ InvertTransformDraftSchema,
100732
+ ThresholdTransformDraftSchema,
100733
+ LinearTransformDraftSchema,
100734
+ EnumMapTransformDraftSchema,
100735
+ NumberBridgeTransformDraftSchema
100736
+ ]);
100737
+ var ScalarOverrideDraftSchema = zod.z.object({
100738
+ kind: zod.z.literal("scalar"),
100739
+ cap: zod.z.string().min(1),
100740
+ targetId: zod.z.string().min(1),
100741
+ source: OverrideSourceSchema,
100742
+ transform: CustomizeTransformDraftSchema
100743
+ });
100744
+ var KeyedArrayOverrideDraftSchema = zod.z.object({
100745
+ kind: zod.z.literal("keyedArray"),
100746
+ cap: zod.z.string().min(1),
100747
+ targetId: zod.z.string().min(1),
100748
+ key: zod.z.string().min(1),
100749
+ label: zod.z.string().min(1),
100750
+ fieldPath: zod.z.string().min(1),
100751
+ source: OverrideSourceSchema,
100752
+ transform: CustomizeTransformDraftSchema
100753
+ });
100754
+ var PulseOverrideDraftSchema = zod.z.object({
100755
+ kind: zod.z.literal("pulse"),
100756
+ cap: zod.z.string().min(1),
100757
+ targetId: zod.z.string().min(1),
100758
+ enabled: zod.z.boolean(),
100759
+ debounceMs: zod.z.number().nonnegative(),
100760
+ sources: zod.z.array(OverrideSourceSchema).min(1)
100761
+ });
100762
+ var SpanSourceDraftSchema = OverrideSourceSchema.extend({ mode: zod.z.enum([
100763
+ "in-addition",
100764
+ "confirm",
100765
+ "replace"
100766
+ ]).optional() });
100767
+ var SpanOverrideDraftSchema = zod.z.object({
100768
+ kind: zod.z.literal("span"),
100769
+ cap: zod.z.string().min(1),
100770
+ targetId: zod.z.string().min(1),
100771
+ timeoutMs: zod.z.number().nonnegative(),
100772
+ cooldownMs: zod.z.number().nonnegative().optional(),
100773
+ sources: zod.z.array(SpanSourceDraftSchema)
100774
+ });
100775
+ var OverrideDraftSchema = zod.z.discriminatedUnion("kind", [
100776
+ ScalarOverrideDraftSchema,
100777
+ KeyedArrayOverrideDraftSchema,
100778
+ PulseOverrideDraftSchema,
100779
+ SpanOverrideDraftSchema
100780
+ ]);
100781
+ /** Effective authority for one declared target. Not a second stored switch. */
100782
+ var CustomizeAssignmentStatusSchema = zod.z.object({
100783
+ targetId: zod.z.string().min(1),
100784
+ configured: zod.z.boolean(),
100785
+ source: zod.z.enum(["native", "assigned"]),
100786
+ state: zod.z.enum([
100787
+ "active",
100788
+ "stale",
100789
+ "released",
100790
+ "unavailable"
100791
+ ]),
100792
+ reason: zod.z.string().nullable()
100793
+ });
100794
+ //#endregion
100795
+ //#region src/composition/customize/field-source.ts
100796
+ function fromRead(source, cap, fieldPath) {
100797
+ return {
100798
+ kind: "from",
100799
+ source,
100800
+ cap,
100801
+ fieldPath
100802
+ };
100803
+ }
100804
+ function expression(expr, bindings) {
100805
+ return {
100806
+ kind: "expression",
100807
+ expr,
100808
+ bindings
100809
+ };
100810
+ }
100811
+ function literal(expr) {
100812
+ return expression(expr, {});
100813
+ }
100814
+ function isLiteral(source, expr) {
100815
+ return source?.kind === "expression" && source.expr === expr && Object.keys(source.bindings).length === 0;
100816
+ }
100817
+ //#endregion
100818
+ //#region src/composition/customize/scalar-expr.ts
100819
+ var UNSIGNED = /^\d+(?:\.\d+)?$/;
100820
+ var SIGNED = /^-?\d+(?:\.\d+)?$/;
100821
+ var DWELL = /^dwell\(x (>=|<=) (\d+(?:\.\d+)?), (\d+(?:\.\d+)?), (\d+(?:\.\d+)?)\)$/;
100822
+ var LINEAR_CLAMP = /^clamp\((x|number\(x\)) \* (-?\d+(?:\.\d+)?) \+ (-?\d+(?:\.\d+)?), (-?\d+(?:\.\d+)?), (-?\d+(?:\.\d+)?)\)$/;
100823
+ var LINEAR_BARE = /^(x|number\(x\)) \* (-?\d+(?:\.\d+)?) \+ (-?\d+(?:\.\d+)?)$/;
100824
+ var IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/;
100825
+ function unsignedToken(value) {
100826
+ return token(value, UNSIGNED);
100827
+ }
100828
+ function signedToken(value) {
100829
+ return token(value, SIGNED);
100830
+ }
100831
+ function constantExpr(value) {
100832
+ if (typeof value === "string") return JSON.stringify(value);
100833
+ if (typeof value === "number") return signedToken(value);
100834
+ if (typeof value === "boolean") return value ? "true" : "false";
100835
+ return "null";
100836
+ }
100837
+ function isIdentifier(path) {
100838
+ return IDENT.test(path);
100839
+ }
100840
+ function dwellExpr(comparison, threshold, start, stop) {
100841
+ return `dwell(x ${comparison === "gte" ? ">=" : "<="} ${threshold}, ${start}, ${stop})`;
100842
+ }
100843
+ function linearExpr(inner, scale, offset, clampMin, clampMax) {
100844
+ const arithmetic = `${inner} * ${scale} + ${offset}`;
100845
+ if (clampMin === null || clampMax === null) return arithmetic;
100846
+ return `clamp(${arithmetic}, ${clampMin}, ${clampMax})`;
100847
+ }
100848
+ function parseDwell(expr) {
100849
+ const match = DWELL.exec(expr);
100850
+ if (match === null) return null;
100851
+ const threshold = Number(match[2]);
100852
+ const startDwellMs = Number(match[3]);
100853
+ const stopDwellMs = Number(match[4]);
100854
+ if (!Number.isFinite(threshold) || !Number.isFinite(startDwellMs) || !Number.isFinite(stopDwellMs)) return null;
100855
+ return {
100856
+ comparison: match[1] === "<=" ? "lte" : "gte",
100857
+ threshold,
100858
+ startDwellMs,
100859
+ stopDwellMs
100860
+ };
100861
+ }
100862
+ function parseLinear(expr) {
100863
+ const clamped = LINEAR_CLAMP.exec(expr);
100864
+ if (clamped !== null) return linearFrom(clamped[1], clamped[2], clamped[3], clamped[4], clamped[5]);
100865
+ const bare = LINEAR_BARE.exec(expr);
100866
+ if (bare === null) return null;
100867
+ return linearFrom(bare[1], bare[2], bare[3], void 0, void 0);
100868
+ }
100869
+ function singleFrom(source) {
100870
+ if (source.kind === "from") return {
100871
+ cap: source.cap,
100872
+ fieldPath: source.fieldPath,
100873
+ addonId: source.source.addonId,
100874
+ stableId: source.source.stableId
100875
+ };
100876
+ if (source.kind !== "expression" || Object.keys(source.bindings).length !== 1) return null;
100877
+ const bound = source.bindings["x"];
100878
+ if (bound === void 0 || bound.kind !== "from") return null;
100879
+ return {
100880
+ cap: bound.cap,
100881
+ fieldPath: bound.fieldPath,
100882
+ addonId: bound.source.addonId,
100883
+ stableId: bound.source.stableId
100884
+ };
100885
+ }
100886
+ function token(value, pattern) {
100887
+ if (!Number.isFinite(value)) return null;
100888
+ const text = Object.is(value, -0) ? "0" : String(value);
100889
+ return pattern.test(text) ? text : null;
100890
+ }
100891
+ function linearFrom(inner, scale, offset, clampMin, clampMax) {
100892
+ if (inner !== "x" && inner !== "number(x)") return null;
100893
+ if (scale === void 0 || offset === void 0) return null;
100894
+ const parsedScale = Number(scale);
100895
+ const parsedOffset = Number(offset);
100896
+ if (!Number.isFinite(parsedScale) || !Number.isFinite(parsedOffset)) return null;
100897
+ if (clampMin === void 0 || clampMax === void 0) return {
100898
+ inner,
100899
+ scale: parsedScale,
100900
+ offset: parsedOffset
100901
+ };
100902
+ const parsedMin = Number(clampMin);
100903
+ const parsedMax = Number(clampMax);
100904
+ if (!Number.isFinite(parsedMin) || !Number.isFinite(parsedMax)) return null;
100905
+ return {
100906
+ inner,
100907
+ scale: parsedScale,
100908
+ offset: parsedOffset,
100909
+ clampMin: parsedMin,
100910
+ clampMax: parsedMax
100911
+ };
100912
+ }
100913
+ //#endregion
100914
+ //#region src/composition/customize/scalar-compile.ts
100915
+ var catalog$4 = CAP_CUSTOMIZE_CATALOG;
100916
+ function compileScalarOverride(input) {
100917
+ const target = catalogTarget$4(input.draft.cap, input.draft.targetId);
100918
+ if (target === null || target.cardinality !== "scalar" || target.path === void 0) return fail$2("target");
100919
+ if (input.draft.transform.kind === "enum-map") return fail$2("enum");
100920
+ const source = sourceSpec$1(target, input.sourceValueKind, input.draft.source.cap);
100921
+ if (source === null) return fail$2("source-kind");
100922
+ if (source.requiredUnit !== void 0 && input.sourceUnit !== source.requiredUnit) return fail$2("unit");
100923
+ const allowed = input.draft.transform.kind === "number" ? "identity" : input.draft.transform.kind;
100924
+ if (!source.transformKinds.includes(allowed)) return fail$2("transform");
100925
+ const value = compileValue$1(input);
100926
+ if (!value.ok) return value;
100927
+ const fields = compileCompanions$1(input, target, value.value);
100928
+ if (!fields.ok) return fields;
100929
+ return {
100930
+ ok: true,
100931
+ value: {
100932
+ kind: "fields",
100933
+ cap: input.draft.cap,
100934
+ fields: fields.value
100935
+ }
100936
+ };
100937
+ }
100938
+ function fail$2(reason) {
100939
+ return {
100940
+ ok: false,
100941
+ reason
100942
+ };
100943
+ }
100944
+ function catalogTarget$4(cap, targetId) {
100945
+ const entry = catalog$4[cap];
100946
+ if (entry === void 0) return null;
100947
+ return entry.targets.find((target) => target.id === targetId) ?? null;
100948
+ }
100949
+ function sourceSpec$1(target, valueKind, sourceCap) {
100950
+ if (valueKind === "boolean" && sourceCap === "switch") return target.sources.find((source) => source.kind === "switch") ?? null;
100951
+ if (valueKind === "boolean") return target.sources.find((source) => source.kind === "binary") ?? fieldSource(target, "boolean");
100952
+ if (valueKind === "number") return target.sources.find((source) => source.kind === "numeric") ?? fieldSource(target, "number");
100953
+ return fieldSource(target, "string");
100954
+ }
100955
+ function fieldSource(target, valueKind) {
100956
+ return target.sources.find((source) => source.kind === "field" && (source.valueKinds ?? []).includes(valueKind)) ?? null;
100957
+ }
100958
+ function compileValue$1(input) {
100959
+ const read = fromRead(refOf$1(input.draft), input.draft.source.cap, input.draft.source.fieldPath);
100960
+ const transform = input.draft.transform;
100961
+ if (transform.kind === "identity" || transform.kind === "number") return {
100962
+ ok: true,
100963
+ value: identityValue(read, input.sourceValueKind)
100964
+ };
100965
+ if (transform.kind === "invert") {
100966
+ if (input.sourceValueKind !== "boolean") return fail$2("source-kind");
100967
+ return {
100968
+ ok: true,
100969
+ value: expression("!x", { x: read })
100970
+ };
100971
+ }
100972
+ if (transform.kind === "threshold") return thresholdValue(transform, read);
100973
+ if (transform.kind === "linear") return linearValue$1(transform, read, input.sourceValueKind);
100974
+ return fail$2("transform");
100975
+ }
100976
+ function identityValue(read, valueKind) {
100977
+ if (valueKind === "string") return expression("number(x)", { x: read });
100978
+ return read;
100979
+ }
100980
+ function thresholdValue(transform, read) {
100981
+ const threshold = unsignedToken(transform.threshold);
100982
+ if (threshold === null) return fail$2("threshold");
100983
+ const start = unsignedToken(transform.startDwellMs);
100984
+ const stop = unsignedToken(transform.stopDwellMs);
100985
+ if (start === null || stop === null) return fail$2("dwell");
100986
+ return {
100987
+ ok: true,
100988
+ value: expression(dwellExpr(transform.comparison, threshold, start, stop), { x: read })
100989
+ };
100990
+ }
100991
+ function linearValue$1(transform, read, valueKind) {
100992
+ const scale = signedToken(transform.scale);
100993
+ const offset = signedToken(transform.offset);
100994
+ if (scale === null || offset === null) return fail$2("scale");
100995
+ const clamps = clampTokens$1(transform.clampMin, transform.clampMax);
100996
+ if (!clamps.ok) return clamps;
100997
+ return {
100998
+ ok: true,
100999
+ value: expression(linearExpr(valueKind === "string" ? "number(x)" : "x", scale, offset, clamps.value.min, clamps.value.max), { x: read })
101000
+ };
101001
+ }
101002
+ function clampTokens$1(clampMin, clampMax) {
101003
+ if (clampMin === void 0 && clampMax === void 0) return {
101004
+ ok: true,
101005
+ value: {
101006
+ min: null,
101007
+ max: null
101008
+ }
101009
+ };
101010
+ if (clampMin === void 0 || clampMax === void 0) return fail$2("clamp");
101011
+ const min = signedToken(clampMin);
101012
+ const max = signedToken(clampMax);
101013
+ if (min === null || max === null || clampMin > clampMax) return fail$2("clamp");
101014
+ return {
101015
+ ok: true,
101016
+ value: {
101017
+ min,
101018
+ max
101019
+ }
101020
+ };
101021
+ }
101022
+ function compileCompanions$1(input, target, value) {
101023
+ if (target.path === void 0) return fail$2("target");
101024
+ const path = target.path;
101025
+ return (target.companions ?? []).filter((companion) => companionIncluded$1(companion, input.apply)).reduce((acc, companion) => {
101026
+ if (!acc.ok) return acc;
101027
+ const built = companionField(input, path, companion);
101028
+ if (!built.ok) return {
101029
+ ok: false,
101030
+ reason: built.reason
101031
+ };
101032
+ return {
101033
+ ok: true,
101034
+ value: {
101035
+ ...acc.value,
101036
+ [companion.path]: built.value
101037
+ }
101038
+ };
101039
+ }, {
101040
+ ok: true,
101041
+ value: { [path]: value }
101042
+ });
101043
+ }
101044
+ function companionIncluded$1(companion, apply) {
101045
+ if (companion.kind === "transition-time") return true;
101046
+ return companion.when === "always" || apply === "add";
101047
+ }
101048
+ function companionField(input, path, companion) {
101049
+ if (companion.kind === "constant") {
101050
+ const expr = constantExpr(companion.value);
101051
+ if (expr === null) return fail$2("scale");
101052
+ return {
101053
+ ok: true,
101054
+ value: literal(expr)
101055
+ };
101056
+ }
101057
+ if (companion.kind === "clock") return {
101058
+ ok: true,
101059
+ value: literal("now")
101060
+ };
101061
+ return transitionField(input, path, companion.sourceChangedAt);
101062
+ }
101063
+ function transitionField(input, path, sourceChangedAt) {
101064
+ if (sourceChangedAt === "prefer" && input.sourceValueKind === "boolean" && input.changedAtField !== null && isIdentifier(input.changedAtField)) return {
101065
+ ok: true,
101066
+ value: fromRead(refOf$1(input.draft), input.draft.source.cap, input.changedAtField)
101067
+ };
101068
+ if (!isIdentifier(path)) return fail$2("transform");
101069
+ const bindings = { [path]: fromRead(input.device, input.draft.cap, path) };
101070
+ return {
101071
+ ok: true,
101072
+ value: expression(`latchedAt(${path})`, bindings)
101073
+ };
101074
+ }
101075
+ function refOf$1(draft) {
101076
+ return {
101077
+ addonId: draft.source.addonId,
101078
+ stableId: draft.source.stableId
101079
+ };
101080
+ }
101081
+ //#endregion
101082
+ //#region src/composition/customize/normalize.ts
101083
+ function sortKeys(value) {
101084
+ if (Array.isArray(value)) return value.map(sortKeys);
101085
+ if (typeof value !== "object" || value === null) return value;
101086
+ return Object.fromEntries(Object.entries(value).toSorted(([a], [b]) => a.localeCompare(b)).map(([key, inner]) => [key, sortKeys(inner)]));
101087
+ }
101088
+ /** Key order is not part of the stored contract. Array order is. */
101089
+ function normalizeStored(stored) {
101090
+ return sortKeys(stored);
101091
+ }
101092
+ function sameStored(a, b) {
101093
+ return JSON.stringify(normalizeStored(a)) === JSON.stringify(normalizeStored(b));
101094
+ }
101095
+ //#endregion
101096
+ //#region src/composition/customize/scalar-decode.ts
101097
+ var catalog$3 = CAP_CUSTOMIZE_CATALOG;
101098
+ function decodeScalarOverride(input) {
101099
+ const target = catalogTarget$3(input.cap, input.targetId);
101100
+ if (target === null || target.cardinality !== "scalar" || target.path === void 0) return null;
101101
+ if (input.feature.cap !== input.cap || input.feature.kind !== "fields") return null;
101102
+ const outputKind = scalarOutputKind(target.valueKind);
101103
+ if (outputKind === null) return null;
101104
+ const value = input.feature.fields[target.path];
101105
+ const read = readValue(value, outputKind, input.cap, input.targetId);
101106
+ if (read === null) return null;
101107
+ const apply = inferApply$1(target, input.feature.fields);
101108
+ if (apply === null) return null;
101109
+ const changedAtField = inferChangedAt(target, input.feature.fields, read);
101110
+ const sourceUnit = unitFor(target, read.sourceValueKind, read.draft.source.cap);
101111
+ const decoded = {
101112
+ ...read,
101113
+ apply,
101114
+ changedAtField,
101115
+ sourceUnit
101116
+ };
101117
+ return reproduces$1(decoded, input.device, input.feature) ? decoded : null;
101118
+ }
101119
+ function catalogTarget$3(cap, targetId) {
101120
+ const entry = catalog$3[cap];
101121
+ if (entry === void 0) return null;
101122
+ return entry.targets.find((target) => target.id === targetId) ?? null;
101123
+ }
101124
+ function scalarOutputKind(valueKind) {
101125
+ if (valueKind === "boolean" || valueKind === "number" || valueKind === "string") return valueKind;
101126
+ return null;
101127
+ }
101128
+ function readValue(field, outputKind, cap, targetId) {
101129
+ if (field === void 0) return null;
101130
+ if (field.kind === "from") return drafted(field, { kind: "identity" }, outputKind, cap, targetId);
101131
+ if (field.kind !== "expression") return null;
101132
+ if (field.expr === "number(x)" && outputKind === "number") return drafted(field, { kind: "identity" }, "string", cap, targetId);
101133
+ if (field.expr === "!x" && outputKind === "boolean") return drafted(field, { kind: "invert" }, "boolean", cap, targetId);
101134
+ const dwell = parseDwell(field.expr);
101135
+ if (dwell !== null) return drafted(field, {
101136
+ kind: "threshold",
101137
+ comparison: dwell.comparison,
101138
+ threshold: dwell.threshold,
101139
+ startDwellMs: dwell.startDwellMs,
101140
+ stopDwellMs: dwell.stopDwellMs
101141
+ }, "number", cap, targetId);
101142
+ const linear = parseLinear(field.expr);
101143
+ if (linear === null || outputKind !== "number") return null;
101144
+ return drafted(field, {
101145
+ kind: "linear",
101146
+ scale: linear.scale,
101147
+ offset: linear.offset,
101148
+ ...linear.clampMin === void 0 || linear.clampMax === void 0 ? {} : {
101149
+ clampMin: linear.clampMin,
101150
+ clampMax: linear.clampMax
101151
+ }
101152
+ }, linear.inner === "number(x)" ? "string" : "number", cap, targetId);
101153
+ }
101154
+ function drafted(field, transform, sourceValueKind, cap, targetId) {
101155
+ const bound = singleFrom(field);
101156
+ if (bound === null) return null;
101157
+ return {
101158
+ sourceValueKind,
101159
+ draft: {
101160
+ kind: "scalar",
101161
+ cap,
101162
+ targetId,
101163
+ source: {
101164
+ addonId: bound.addonId,
101165
+ stableId: bound.stableId,
101166
+ cap: bound.cap,
101167
+ fieldPath: bound.fieldPath
101168
+ },
101169
+ transform
101170
+ }
101171
+ };
101172
+ }
101173
+ function inferApply$1(target, fields) {
101174
+ const addPaths = (target.companions ?? []).flatMap((companion) => companion.kind !== "transition-time" && companion.when === "add" ? [companion.path] : []);
101175
+ if (addPaths.length === 0) return "replace";
101176
+ const present = addPaths.filter((path) => fields[path] !== void 0);
101177
+ if (present.length === addPaths.length) return "add";
101178
+ if (present.length === 0) return "replace";
101179
+ return null;
101180
+ }
101181
+ function inferChangedAt(target, fields, read) {
101182
+ if (read.sourceValueKind !== "boolean") return null;
101183
+ const transition = (target.companions ?? []).find((companion) => companion.kind === "transition-time");
101184
+ if (transition === void 0 || transition.sourceChangedAt !== "prefer") return null;
101185
+ const since = fields[transition.path];
101186
+ if (since?.kind !== "from") return null;
101187
+ if (since.cap !== read.draft.source.cap) return null;
101188
+ if (since.source.addonId !== read.draft.source.addonId || since.source.stableId !== read.draft.source.stableId) return null;
101189
+ return since.fieldPath;
101190
+ }
101191
+ function unitFor(target, valueKind, sourceCap) {
101192
+ if (valueKind === "boolean" && sourceCap === "switch") return null;
101193
+ if (valueKind === "number") return target.sources.find((source) => source.kind === "numeric")?.requiredUnit ?? null;
101194
+ return null;
101195
+ }
101196
+ function reproduces$1(decoded, device, stored) {
101197
+ const compiled = compileScalarOverride({
101198
+ draft: decoded.draft,
101199
+ device,
101200
+ apply: decoded.apply,
101201
+ sourceValueKind: decoded.sourceValueKind,
101202
+ changedAtField: decoded.changedAtField,
101203
+ sourceUnit: decoded.sourceUnit
101204
+ });
101205
+ if (!compiled.ok) return false;
101206
+ return sameFeature$2(compiled.value, stored);
101207
+ }
101208
+ function sameFeature$2(compiled, stored) {
101209
+ return sameStored(wrap$1(withoutEnabled(compiled)), wrap$1(withoutEnabled(stored)));
101210
+ }
101211
+ function withoutEnabled(feature) {
101212
+ const { enabled: _enabled, ...rest } = feature;
101213
+ return rest;
101214
+ }
101215
+ function wrap$1(feature) {
101216
+ return {
101217
+ family: "composition",
101218
+ target: {
101219
+ addonId: "t",
101220
+ stableId: "t"
101221
+ },
101222
+ feature
101223
+ };
101224
+ }
101225
+ //#endregion
101226
+ //#region src/composition/customize/scalar-status.ts
101227
+ function projectScalarAssignment(input) {
101228
+ if (input.stored.kind === "pending") return unanswered$1(input.targetId, "pending", null);
101229
+ if (input.stored.kind === "unknown") return unanswered$1(input.targetId, "unknown", input.stored.reason ?? "unknown");
101230
+ if (input.stored.value === null) return native$2(input.targetId);
101231
+ const decoded = decodeScalarOverride({
101232
+ feature: input.stored.value,
101233
+ device: input.device,
101234
+ cap: input.cap,
101235
+ targetId: input.targetId
101236
+ });
101237
+ if (decoded === null) return {
101238
+ text: "unknown",
101239
+ status: status$1(input.targetId, true, "assigned", "unavailable", "not-canonical")
101240
+ };
101241
+ return projectDecoded$1(input, decoded.apply, sourceLabel(decoded.draft.source.cap, decoded.draft.source.fieldPath));
101242
+ }
101243
+ function projectDecoded$1(input, apply, label) {
101244
+ if (input.sourcePresence === "pending") return {
101245
+ text: "pending",
101246
+ status: status$1(input.targetId, true, "assigned", "stale", null)
101247
+ };
101248
+ if (input.sourcePresence === "unknown") return {
101249
+ text: "unknown",
101250
+ status: status$1(input.targetId, true, "assigned", "stale", input.sourceUnknownReason ?? "unknown")
101251
+ };
101252
+ if (input.sourcePresence === "absent" && apply === "replace") return {
101253
+ text: "Native · source missing",
101254
+ status: status$1(input.targetId, true, "native", "released", "source-missing")
101255
+ };
101256
+ if (input.sourcePresence === "absent") return {
101257
+ text: `Assigned · ${label}`,
101258
+ status: status$1(input.targetId, true, "assigned", "unavailable", "source-missing")
101259
+ };
101260
+ return {
101261
+ text: `Assigned · ${label}`,
101262
+ status: status$1(input.targetId, true, "assigned", "active", null)
101263
+ };
101264
+ }
101265
+ function native$2(targetId) {
101266
+ return {
101267
+ text: "Native",
101268
+ status: status$1(targetId, false, "native", "active", null)
101269
+ };
101270
+ }
101271
+ function unanswered$1(targetId, text, reason) {
101272
+ return {
101273
+ text,
101274
+ status: status$1(targetId, false, "native", text === "pending" ? "unavailable" : "stale", reason)
101275
+ };
101276
+ }
101277
+ function sourceLabel(cap, fieldPath) {
101278
+ return `${cap}.${fieldPath}`;
101279
+ }
101280
+ function status$1(targetId, configured, source, state, reason) {
101281
+ return {
101282
+ targetId,
101283
+ configured,
101284
+ source,
101285
+ state,
101286
+ reason
101287
+ };
101288
+ }
101289
+ //#endregion
101290
+ //#region src/composition/customize/event-compile.ts
101291
+ var catalog$2 = CAP_CUSTOMIZE_CATALOG;
101292
+ function compilePulseOverride(input) {
101293
+ const target = catalogTarget$2(input.draft.cap, input.draft.targetId);
101294
+ if (target === null || target.shape !== "pulse") return fail$1("target");
101295
+ const timestampPath = target.timestampPath;
101296
+ const counterPath = target.counterPath;
101297
+ if (timestampPath === void 0 || counterPath === void 0 || !isIdentifier(timestampPath) || !isIdentifier(counterPath)) return fail$1("path");
101298
+ if (!(target.edges ?? []).includes("rising")) return fail$1("edge");
101299
+ const pairs = pairSources(input);
101300
+ if (!pairs.ok) return pairs;
101301
+ if (pairs.value.length === 0) return fail$1("sources");
101302
+ const debounce = unsignedToken(input.draft.debounceMs);
101303
+ if (debounce === null) return fail$1("debounce");
101304
+ const ordered = pairs.value.toSorted((a, b) => pairKey(a).localeCompare(pairKey(b)));
101305
+ return {
101306
+ ok: true,
101307
+ value: {
101308
+ kind: "fields",
101309
+ cap: input.draft.cap,
101310
+ enabled: input.draft.enabled,
101311
+ fields: {
101312
+ [timestampPath]: expression(pulseExpr(ordered.length, debounce), pulseBindings(ordered)),
101313
+ [counterPath]: expression(`count(${timestampPath})`, { [timestampPath]: fromRead(input.device, input.draft.cap, timestampPath) })
101314
+ }
101315
+ }
101316
+ };
101317
+ }
101318
+ function compileSpanOverride(input) {
101319
+ const target = catalogTarget$2(input.draft.cap, input.draft.targetId);
101320
+ if (target === null || target.shape !== "span") return fail$1("target");
101321
+ if (target.applyAuthority?.kind !== "camera-sensors") return fail$1("authority");
101322
+ if (input.draft.timeoutMs < 0 || !Number.isFinite(input.draft.timeoutMs)) return fail$1("timeout");
101323
+ if (target.cooldownMs === void 0 && input.draft.cooldownMs !== void 0) return fail$1("cooldown");
101324
+ if (input.draft.cooldownMs !== void 0 && input.draft.cooldownMs < 0) return fail$1("cooldown");
101325
+ const sensors = sensorEntries(input.draft.sources, input.device, target.sourceModes);
101326
+ if (!sensors.ok) return sensors;
101327
+ if (sensors.value.length === 0) return {
101328
+ ok: true,
101329
+ value: {
101330
+ config: null,
101331
+ timeoutMs: input.draft.timeoutMs,
101332
+ cooldownMs: input.draft.cooldownMs
101333
+ }
101334
+ };
101335
+ const parsed = CameraSensorsConfigSchema.safeParse({ sensors: sensors.value });
101336
+ if (!parsed.success) {
101337
+ const issue = parsed.error.issues[0];
101338
+ return fail$1(issue === void 0 ? "cameraSensors" : issue.message);
101339
+ }
101340
+ return {
101341
+ ok: true,
101342
+ value: {
101343
+ config: parsed.data,
101344
+ timeoutMs: input.draft.timeoutMs,
101345
+ cooldownMs: input.draft.cooldownMs
101346
+ }
101347
+ };
101348
+ }
101349
+ function pairSources(input) {
101350
+ if (input.changedAtFields.length !== input.draft.sources.length) return fail$1("changed-at");
101351
+ const pairs = input.draft.sources.map((source, index) => {
101352
+ return {
101353
+ source,
101354
+ changedAtField: input.changedAtFields[index] ?? ""
101355
+ };
101356
+ });
101357
+ if (pairs.some((pair) => pair.changedAtField.length === 0 || pair.source.fieldPath.length === 0)) return fail$1("changed-at");
101358
+ return {
101359
+ ok: true,
101360
+ value: pairs
101361
+ };
101362
+ }
101363
+ function pairKey(pair) {
101364
+ return `${pair.source.addonId}/${pair.source.stableId}#${pair.source.cap}#${pair.source.fieldPath}`;
101365
+ }
101366
+ function pulseExpr(count, debounce) {
101367
+ const roses = [];
101368
+ for (let index = 0; index < count; index += 1) roses.push(`rose(active${index}, changed${index}, ${debounce})`);
101369
+ return `latest(${roses.join(", ")})`;
101370
+ }
101371
+ function pulseBindings(pairs) {
101372
+ const bindings = {};
101373
+ pairs.forEach((pair, index) => {
101374
+ const ref = {
101375
+ addonId: pair.source.addonId,
101376
+ stableId: pair.source.stableId
101377
+ };
101378
+ bindings[`active${index}`] = fromRead(ref, pair.source.cap, pair.source.fieldPath);
101379
+ bindings[`changed${index}`] = fromRead(ref, pair.source.cap, pair.changedAtField);
101380
+ });
101381
+ return bindings;
101382
+ }
101383
+ function sensorEntries(sources, device, modes) {
101384
+ const entries = [];
101385
+ for (const source of sources) {
101386
+ if (source.addonId === device.addonId && source.stableId === device.stableId) return fail$1("self");
101387
+ const mode = source.mode ?? "in-addition";
101388
+ if (modes !== void 0 && !modes.includes(mode)) return fail$1("mode");
101389
+ if (modes === void 0 && source.mode !== void 0 && source.mode !== "in-addition") return fail$1("mode");
101390
+ entries.push({
101391
+ addonId: source.addonId,
101392
+ stableId: source.stableId,
101393
+ mode
101394
+ });
101395
+ }
101396
+ return {
101397
+ ok: true,
101398
+ value: entries
101399
+ };
101400
+ }
101401
+ function catalogTarget$2(cap, targetId) {
101402
+ const entry = catalog$2[cap];
101403
+ if (entry === void 0) return null;
101404
+ return entry.targets.find((target) => target.id === targetId) ?? null;
101405
+ }
101406
+ function fail$1(reason) {
101407
+ return {
101408
+ ok: false,
101409
+ reason
101410
+ };
101411
+ }
101412
+ //#endregion
101413
+ //#region src/composition/customize/event-decode.ts
101414
+ var ROSE_SOURCE = String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
101415
+ function decodePulseOverride(input) {
101416
+ if (input.feature.cap !== input.cap || input.feature.kind !== "fields") return null;
101417
+ if (input.feature.enabled === void 0) return null;
101418
+ const timestamp = input.feature.fields[input.timestampPath];
101419
+ const counter = input.feature.fields[input.counterPath];
101420
+ if (timestamp === void 0 || counter === void 0) return null;
101421
+ if (Object.keys(input.feature.fields).length !== 2) return null;
101422
+ const edges = readEdges(timestamp);
101423
+ if (edges === null) return null;
101424
+ if (readCount(counter, input) === null) return null;
101425
+ const draft = {
101426
+ kind: "pulse",
101427
+ cap: input.cap,
101428
+ targetId: input.targetId,
101429
+ enabled: input.feature.enabled,
101430
+ debounceMs: edges.debounceMs,
101431
+ sources: edges.sources
101432
+ };
101433
+ const decoded = {
101434
+ draft,
101435
+ changedAtFields: edges.changedAtFields
101436
+ };
101437
+ const compiled = compilePulseOverride({
101438
+ draft,
101439
+ device: input.device,
101440
+ changedAtFields: edges.changedAtFields
101441
+ });
101442
+ if (!compiled.ok) return null;
101443
+ return sameFeature$1(compiled.value, input.feature) ? decoded : null;
101444
+ }
101445
+ function readEdges(field) {
101446
+ if (field.kind !== "expression" || !field.expr.startsWith("latest(") || !field.expr.endsWith(")")) return null;
101447
+ const inner = field.expr.slice(7, -1);
101448
+ const found = [...inner.matchAll(new RegExp(ROSE_SOURCE, "g"))];
101449
+ if (found.length === 0 || found.map((match) => match[0]).join(", ") !== inner) return null;
101450
+ if (Object.keys(field.bindings).length !== found.length * 2) return null;
101451
+ const rows = found.map((match, index) => readRose(match, index, field.bindings));
101452
+ if (rows.some((row) => row === null)) return null;
101453
+ const edges = rows.filter((row) => row !== null);
101454
+ const debounceMs = edges[0]?.debounceMs;
101455
+ if (debounceMs === void 0 || edges.some((row) => row.debounceMs !== debounceMs)) return null;
101456
+ return {
101457
+ debounceMs,
101458
+ sources: edges.map((row) => row.source),
101459
+ changedAtFields: edges.map((row) => row.changedAtField)
101460
+ };
101461
+ }
101462
+ function readRose(match, index, bindings) {
101463
+ const activeIndex = Number(match[1]);
101464
+ const changedIndex = Number(match[2]);
101465
+ const debounceMs = Number(match[3]);
101466
+ if (activeIndex !== index || changedIndex !== index || !Number.isFinite(debounceMs)) return null;
101467
+ const active = fromBinding(bindings[`active${index}`]);
101468
+ const changed = fromBinding(bindings[`changed${index}`]);
101469
+ if (active === null || changed === null) return null;
101470
+ if (active.cap !== changed.cap) return null;
101471
+ if (active.source.addonId !== changed.source.addonId) return null;
101472
+ if (active.source.stableId !== changed.source.stableId) return null;
101473
+ return {
101474
+ debounceMs,
101475
+ changedAtField: changed.fieldPath,
101476
+ source: {
101477
+ addonId: active.source.addonId,
101478
+ stableId: active.source.stableId,
101479
+ cap: active.cap,
101480
+ fieldPath: active.fieldPath
101481
+ }
101482
+ };
101483
+ }
101484
+ function fromBinding(value) {
101485
+ if (value === void 0 || value.kind !== "from") return null;
101486
+ return value;
101487
+ }
101488
+ function readCount(field, input) {
101489
+ if (field.kind !== "expression" || field.expr !== `count(${input.timestampPath})`) return null;
101490
+ const binding = fromBinding(field.bindings[input.timestampPath]);
101491
+ if (binding === null) return null;
101492
+ if (Object.keys(field.bindings).length !== 1) return null;
101493
+ if (binding.cap !== input.cap || binding.fieldPath !== input.timestampPath) return null;
101494
+ if (binding.source.addonId !== input.device.addonId) return null;
101495
+ if (binding.source.stableId !== input.device.stableId) return null;
101496
+ return true;
101497
+ }
101498
+ function sameFeature$1(left, right) {
101499
+ return JSON.stringify(left) === JSON.stringify(right);
101500
+ }
101501
+ //#endregion
101502
+ //#region src/composition/customize/event-eval.ts
101503
+ var INITIAL_PULSE = {
101504
+ priorActive: void 0,
101505
+ lastPressedAt: null,
101506
+ count: 0,
101507
+ acceptedAt: null
101508
+ };
101509
+ var INITIAL_SPAN = {
101510
+ open: false,
101511
+ startedAt: null,
101512
+ endedAt: null,
101513
+ quietUntil: null,
101514
+ priorActive: void 0
101515
+ };
101516
+ function stepPulse(state, sample, debounceMs) {
101517
+ if (sample.kind === "unread" || debounceMs < 0) return state;
101518
+ if (state.priorActive === void 0) return {
101519
+ ...state,
101520
+ priorActive: sample.active
101521
+ };
101522
+ if (!sample.active) return {
101523
+ ...state,
101524
+ priorActive: false
101525
+ };
101526
+ if (state.priorActive) return state;
101527
+ const at = finite(sample.changedAt);
101528
+ if (at === null) return {
101529
+ ...state,
101530
+ priorActive: true
101531
+ };
101532
+ if (state.acceptedAt !== null && at - state.acceptedAt < debounceMs) return {
101533
+ ...state,
101534
+ priorActive: true
101535
+ };
101536
+ return {
101537
+ priorActive: true,
101538
+ lastPressedAt: at,
101539
+ count: state.count + 1,
101540
+ acceptedAt: at
101541
+ };
101542
+ }
101543
+ function stepSpan(state, sample, timing) {
101544
+ const timed = expire(state, timing);
101545
+ if (sample.kind === "unread" || timing.timeoutMs < 0 || timing.cooldownMs < 0) return timed;
101546
+ if (timed.priorActive === void 0) return {
101547
+ ...timed,
101548
+ priorActive: sample.active
101549
+ };
101550
+ if (timed.open && timed.priorActive && !sample.active) return finish(timed, finite(sample.changedAt) ?? timing.nowMs, timing.cooldownMs, false);
101551
+ if (!sample.active) return {
101552
+ ...timed,
101553
+ priorActive: false
101554
+ };
101555
+ if (timed.priorActive || timed.open) return {
101556
+ ...timed,
101557
+ priorActive: true
101558
+ };
101559
+ const at = finite(sample.changedAt) ?? timing.nowMs;
101560
+ if (timed.quietUntil !== null && at < timed.quietUntil) return {
101561
+ ...timed,
101562
+ priorActive: true
101563
+ };
101564
+ return {
101565
+ open: true,
101566
+ startedAt: at,
101567
+ endedAt: null,
101568
+ quietUntil: null,
101569
+ priorActive: true
101570
+ };
101571
+ }
101572
+ function expire(state, timing) {
101573
+ if (!state.open || state.startedAt === null) return state;
101574
+ const deadline = state.startedAt + timing.timeoutMs;
101575
+ if (timing.nowMs < deadline) return state;
101576
+ return finish(state, deadline, timing.cooldownMs, state.priorActive === true);
101577
+ }
101578
+ function finish(state, endedAt, cooldownMs, priorActive) {
101579
+ return {
101580
+ open: false,
101581
+ startedAt: state.startedAt,
101582
+ endedAt,
101583
+ quietUntil: cooldownMs > 0 ? endedAt + cooldownMs : null,
101584
+ priorActive
101585
+ };
101586
+ }
101587
+ function finite(value) {
101588
+ return value !== null && Number.isFinite(value) ? value : null;
101589
+ }
101590
+ //#endregion
101591
+ //#region src/composition/customize/event-status.ts
101592
+ function projectPulseAssignment(input) {
101593
+ if (input.stored.kind === "pending") return held(input.targetId, "pending", null);
101594
+ if (input.stored.kind === "unknown") return held(input.targetId, "unknown", input.stored.reason ?? "unknown");
101595
+ if (input.stored.value === null) return native$1(input.targetId);
101596
+ const decoded = decodePulseOverride({
101597
+ feature: input.stored.value,
101598
+ device: input.device,
101599
+ cap: input.cap,
101600
+ targetId: input.targetId,
101601
+ timestampPath: input.timestampPath,
101602
+ counterPath: input.counterPath
101603
+ });
101604
+ if (decoded === null) return {
101605
+ text: "unknown",
101606
+ status: row(input.targetId, true, "assigned", "unavailable", "not-canonical")
101607
+ };
101608
+ if (input.sourcePresence === "pending") return {
101609
+ text: "pending",
101610
+ status: row(input.targetId, true, "assigned", "stale", null)
101611
+ };
101612
+ if (input.sourcePresence === "unknown") return {
101613
+ text: "unknown",
101614
+ status: row(input.targetId, true, "assigned", "stale", input.sourceUnknownReason ?? "unknown")
101615
+ };
101616
+ if (input.sourcePresence === "absent" && input.apply === "replace") return {
101617
+ text: "Native · source missing",
101618
+ status: row(input.targetId, true, "native", "released", "source-missing")
101619
+ };
101620
+ if (input.sourcePresence === "absent") return {
101621
+ text: "Assigned · source missing",
101622
+ status: row(input.targetId, true, "assigned", "unavailable", "source-missing")
101623
+ };
101624
+ const source = decoded.draft.sources[0];
101625
+ return {
101626
+ text: `Assigned · ${source === void 0 ? "assigned" : `${source.cap}.${source.fieldPath}`}`,
101627
+ status: row(input.targetId, true, "assigned", "active", null)
101628
+ };
101629
+ }
101630
+ function projectSpanAssignment(targetId, stored) {
101631
+ if (stored.kind === "pending") return {
101632
+ text: "pending",
101633
+ writable: false,
101634
+ rows: [],
101635
+ status: row(targetId, false, "native", "unavailable", null)
101636
+ };
101637
+ if (stored.kind === "unknown") return {
101638
+ text: "unknown",
101639
+ writable: false,
101640
+ rows: [],
101641
+ status: row(targetId, false, "native", "stale", stored.reason ?? "unknown")
101642
+ };
101643
+ if (stored.value.state === "unreadable") return {
101644
+ text: "unreadable",
101645
+ writable: false,
101646
+ rows: [],
101647
+ status: row(targetId, false, "assigned", "unavailable", stored.value.reason)
101648
+ };
101649
+ if (stored.value.state === "not-configured") return {
101650
+ text: "Native",
101651
+ writable: true,
101652
+ rows: [],
101653
+ status: row(targetId, false, "native", "active", null)
101654
+ };
101655
+ const rows = stored.value.sensors.map(sensorRow);
101656
+ const reason = spanReason(stored.value);
101657
+ return {
101658
+ text: rows.length === 0 ? "Native" : "Assigned",
101659
+ writable: true,
101660
+ rows,
101661
+ status: row(targetId, rows.length > 0, "assigned", "active", reason)
101662
+ };
101663
+ }
101664
+ function spanReason(status) {
101665
+ if (status.notForwarded !== void 0) return status.notForwarded;
101666
+ if (status.notEnforced !== void 0) return status.notEnforced;
101667
+ return status.sensors.map(attachmentReason).find((reason) => reason !== null) ?? null;
101668
+ }
101669
+ function sensorRow(sensor) {
101670
+ return {
101671
+ key: `${sensor.addonId}/${sensor.stableId}`,
101672
+ addonId: sensor.addonId,
101673
+ stableId: sensor.stableId,
101674
+ name: sensor.state === "missing" || sensor.state === "unreadable" ? sensor.stableId : sensor.name,
101675
+ mode: sensor.mode,
101676
+ state: sensor.state,
101677
+ reason: attachmentReason(sensor)
101678
+ };
101679
+ }
101680
+ function attachmentReason(sensor) {
101681
+ switch (sensor.state) {
101682
+ case "ready": return null;
101683
+ case "offline":
101684
+ case "missing":
101685
+ case "unsupported":
101686
+ case "unreadable": return sensor.reason;
101687
+ }
101688
+ }
101689
+ function native$1(targetId) {
101690
+ return {
101691
+ text: "Native",
101692
+ status: row(targetId, false, "native", "active", null)
101693
+ };
101694
+ }
101695
+ function held(targetId, text, reason) {
101696
+ return {
101697
+ text,
101698
+ status: row(targetId, false, "native", text === "pending" ? "unavailable" : "stale", reason)
101699
+ };
101700
+ }
101701
+ function row(targetId, configured, source, state, reason) {
101702
+ return {
101703
+ targetId,
101704
+ configured,
101705
+ source,
101706
+ state,
101707
+ reason
101708
+ };
101709
+ }
101710
+ //#endregion
101711
+ //#region src/composition/customize/keyed-array-expr.ts
101712
+ var STEP = /^x == ("(?:\\.|[^"\\])*") \? ("(?:\\.|[^"\\])*"|null) : ([\s\S]+)$/;
101713
+ function enumMapExpr(mapping) {
101714
+ const keys = Object.keys(mapping).toSorted();
101715
+ if (keys.length === 0) return null;
101716
+ return keys.reduceRight((rest, key) => {
101717
+ if (rest === null) return null;
101718
+ const value = mapping[key];
101719
+ if (value === void 0) return null;
101720
+ const rhs = value === null ? "null" : JSON.stringify(value);
101721
+ return `x == ${JSON.stringify(key)} ? ${rhs} : ${rest}`;
101722
+ }, "null");
101723
+ }
101724
+ function parseEnumMap(expr) {
101725
+ const mapping = {};
101726
+ let rest = expr;
101727
+ while (rest !== "null") {
101728
+ const match = STEP.exec(rest);
101729
+ if (match === null || match[1] === void 0 || match[2] === void 0 || match[3] === void 0) return null;
101730
+ const key = jsonString(match[1]);
101731
+ const value = match[2] === "null" ? null : jsonString(match[2]);
101732
+ if (key === null || match[2] !== "null" && value === null) return null;
101733
+ if (Object.prototype.hasOwnProperty.call(mapping, key)) return null;
101734
+ mapping[key] = value;
101735
+ rest = match[3];
101736
+ }
101737
+ return Object.keys(mapping).length === 0 ? null : mapping;
101738
+ }
101739
+ function enumMapDraft(mapping) {
101740
+ return {
101741
+ kind: "enum-map",
101742
+ mapping: { ...mapping }
101743
+ };
101744
+ }
101745
+ function jsonString(token) {
101746
+ try {
101747
+ const parsed = JSON.parse(token);
101748
+ return typeof parsed === "string" ? parsed : null;
101749
+ } catch {
101750
+ return null;
101751
+ }
101752
+ }
101753
+ //#endregion
101754
+ //#region src/composition/customize/keyed-array-compile.ts
101755
+ var catalog$1 = CAP_CUSTOMIZE_CATALOG;
101756
+ function compileKeyedArrayOverride(input) {
101757
+ const target = catalogTarget$1(input.cap, input.targetId);
101758
+ if (target === null || target.cardinality !== "keyedArray") return fail("target");
101759
+ if (input.items.length === 0) return fail("items");
101760
+ if (input.items.some((item) => item.draft.cap !== input.cap || item.draft.targetId !== input.targetId)) return fail("target");
101761
+ const keys = input.items.map((item) => item.draft.key);
101762
+ if (new Set(keys).size !== keys.length) return fail("key");
101763
+ const built = input.items.reduce((acc, item) => {
101764
+ if (!acc.ok) return acc;
101765
+ const entry = compileItem(target, item);
101766
+ if (!entry.ok) return entry;
101767
+ return {
101768
+ ok: true,
101769
+ value: {
101770
+ ...acc.value,
101771
+ [item.draft.key]: entry.value
101772
+ }
101773
+ };
101774
+ }, {
101775
+ ok: true,
101776
+ value: {}
101777
+ });
101778
+ if (!built.ok) return built;
101779
+ const fields = compileCompanions(target, input.apply);
101780
+ if (!fields.ok) return fields;
101781
+ return {
101782
+ ok: true,
101783
+ value: {
101784
+ kind: "fields",
101785
+ cap: input.cap,
101786
+ fields: fields.value,
101787
+ items: { ...built.value }
101788
+ }
101789
+ };
101790
+ }
101791
+ /** Put one compiled item into an existing feature. Other items stay as stored. */
101792
+ function mergeKeyedArrayItem(current, compiled, key) {
101793
+ const item = compiled.items?.[key];
101794
+ if (item === void 0) return null;
101795
+ return {
101796
+ kind: "fields",
101797
+ cap: compiled.cap,
101798
+ ...current?.enabled === void 0 ? {} : { enabled: current.enabled },
101799
+ fields: current === null ? compiled.fields : current.fields,
101800
+ items: {
101801
+ ...current?.items,
101802
+ [key]: item
101803
+ }
101804
+ };
101805
+ }
101806
+ /** The feature without item `key`. Null when that item was the last one. */
101807
+ function withoutKeyedArrayItem(feature, key) {
101808
+ const rest = Object.fromEntries(Object.entries(feature.items ?? {}).filter(([name]) => name !== key));
101809
+ if (Object.keys(rest).length === 0) return null;
101810
+ return {
101811
+ ...feature,
101812
+ items: rest
101813
+ };
101814
+ }
101815
+ function fail(reason) {
101816
+ return {
101817
+ ok: false,
101818
+ reason
101819
+ };
101820
+ }
101821
+ function catalogTarget$1(cap, targetId) {
101822
+ const entry = catalog$1[cap];
101823
+ if (entry === void 0) return null;
101824
+ return entry.targets.find((target) => target.id === targetId) ?? null;
101825
+ }
101826
+ function compileItem(target, item) {
101827
+ if (!require_composition.COMPOSITION_ITEM_KEY_RE.test(item.draft.key) || item.draft.label.trim() === "") return fail("key");
101828
+ const field = (target.fields ?? []).find((entry) => entry.path === item.draft.fieldPath);
101829
+ if (field === void 0) return fail("field");
101830
+ const source = sourceSpec(field, item);
101831
+ if (source === null) return fail("source-kind");
101832
+ if (source.requiredUnit !== void 0 && item.sourceUnit !== source.requiredUnit) return fail("unit");
101833
+ const allowed = item.draft.transform.kind;
101834
+ if (!source.transformKinds.includes(allowed)) return fail("transform");
101835
+ const value = compileValue(item, field);
101836
+ if (!value.ok) return value;
101837
+ const fields = compileLiterals(target, field, item, value.value);
101838
+ if (!fields.ok) return fields;
101839
+ return {
101840
+ ok: true,
101841
+ value: {
101842
+ label: item.draft.label.trim(),
101843
+ fields: fields.value
101844
+ }
101845
+ };
101846
+ }
101847
+ function sourceSpec(field, item) {
101848
+ if (item.sourceValueKind === "number") return field.sources.find((source) => source.kind === "numeric") ?? null;
101849
+ if (item.sourceValueKind === "enum" || item.sourceValueKind === "string") return field.sources.find((source) => source.kind === "enum") ?? null;
101850
+ return null;
101851
+ }
101852
+ function compileValue(item, field) {
101853
+ const read = fromRead(refOf(item.draft), item.draft.source.cap, item.draft.source.fieldPath);
101854
+ const transform = item.draft.transform;
101855
+ if (transform.kind === "identity") return {
101856
+ ok: true,
101857
+ value: read
101858
+ };
101859
+ if (transform.kind === "linear") return linearValue(transform, read);
101860
+ if (transform.kind === "enum-map") return enumValue(transform, read, field);
101861
+ return fail("transform");
101862
+ }
101863
+ function linearValue(transform, read) {
101864
+ const scale = signedToken(transform.scale);
101865
+ const offset = signedToken(transform.offset);
101866
+ if (scale === null || offset === null) return fail("scale");
101867
+ const clamps = clampTokens(transform.clampMin, transform.clampMax);
101868
+ if (!clamps.ok) return clamps;
101869
+ return {
101870
+ ok: true,
101871
+ value: expression(linearExpr("x", scale, offset, clamps.value.min, clamps.value.max), { x: read })
101872
+ };
101873
+ }
101874
+ function clampTokens(clampMin, clampMax) {
101875
+ if (clampMin === void 0 && clampMax === void 0) return {
101876
+ ok: true,
101877
+ value: {
101878
+ min: null,
101879
+ max: null
101880
+ }
101881
+ };
101882
+ if (clampMin === void 0 || clampMax === void 0) return fail("clamp");
101883
+ const min = signedToken(clampMin);
101884
+ const max = signedToken(clampMax);
101885
+ if (min === null || max === null || clampMin > clampMax) return fail("clamp");
101886
+ return {
101887
+ ok: true,
101888
+ value: {
101889
+ min,
101890
+ max
101891
+ }
101892
+ };
101893
+ }
101894
+ function enumValue(transform, read, field) {
101895
+ const allowed = new Set(field.enumValues ?? []);
101896
+ const entries = Object.entries(transform.mapping);
101897
+ if (entries.length === 0) return fail("enum");
101898
+ if (entries.some(([key, value]) => key.length === 0 || value !== null && !allowed.has(value))) return fail("enum");
101899
+ const expr = enumMapExpr(transform.mapping);
101900
+ if (expr === null) return fail("enum");
101901
+ return {
101902
+ ok: true,
101903
+ value: expression(expr, { x: read })
101904
+ };
101905
+ }
101906
+ function compileLiterals(target, field, item, value) {
101907
+ const required = new Set((field.literals ?? []).map((literalSpec) => literalSpec.path));
101908
+ const traits = new Map((target.traits ?? []).map((trait) => [trait.path, new Set(trait.values)]));
101909
+ if ([...required].filter((path) => !item.literals.some((literalSpec) => literalSpec.path === path)).length > 0) return fail("literal");
101910
+ return item.literals.reduce((acc, entry) => {
101911
+ if (!acc.ok) return acc;
101912
+ if (entry.path === field.path || acc.value[entry.path] !== void 0) return fail("literal");
101913
+ const allowed = allowedLiteral(field, traits, entry.path);
101914
+ if (allowed === null || !allowed.has(entry.value)) return fail("literal");
101915
+ const expr = constantExpr(entry.value);
101916
+ if (expr === null) return fail("literal");
101917
+ return {
101918
+ ok: true,
101919
+ value: {
101920
+ ...acc.value,
101921
+ [entry.path]: literal(expr)
101922
+ }
101923
+ };
101924
+ }, {
101925
+ ok: true,
101926
+ value: { [field.path]: value }
101927
+ });
101928
+ }
101929
+ function allowedLiteral(field, traits, path) {
101930
+ const trait = traits.get(path);
101931
+ if (trait !== void 0) return trait;
101932
+ const required = (field.literals ?? []).find((entry) => entry.path === path);
101933
+ return required === void 0 ? null : new Set(required.values);
101934
+ }
101935
+ function compileCompanions(target, apply) {
101936
+ return (target.companions ?? []).filter((companion) => companionIncluded(companion, apply)).reduce((acc, companion) => {
101937
+ if (!acc.ok) return acc;
101938
+ if (companion.kind !== "clock") return fail("companion");
101939
+ return {
101940
+ ok: true,
101941
+ value: {
101942
+ ...acc.value,
101943
+ [companion.path]: literal("now")
101944
+ }
101945
+ };
101946
+ }, {
101947
+ ok: true,
101948
+ value: {}
101949
+ });
101950
+ }
101951
+ function companionIncluded(companion, apply) {
101952
+ if (companion.kind === "transition-time") return false;
101953
+ return companion.when === "always" || apply === "add";
101954
+ }
101955
+ function refOf(draft) {
101956
+ return {
101957
+ addonId: draft.source.addonId,
101958
+ stableId: draft.source.stableId
101959
+ };
101960
+ }
101961
+ //#endregion
101962
+ //#region src/composition/customize/keyed-array-decode.ts
101963
+ var catalog = CAP_CUSTOMIZE_CATALOG;
101964
+ function readKeyedArrayItems(feature, cap, targetId) {
101965
+ const target = catalogTarget(cap, targetId);
101966
+ if (target === null || target.cardinality !== "keyedArray" || feature.cap !== cap) return null;
101967
+ const apply = inferApply(target, feature.fields);
101968
+ const canonical = apply !== null && companionsMatch(target, feature.fields, apply);
101969
+ const items = Object.entries(feature.items ?? {}).map(([key, item]) => viewOf(target, cap, targetId, key, item, canonical));
101970
+ return {
101971
+ canonical,
101972
+ apply: apply ?? "add",
101973
+ items
101974
+ };
101975
+ }
101976
+ function decodeKeyedArrayOverride(input) {
101977
+ const read = readKeyedArrayItems(input.feature, input.cap, input.targetId);
101978
+ if (read === null || !read.canonical) return null;
101979
+ if (read.items.some((item) => item.compile === null)) return null;
101980
+ const compiles = read.items.flatMap((item) => item.compile === null ? [] : [item.compile]);
101981
+ const compiled = compileKeyedArrayOverride({
101982
+ cap: input.cap,
101983
+ targetId: input.targetId,
101984
+ device: input.device,
101985
+ apply: read.apply,
101986
+ items: compiles
101987
+ });
101988
+ if (!compiled.ok) return null;
101989
+ return sameFeature(compiled.value, input.feature) ? read : null;
101990
+ }
101991
+ function viewOf(target, cap, targetId, key, item, canonical) {
101992
+ const blank = {
101993
+ key,
101994
+ label: item.label,
101995
+ recognized: false,
101996
+ compile: null
101997
+ };
101998
+ if (!canonical) return blank;
101999
+ const compile = compileOf(target, cap, targetId, key, item);
102000
+ if (compile === null) return blank;
102001
+ return {
102002
+ key,
102003
+ label: item.label,
102004
+ recognized: true,
102005
+ compile
102006
+ };
102007
+ }
102008
+ function compileOf(target, cap, targetId, key, item) {
102009
+ const assigned = assignedField(target, item);
102010
+ if (assigned === null) return null;
102011
+ const literals = literalFields(target, assigned.field, item, assigned.path);
102012
+ if (literals === null) return null;
102013
+ const draft = draftOf(cap, targetId, key, item.label, assigned);
102014
+ if (draft === null) return null;
102015
+ const compile = {
102016
+ draft,
102017
+ sourceValueKind: assigned.sourceValueKind,
102018
+ sourceUnit: null,
102019
+ literals
102020
+ };
102021
+ return reproduces(cap, targetId, key, compile, item) ? compile : null;
102022
+ }
102023
+ function assignedField(target, item) {
102024
+ const paths = Object.keys(item.fields).filter((path) => !isConstant(item.fields[path]));
102025
+ if (paths.length !== 1) return null;
102026
+ const path = paths[0];
102027
+ if (path === void 0) return null;
102028
+ const field = (target.fields ?? []).find((entry) => entry.path === path);
102029
+ const source = item.fields[path];
102030
+ if (field === void 0 || source === void 0) return null;
102031
+ const read = readTransform(source, field);
102032
+ if (read === null) return null;
102033
+ return {
102034
+ path,
102035
+ field,
102036
+ source,
102037
+ ...read
102038
+ };
102039
+ }
102040
+ function readTransform(source, field) {
102041
+ if (source.kind === "from") return field.valueKind === "enum" ? {
102042
+ sourceValueKind: "enum",
102043
+ transform: { kind: "identity" }
102044
+ } : {
102045
+ sourceValueKind: "number",
102046
+ transform: { kind: "identity" }
102047
+ };
102048
+ if (source.kind !== "expression") return null;
102049
+ const mapped = parseEnumMap(source.expr);
102050
+ if (mapped !== null && field.valueKind === "enum") return {
102051
+ sourceValueKind: "enum",
102052
+ transform: enumMapDraft(mapped)
102053
+ };
102054
+ const linear = parseLinear(source.expr);
102055
+ if (linear === null || linear.inner !== "x" || field.valueKind !== "number") return null;
102056
+ return {
102057
+ sourceValueKind: "number",
102058
+ transform: {
102059
+ kind: "linear",
102060
+ scale: linear.scale,
102061
+ offset: linear.offset,
102062
+ ...linear.clampMin === void 0 || linear.clampMax === void 0 ? {} : {
102063
+ clampMin: linear.clampMin,
102064
+ clampMax: linear.clampMax
102065
+ }
102066
+ }
102067
+ };
102068
+ }
102069
+ function literalFields(target, field, item, assignedPath) {
102070
+ const required = new Set((field.literals ?? []).map((entry) => entry.path));
102071
+ const traits = new Set((target.traits ?? []).map((trait) => trait.path));
102072
+ const found = Object.keys(item.fields).filter((path) => path !== assignedPath);
102073
+ if (found.some((path) => !required.has(path) && !traits.has(path))) return null;
102074
+ if ([...required].some((path) => !found.includes(path))) return null;
102075
+ const literals = found.map((path) => literalValue(item.fields[path], path));
102076
+ if (literals.some((entry) => entry === null)) return null;
102077
+ return literals.flatMap((entry) => entry === null ? [] : [entry]);
102078
+ }
102079
+ function literalValue(source, path) {
102080
+ if (source?.kind !== "expression" || Object.keys(source.bindings).length !== 0) return null;
102081
+ if (!(source.expr.startsWith("\"") && source.expr.endsWith("\""))) return null;
102082
+ try {
102083
+ const parsed = JSON.parse(source.expr);
102084
+ return typeof parsed === "string" ? {
102085
+ path,
102086
+ value: parsed
102087
+ } : null;
102088
+ } catch {
102089
+ return null;
102090
+ }
102091
+ }
102092
+ function draftOf(cap, targetId, key, label, assigned) {
102093
+ const bound = singleFrom(assigned.source);
102094
+ if (bound === null) return null;
102095
+ return {
102096
+ kind: "keyedArray",
102097
+ cap,
102098
+ targetId,
102099
+ key,
102100
+ label,
102101
+ fieldPath: assigned.path,
102102
+ source: {
102103
+ addonId: bound.addonId,
102104
+ stableId: bound.stableId,
102105
+ cap: bound.cap,
102106
+ fieldPath: bound.fieldPath
102107
+ },
102108
+ transform: assigned.transform
102109
+ };
102110
+ }
102111
+ function reproduces(cap, targetId, key, compile, item) {
102112
+ const compiled = compileKeyedArrayOverride({
102113
+ cap,
102114
+ targetId,
102115
+ device: {
102116
+ addonId: "t",
102117
+ stableId: "t"
102118
+ },
102119
+ apply: "add",
102120
+ items: [compile]
102121
+ });
102122
+ if (!compiled.ok) return false;
102123
+ const written = compiled.value.items?.[key];
102124
+ if (written === void 0) return false;
102125
+ return JSON.stringify(written) === JSON.stringify(item);
102126
+ }
102127
+ function isConstant(source) {
102128
+ return source?.kind === "expression" && Object.keys(source.bindings).length === 0;
102129
+ }
102130
+ function inferApply(target, fields) {
102131
+ const addPaths = (target.companions ?? []).flatMap((companion) => companion.kind !== "transition-time" && companion.when === "add" ? [companion.path] : []);
102132
+ if (addPaths.length === 0) return "replace";
102133
+ const present = addPaths.filter((path) => fields[path] !== void 0);
102134
+ if (present.length === addPaths.length) return "add";
102135
+ if (present.length === 0) return "replace";
102136
+ return null;
102137
+ }
102138
+ function companionsMatch(target, fields, apply) {
102139
+ const expected = (target.companions ?? []).flatMap((companion) => {
102140
+ if (companion.kind === "transition-time") return [];
102141
+ if (companion.when === "always" || apply === "add") return [companion.path];
102142
+ return [];
102143
+ });
102144
+ if (Object.keys(fields).toSorted().join(",") !== [...expected].toSorted().join(",")) return false;
102145
+ return expected.every((path) => isLiteral(fields[path], "now"));
102146
+ }
102147
+ function catalogTarget(cap, targetId) {
102148
+ const entry = catalog[cap];
102149
+ if (entry === void 0) return null;
102150
+ return entry.targets.find((target) => target.id === targetId) ?? null;
102151
+ }
102152
+ function sameFeature(compiled, stored) {
102153
+ return sameStored(wrap(stripEnabled(compiled)), wrap(stripEnabled(stored)));
102154
+ }
102155
+ function stripEnabled(feature) {
102156
+ const { enabled: _enabled, ...rest } = feature;
102157
+ return rest;
102158
+ }
102159
+ function wrap(feature) {
102160
+ return {
102161
+ family: "composition",
102162
+ target: {
102163
+ addonId: "t",
102164
+ stableId: "t"
102165
+ },
102166
+ feature
102167
+ };
102168
+ }
102169
+ //#endregion
102170
+ //#region src/composition/customize/keyed-array-status.ts
102171
+ function projectKeyedArrayAssignment(input) {
102172
+ if (input.stored.kind === "pending") return unanswered(input.targetId, "pending", null);
102173
+ if (input.stored.kind === "unknown") return unanswered(input.targetId, "unknown", input.stored.reason ?? "unknown");
102174
+ if (input.stored.value === null) return native(input.targetId);
102175
+ const read = readKeyedArrayItems(input.stored.value, input.cap, input.targetId);
102176
+ const count = read?.items.filter((item) => item.recognized).length ?? 0;
102177
+ if (read === null || !read.canonical || count === 0) return {
102178
+ text: "unknown",
102179
+ assignedCount: 0,
102180
+ status: status(input.targetId, true, "assigned", "unavailable", "not-canonical")
102181
+ };
102182
+ return projectDecoded(input, count);
102183
+ }
102184
+ function projectDecoded(input, count) {
102185
+ const text = `${count} assigned`;
102186
+ if (input.sourcePresence === "pending") return {
102187
+ text: "pending",
102188
+ assignedCount: count,
102189
+ status: status(input.targetId, true, "assigned", "stale", null)
102190
+ };
102191
+ if (input.sourcePresence === "unknown") return {
102192
+ text: "unknown",
102193
+ assignedCount: count,
102194
+ status: status(input.targetId, true, "assigned", "stale", input.sourceUnknownReason ?? "unknown")
102195
+ };
102196
+ if (input.sourcePresence === "absent") return {
102197
+ text,
102198
+ assignedCount: count,
102199
+ status: status(input.targetId, true, "assigned", "unavailable", "source-missing")
102200
+ };
102201
+ return {
102202
+ text,
102203
+ assignedCount: count,
102204
+ status: status(input.targetId, true, "assigned", "active", null)
102205
+ };
102206
+ }
102207
+ function native(targetId) {
102208
+ return {
102209
+ text: "Native",
102210
+ assignedCount: 0,
102211
+ status: status(targetId, false, "native", "active", null)
102212
+ };
102213
+ }
102214
+ function unanswered(targetId, text, reason) {
102215
+ return {
102216
+ text,
102217
+ assignedCount: 0,
102218
+ status: status(targetId, false, "native", text === "pending" ? "unavailable" : "stale", reason)
102219
+ };
102220
+ }
102221
+ function status(targetId, configured, source, state, reason) {
102222
+ return {
102223
+ targetId,
102224
+ configured,
102225
+ source,
102226
+ state,
102227
+ reason
102228
+ };
102229
+ }
102230
+ //#endregion
100005
102231
  //#region src/generated/scope-presets.ts
100006
102232
  var SCOPE_PRESETS = [
100007
102233
  {
@@ -101660,6 +103886,7 @@ function prepareNotification(caps, n) {
101660
103886
  * narrows, and still fails CLOSED on a subject that cannot produce the identity
101661
103887
  * it tests (a device the mirror cannot name is not evidence of a camera).
101662
103888
  */
103889
+ var LEGACY_KINDS_WITHOUT_FILTERS = new Set(NC_LEGACY_SYSTEM_EVENT_KINDS);
101663
103890
  /**
101664
103891
  * Every filter, for the callers that must cover all of them (guards, tests).
101665
103892
  *
@@ -101683,6 +103910,7 @@ var NC_SYSTEM_EVENT_FILTER_KEYS = [
101683
103910
  * ignores it and an editor hides its input. It never means "excluded".
101684
103911
  */
101685
103912
  function systemEventFilterApplies(kind, filter) {
103913
+ if (LEGACY_KINDS_WITHOUT_FILTERS.has(kind)) return false;
101686
103914
  switch (filter) {
101687
103915
  case "deviceIds": return kind.startsWith("device-") || kind.startsWith("stream-") || kind === "detection-blind" || kind.startsWith("motion-") || kind.startsWith("recording-") || kind === "alarm-triggered";
101688
103916
  case "deviceTypes": return kind.startsWith("device-") || kind === "detection-blind" || kind.startsWith("motion-");
@@ -101737,9 +103965,6 @@ var NC_SYSTEM_EVENT_FAMILY = {
101737
103965
  "device-battery-normal": "device-events",
101738
103966
  "device-consumable-low": "device-events",
101739
103967
  "device-consumable-normal": "device-events",
101740
- "device-tank-low": "device-events",
101741
- "device-tank-full": "device-events",
101742
- "device-tank-normal": "device-events",
101743
103968
  "stream-online": "device-events",
101744
103969
  "stream-offline": "device-events",
101745
103970
  "detection-blind": "device-events",
@@ -101834,16 +104059,6 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
101834
104059
  label: "Consumables",
101835
104060
  kinds: ["device-consumable-low", "device-consumable-normal"]
101836
104061
  },
101837
- {
101838
- id: "tanks",
101839
- family: "device-events",
101840
- label: "Tanks",
101841
- kinds: [
101842
- "device-tank-low",
101843
- "device-tank-full",
101844
- "device-tank-normal"
101845
- ]
101846
- },
101847
104062
  {
101848
104063
  id: "detection-blind",
101849
104064
  family: "device-events",
@@ -103740,11 +105955,6 @@ var RULE_BODY_ONLY = ["body"];
103740
105955
  var RULE_TEXT = ["title", "body"];
103741
105956
  var BATTERY = ["device-battery-low", "device-battery-normal"];
103742
105957
  var CONSUMABLE = ["device-consumable-low", "device-consumable-normal"];
103743
- var TANK = [
103744
- "device-tank-low",
103745
- "device-tank-full",
103746
- "device-tank-normal"
103747
- ];
103748
105958
  var ALERT_EPISODE = [
103749
105959
  "alert-critical",
103750
105960
  "alert-error",
@@ -103776,7 +105986,6 @@ var DEVICE_EVENTS = [
103776
105986
  "device-enabled",
103777
105987
  ...BATTERY,
103778
105988
  ...CONSUMABLE,
103779
- ...TANK,
103780
105989
  "stream-online",
103781
105990
  "stream-offline",
103782
105991
  "detection-blind",
@@ -103822,12 +106031,6 @@ var STATE_SUMMARY_SECTION_VARS = [
103822
106031
  example: "Robot — filter 10 %",
103823
106032
  kinds: CONSUMABLE
103824
106033
  },
103825
- {
103826
- name: "summaryTanks",
103827
- label: "Summary: tanks",
103828
- example: "Robot — clean water low",
103829
- kinds: TANK
103830
- },
103831
106034
  {
103832
106035
  name: "summaryDetection",
103833
106036
  label: "Summary: cameras detecting nothing",
@@ -104236,18 +106439,7 @@ var NC_TEMPLATE_VARS = [
104236
106439
  families: ["rule"],
104237
106440
  fields: [...RULE_TEXT],
104238
106441
  kinds: ["system"],
104239
- systemEventKinds: [...CONSUMABLE, ...TANK]
104240
- },
104241
- {
104242
- name: "tank",
104243
- label: "Tank",
104244
- description: "Which tank, as a stable token: cleanWater, dirtyWater, detergent, dustBin, or the device key of any other supply (salt, rinse aid).",
104245
- example: "clean water",
104246
- group: "system",
104247
- families: ["rule"],
104248
- fields: [...RULE_TEXT],
104249
- kinds: ["system"],
104250
- systemEventKinds: [...TANK]
106442
+ systemEventKinds: [...CONSUMABLE]
104251
106443
  },
104252
106444
  {
104253
106445
  name: "profile",
@@ -104898,9 +107090,6 @@ var NC_TEMPLATE_VARS = [
104898
107090
  * delete it from here then, and the served catalog names it again.
104899
107091
  */
104900
107092
  var NC_TEMPLATE_HELD_BACK_SYSTEM_EVENT_KINDS = [
104901
- "device-tank-low",
104902
- "device-tank-full",
104903
- "device-tank-normal",
104904
107093
  "node-restarting",
104905
107094
  "node-updating",
104906
107095
  "alert-critical",
@@ -105062,15 +107251,6 @@ var NC_SYSTEM_EVENT_CLASS_SPECS = [
105062
107251
  snapshotLabel: "Consumables low now",
105063
107252
  snapshotSection: "consumables"
105064
107253
  },
105065
- {
105066
- id: "tanks",
105067
- family: "device-events",
105068
- label: "Tanks (low or full / back to normal)",
105069
- bad: ["device-tank-low", "device-tank-full"],
105070
- recovery: ["device-tank-normal"],
105071
- snapshotLabel: "Tanks low or full now",
105072
- snapshotSection: "tanks"
105073
- },
105074
107254
  {
105075
107255
  id: "motion-noise",
105076
107256
  family: "device-events",
@@ -110783,6 +112963,7 @@ exports.CAMSTACK_EVENT_PREFIX = CAMSTACK_EVENT_PREFIX;
110783
112963
  exports.CAM_PROFILE_ORDER = require_sleep.CAM_PROFILE_ORDER;
110784
112964
  exports.CAPABILITY_NAMES = CAPABILITY_NAMES;
110785
112965
  exports.CAPABILITY_ROUTER_KEYS = CAPABILITY_ROUTER_KEYS;
112966
+ exports.CAP_CUSTOMIZE_CATALOG = CAP_CUSTOMIZE_CATALOG;
110786
112967
  exports.CAP_NAMES_WITH_STATUS = CAP_NAMES_WITH_STATUS;
110787
112968
  exports.CAP_NODE_PIN_CONTEXT_KEY = require_sleep.CAP_NODE_PIN_CONTEXT_KEY;
110788
112969
  exports.CAP_PROVIDER_KIND_MAP = CAP_PROVIDER_KIND_MAP;
@@ -111011,6 +113192,7 @@ exports.CredentialScopeSchema = CredentialScopeSchema;
111011
113192
  exports.CredentialTokenClaimsSchema = CredentialTokenClaimsSchema;
111012
113193
  exports.CustomActionInputSchema = CustomActionInputSchema;
111013
113194
  exports.CustomModelDescriptorSchema = CustomModelDescriptorSchema;
113195
+ exports.CustomizeAssignmentStatusSchema = CustomizeAssignmentStatusSchema;
111014
113196
  exports.DATABASE_SNAPSHOT_PARTIAL_SUFFIX = DATABASE_SNAPSHOT_PARTIAL_SUFFIX;
111015
113197
  exports.DATABASE_SNAPSHOT_SUFFIX = DATABASE_SNAPSHOT_SUFFIX;
111016
113198
  exports.DATABASE_SNAPSHOT_TIMEOUT_MS = DATABASE_SNAPSHOT_TIMEOUT_MS;
@@ -111352,6 +113534,8 @@ exports.ICON_ENTRIES = ICON_ENTRIES;
111352
113534
  exports.ICON_KEYS = ICON_KEYS;
111353
113535
  exports.ICON_VIEWER_MODULES = ICON_VIEWER_MODULES;
111354
113536
  exports.INFERENCE_DEVICE_EXCLUSION_REASONS = INFERENCE_DEVICE_EXCLUSION_REASONS;
113537
+ exports.INITIAL_PULSE = INITIAL_PULSE;
113538
+ exports.INITIAL_SPAN = INITIAL_SPAN;
111355
113539
  exports.INVERTIBLE_CAPS = INVERTIBLE_CAPS;
111356
113540
  exports.IconKeySchema = IconKeySchema;
111357
113541
  exports.ImageContractSchema = ImageContractSchema;
@@ -111533,6 +113717,7 @@ exports.MOTION_CROP_MAX_REGIONS = MOTION_CROP_MAX_REGIONS;
111533
113717
  exports.MOTION_CROP_MOTION_PAD = MOTION_CROP_MOTION_PAD;
111534
113718
  exports.MOTION_CROP_TRACKED_PAD = MOTION_CROP_TRACKED_PAD;
111535
113719
  exports.MOTION_SOURCE_LABELS = MOTION_SOURCE_LABELS;
113720
+ exports.MOTION_SPAN_TIMEOUT_MS = MOTION_SPAN_TIMEOUT_MS;
111536
113721
  exports.MOTION_TRIGGER_FEATURE = MOTION_TRIGGER_FEATURE;
111537
113722
  exports.ManagedModelCatalogEntrySchema = ManagedModelCatalogEntrySchema;
111538
113723
  exports.ManagedModelExtraFileSchema = ManagedModelExtraFileSchema;
@@ -111665,6 +113850,7 @@ exports.NC_GROUPING_MAX_SEC = NC_GROUPING_MAX_SEC;
111665
113850
  exports.NC_GROUPING_MIN_SEC = NC_GROUPING_MIN_SEC;
111666
113851
  exports.NC_HISTORY_LIMIT_DEFAULT = NC_HISTORY_LIMIT_DEFAULT;
111667
113852
  exports.NC_HISTORY_LIMIT_MAX = NC_HISTORY_LIMIT_MAX;
113853
+ exports.NC_LEGACY_SYSTEM_EVENT_KINDS = NC_LEGACY_SYSTEM_EVENT_KINDS;
111668
113854
  exports.NC_MAX_PER_TRACK_IMMEDIATE = NC_MAX_PER_TRACK_IMMEDIATE;
111669
113855
  exports.NC_MEDIA_IMAGE_MODES = NC_MEDIA_IMAGE_MODES;
111670
113856
  exports.NC_OCCUPANCY_DEFAULTS = NC_OCCUPANCY_DEFAULTS;
@@ -111679,6 +113865,7 @@ exports.NC_SENSOR_TRANSITION_NEVER_FIRES_WARNING = NC_SENSOR_TRANSITION_NEVER_FI
111679
113865
  exports.NC_SENSOR_TRANSITION_UNSUPPORTED_REASON = NC_SENSOR_TRANSITION_UNSUPPORTED_REASON;
111680
113866
  exports.NC_SERVER_PACKAGE_NAME = NC_SERVER_PACKAGE_NAME;
111681
113867
  exports.NC_SNOOZE_MAX_MINUTES = NC_SNOOZE_MAX_MINUTES;
113868
+ exports.NC_STATE_SUMMARY_SECTION_IDS = NC_STATE_SUMMARY_SECTION_IDS;
111682
113869
  exports.NC_SYSTEM_DELIVERY = NC_SYSTEM_DELIVERY;
111683
113870
  exports.NC_SYSTEM_EVENT_CLASS_SPECS = NC_SYSTEM_EVENT_CLASS_SPECS;
111684
113871
  exports.NC_SYSTEM_EVENT_CONDITION_FILTER_KEYS = NC_SYSTEM_EVENT_CONDITION_FILTER_KEYS;
@@ -111689,7 +113876,6 @@ exports.NC_SYSTEM_EVENT_FILTER_KEYS = NC_SYSTEM_EVENT_FILTER_KEYS;
111689
113876
  exports.NC_SYSTEM_EVENT_KIND_GROUP_SPECS = NC_SYSTEM_EVENT_KIND_GROUP_SPECS;
111690
113877
  exports.NC_SYSTEM_EVENT_SUMMARY_FAMILIES = NC_SYSTEM_EVENT_SUMMARY_FAMILIES;
111691
113878
  exports.NC_SYSTEM_RULE_KINDS = NC_SYSTEM_RULE_KINDS;
111692
- exports.NC_TANK_SYSTEM_EVENT_KINDS = NC_TANK_SYSTEM_EVENT_KINDS;
111693
113879
  exports.NC_TAXONOMY = NC_TAXONOMY;
111694
113880
  exports.NC_TEMPLATE_HELD_BACK_SYSTEM_EVENT_KINDS = NC_TEMPLATE_HELD_BACK_SYSTEM_EVENT_KINDS;
111695
113881
  exports.NC_TEMPLATE_VARS = NC_TEMPLATE_VARS;
@@ -111907,6 +114093,7 @@ exports.OsdTemplateBindingSchema = OsdTemplateBindingSchema;
111907
114093
  exports.OsdTemplateFormatSchema = OsdTemplateFormatSchema;
111908
114094
  exports.OsdTemplatePickSchema = OsdTemplatePickSchema;
111909
114095
  exports.OsdTemplateTokenKindSchema = OsdTemplateTokenKindSchema;
114096
+ exports.OverrideDraftSchema = OverrideDraftSchema;
111910
114097
  exports.PEER_BYTES_CHUNK_BYTES = require_sleep.PEER_BYTES_CHUNK_BYTES;
111911
114098
  exports.PEER_BYTES_MAX_OUTSTANDING = require_sleep.PEER_BYTES_MAX_OUTSTANDING;
111912
114099
  exports.PEER_BYTES_STALL_MS = require_sleep.PEER_BYTES_STALL_MS;
@@ -112067,6 +114254,10 @@ exports.ROOT_CHILD_CONTAINMENT_MIN = ROOT_CHILD_CONTAINMENT_MIN;
112067
114254
  exports.ROOT_FACE_REFINE_INPUT_PX = ROOT_FACE_REFINE_INPUT_PX;
112068
114255
  exports.ROOT_FACE_REFINE_SCALE = ROOT_FACE_REFINE_SCALE;
112069
114256
  exports.ROOT_SUPPLIABLE_STEP_IDS = ROOT_SUPPLIABLE_STEP_IDS;
114257
+ exports.RUNNING_POWER_START_DELAY_MS = RUNNING_POWER_START_DELAY_MS;
114258
+ exports.RUNNING_POWER_STOP_DELAY_MS = RUNNING_POWER_STOP_DELAY_MS;
114259
+ exports.RUNNING_POWER_THRESHOLD_WATTS = RUNNING_POWER_THRESHOLD_WATTS;
114260
+ exports.RUNNING_STATE_COLD = RUNNING_STATE_COLD;
112070
114261
  exports.RUNTIME_DEFAULTS = require_sleep.RUNTIME_DEFAULTS;
112071
114262
  exports.RUNTIME_STATE_POLICY = RUNTIME_STATE_POLICY;
112072
114263
  exports.RUNTIME_STATE_REFRESH_MISS_COOLDOWN_MS = RUNTIME_STATE_REFRESH_MISS_COOLDOWN_MS;
@@ -112218,6 +114409,8 @@ exports.RunnerJumpStepProvisioningSchema = RunnerJumpStepProvisioningSchema;
112218
114409
  exports.RunnerLocalLoadSchema = RunnerLocalLoadSchema;
112219
114410
  exports.RunnerLocalMetricsSchema = RunnerLocalMetricsSchema;
112220
114411
  exports.RunnerRefusalSchema = RunnerRefusalSchema;
114412
+ exports.RunningStateSourceSchema = RunningStateSourceSchema;
114413
+ exports.RunningStateStatusSchema = RunningStateStatusSchema;
112221
114414
  exports.SCENE_CONDITIONS = SCENE_CONDITIONS;
112222
114415
  exports.SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX = SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX;
112223
114416
  exports.SCENE_CONFIRM_DEFAULT_TIMEOUT_MS = SCENE_CONFIRM_DEFAULT_TIMEOUT_MS;
@@ -112657,7 +114850,6 @@ exports.buildCapabilityLookup = buildCapabilityLookup;
112657
114850
  exports.buildDeviceAdminUrl = buildDeviceAdminUrl;
112658
114851
  exports.buildDeviceEnrollmentLink = buildDeviceEnrollmentLink;
112659
114852
  exports.buildDeviceSignatureMessage = buildDeviceSignatureMessage;
112660
- exports.buildDoorbellCompositionFeature = buildDoorbellCompositionFeature;
112661
114853
  exports.buildEventKindDescriptor = buildEventKindDescriptor;
112662
114854
  exports.buildFfmpegArgs = require_composition.buildFfmpegArgs;
112663
114855
  exports.buildFrigateClassMap = buildFrigateClassMap;
@@ -112731,6 +114923,10 @@ exports.commitWatchdogRestart = commitWatchdogRestart;
112731
114923
  exports.compareToTarget = compareToTarget;
112732
114924
  exports.compileExpression = require_composition.compileExpression;
112733
114925
  exports.compileExpressionSafe = require_composition.compileExpressionSafe;
114926
+ exports.compileKeyedArrayOverride = compileKeyedArrayOverride;
114927
+ exports.compilePulseOverride = compilePulseOverride;
114928
+ exports.compileScalarOverride = compileScalarOverride;
114929
+ exports.compileSpanOverride = compileSpanOverride;
112734
114930
  exports.composeSwitchedOff = composeSwitchedOff;
112735
114931
  exports.composedDeviceRef = require_composition.composedDeviceRef;
112736
114932
  exports.composedDeviceStableId = require_composition.composedDeviceStableId;
@@ -112795,6 +114991,9 @@ exports.dayOfWeekToIndex = dayOfWeekToIndex;
112795
114991
  exports.declarationOwnerNodeId = declarationOwnerNodeId;
112796
114992
  exports.declarationsOf = require_sleep.declarationsOf;
112797
114993
  exports.declareLogChannel = declareLogChannel;
114994
+ exports.decodeKeyedArrayOverride = decodeKeyedArrayOverride;
114995
+ exports.decodePulseOverride = decodePulseOverride;
114996
+ exports.decodeScalarOverride = decodeScalarOverride;
112798
114997
  exports.decodeVectorBase64 = decodeVectorBase64;
112799
114998
  exports.decoderCapability = decoderCapability;
112800
114999
  exports.defaultDeliveryForSection = defaultDeliveryForSection;
@@ -112853,7 +115052,6 @@ exports.dishwasherCapability = dishwasherCapability;
112853
115052
  exports.doActionSelectValue = doActionSelectValue;
112854
115053
  exports.dominantClipLabels = dominantClipLabels;
112855
115054
  exports.doorbellCapability = doorbellCapability;
112856
- exports.doorbellFeatureSources = doorbellFeatureSources;
112857
115055
  exports.droppedConditionsForKind = droppedConditionsForKind;
112858
115056
  exports.edgetpuDelegateDevice = edgetpuDelegateDevice;
112859
115057
  exports.effectiveStepSettings = effectiveStepSettings;
@@ -113105,6 +115303,7 @@ exports.measuredDetectorCells = measuredDetectorCells;
113105
115303
  exports.mediaPlayerCapability = mediaPlayerCapability;
113106
115304
  exports.memoizePinnedFfmpeg = memoizePinnedFfmpeg;
113107
115305
  exports.mergeClipLabels = mergeClipLabels;
115306
+ exports.mergeKeyedArrayItem = mergeKeyedArrayItem;
113108
115307
  exports.mergeSecretStatePaths = require_sleep.mergeSecretStatePaths;
113109
115308
  exports.mergeSettingsBags = mergeSettingsBags;
113110
115309
  exports.mergeSourceInfo = mergeSourceInfo;
@@ -113231,6 +115430,10 @@ exports.pressureSensorCapability = pressureSensorCapability;
113231
115430
  exports.principalMayReachAddon = principalMayReachAddon;
113232
115431
  exports.privacyMaskCapability = privacyMaskCapability;
113233
115432
  exports.procedureAuthKey = procedureAuthKey;
115433
+ exports.projectKeyedArrayAssignment = projectKeyedArrayAssignment;
115434
+ exports.projectPulseAssignment = projectPulseAssignment;
115435
+ exports.projectScalarAssignment = projectScalarAssignment;
115436
+ exports.projectSpanAssignment = projectSpanAssignment;
113234
115437
  exports.projectSubjectPath = projectSubjectPath;
113235
115438
  exports.providerMotionEvent = providerMotionEvent;
113236
115439
  exports.ptzAutotrackCapability = ptzAutotrackCapability;
@@ -113246,6 +115449,7 @@ exports.readErrorI18n = require_sleep.readErrorI18n;
113246
115449
  exports.readFaceRescoreIntervalMinutes = readFaceRescoreIntervalMinutes;
113247
115450
  exports.readHubMotionDetected = readHubMotionDetected;
113248
115451
  exports.readHubMotionStatus = readHubMotionStatus;
115452
+ exports.readKeyedArrayItems = readKeyedArrayItems;
113249
115453
  exports.readMotionTriggeredBy = readMotionTriggeredBy;
113250
115454
  exports.readNativeLeaseOverride = readNativeLeaseOverride;
113251
115455
  exports.readNodePin = require_sleep.readNodePin;
@@ -113348,6 +115552,11 @@ exports.ruleSectionOf = ruleSectionOf;
113348
115552
  exports.ruleSeedForSection = ruleSeedForSection;
113349
115553
  exports.ruleTriggerZoneIds = ruleTriggerZoneIds;
113350
115554
  exports.runInferenceStep = runInferenceStep;
115555
+ exports.runningFromDishwasherOperation = runningFromDishwasherOperation;
115556
+ exports.runningFromLawnMower = runningFromLawnMower;
115557
+ exports.runningFromMediaPlayer = runningFromMediaPlayer;
115558
+ exports.runningFromVacuumState = runningFromVacuumState;
115559
+ exports.runningStateCapability = runningStateCapability;
113351
115560
  exports.runtimeDevices = runtimeDevices;
113352
115561
  exports.runtimeStatePolicyFor = runtimeStatePolicyFor;
113353
115562
  exports.sameDoFamily = sameDoFamily;
@@ -113405,7 +115614,9 @@ exports.startReachabilityPoll = startReachabilityPoll;
113405
115614
  exports.stateLabel = stateLabel;
113406
115615
  exports.stateVocabularyFor = stateVocabularyFor;
113407
115616
  exports.stepModelRunsOnFormat = stepModelRunsOnFormat;
115617
+ exports.stepPulse = stepPulse;
113408
115618
  exports.stepSettingSource = stepSettingSource;
115619
+ exports.stepSpan = stepSpan;
113409
115620
  exports.storageAdminCapability = storageAdminCapability;
113410
115621
  exports.storageCapability = storageCapability;
113411
115622
  exports.storageEvictableCapability = storageEvictableCapability;
@@ -113523,6 +115734,7 @@ exports.withLocationMode = withLocationMode;
113523
115734
  exports.withSystemEventClasses = withSystemEventClasses;
113524
115735
  exports.withoutCallerStamp = require_sleep.withoutCallerStamp;
113525
115736
  exports.withoutField = withoutField;
115737
+ exports.withoutKeyedArrayItem = withoutKeyedArrayItem;
113526
115738
  exports.writeModelBoundSetting = writeModelBoundSetting;
113527
115739
  exports.zodEntriesToConfigUI = zodEntriesToConfigUI;
113528
115740
  exports.zoneAnalyticsCapability = zoneAnalyticsCapability;