@camstack/types 1.2.406 → 1.2.408

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 (45) hide show
  1. package/dist/capabilities/battery.cap.d.ts +46 -0
  2. package/dist/capabilities/capability-definition.d.ts +8 -0
  3. package/dist/capabilities/composer.cap.d.ts +22 -0
  4. package/dist/capabilities/consumables.cap.d.ts +110 -0
  5. package/dist/capabilities/customize-catalog.d.ts +72 -0
  6. package/dist/capabilities/customize-spec.d.ts +202 -0
  7. package/dist/capabilities/doorbell.cap.d.ts +39 -0
  8. package/dist/capabilities/index.d.ts +3 -3
  9. package/dist/capabilities/motion.cap.d.ts +39 -0
  10. package/dist/capabilities/running-state.cap.d.ts +68 -4
  11. package/dist/catalogs/sensor-active-state.d.ts +1 -1
  12. package/dist/client.js +1 -1
  13. package/dist/client.mjs +1 -1
  14. package/dist/composition/customize/__fixtures__/refs.d.ts +27 -0
  15. package/dist/composition/customize/__fixtures__/stored-cases.d.ts +13 -0
  16. package/dist/composition/customize/event-compile.d.ts +20 -0
  17. package/dist/composition/customize/event-decode.d.ts +19 -0
  18. package/dist/composition/customize/event-eval.d.ts +35 -0
  19. package/dist/composition/customize/event-status.d.ts +49 -0
  20. package/dist/composition/customize/field-source.d.ts +5 -0
  21. package/dist/composition/customize/keyed-array-compile.d.ts +26 -0
  22. package/dist/composition/customize/keyed-array-decode.d.ts +20 -0
  23. package/dist/composition/customize/keyed-array-expr.d.ts +10 -0
  24. package/dist/composition/customize/keyed-array-status.d.ts +22 -0
  25. package/dist/composition/customize/normalize.d.ts +4 -0
  26. package/dist/composition/customize/override-draft.d.ts +311 -0
  27. package/dist/composition/customize/scalar-compile.d.ts +13 -0
  28. package/dist/composition/customize/scalar-decode.d.ts +17 -0
  29. package/dist/composition/customize/scalar-expr.d.ts +33 -0
  30. package/dist/composition/customize/scalar-status.d.ts +31 -0
  31. package/dist/composition/customize/stored.d.ts +15 -0
  32. package/dist/composition/index.d.ts +0 -1
  33. package/dist/{composition-xz-ud5EQ.mjs → composition-BJ8iAZb3.mjs} +1 -1
  34. package/dist/{composition-RmnnN39T.js → composition-CSLSFGTO.js} +1 -1
  35. package/dist/generated/customize-catalog.d.ts +229 -0
  36. package/dist/index.d.ts +14 -1
  37. package/dist/index.js +2277 -292
  38. package/dist/index.mjs +2254 -288
  39. package/dist/node.js +1 -1
  40. package/dist/node.mjs +1 -1
  41. package/dist/running-state/defaults.d.ts +3 -0
  42. package/dist/running-state/from-operation.d.ts +4 -4
  43. package/package.json +1 -1
  44. package/dist/composition/presets/doorbell-feature.d.ts +0 -20
  45. package/dist/running-state/assignment.d.ts +0 -34
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_sleep = require("./sleep-UP964hNP.js");
3
3
  const require_event_category = require("./event-category-DG6Vir8Z.js");
4
- const require_composition = require("./composition-RmnnN39T.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");
@@ -12766,6 +12766,13 @@ var ComposerUnreadableBlockSchema = zod.z.object({
12766
12766
  /** The parse error, in the operator's words. */
12767
12767
  error: zod.z.string()
12768
12768
  });
12769
+ /** A confirmed release the hub did not accept. `deviceId` is the claim's device. */
12770
+ var UnreleasedClaimSchema = zod.z.object({
12771
+ deviceId: zod.z.number().int(),
12772
+ capName: zod.z.string(),
12773
+ owner: zod.z.string(),
12774
+ error: zod.z.string()
12775
+ });
12769
12776
  var ComposerApplyInputSchema = zod.z.object({
12770
12777
  /** The shared Blocks integration; null until `core-blocks` has reconciled it. */
12771
12778
  integrationId: zod.z.string().nullable(),
@@ -12775,7 +12782,13 @@ var ComposerApplyInputSchema = zod.z.object({
12775
12782
  /** Operator restarts: rebuild these runtimes and re-resolve their sources. Stores nothing (D62). */
12776
12783
  restartBlockIds: zod.z.array(zod.z.string()),
12777
12784
  /** Composition rows that exist but do not parse: held, never withdrawn, reported failed. */
12778
- unreadableBlocks: zod.z.array(ComposerUnreadableBlockSchema)
12785
+ unreadableBlocks: zod.z.array(ComposerUnreadableBlockSchema),
12786
+ /**
12787
+ * Operator-confirmed deletions. Their claims are released on this apply,
12788
+ * before any replacement block claims. A block that merely vanished from the
12789
+ * snapshot is not listed here and still waits for two applies (D49).
12790
+ */
12791
+ retiredBlockIds: zod.z.array(zod.z.string()).optional()
12779
12792
  });
12780
12793
  var ComposerBlockVerdictSchema = zod.z.object({
12781
12794
  blockId: zod.z.string(),
@@ -12789,7 +12802,13 @@ var ComposerApplyResultSchema = zod.z.object({
12789
12802
  * integration unknown, its own rows unread or read empty once). An empty
12790
12803
  * apply the caller owes is paid off only by one the composer acted on (D49).
12791
12804
  */
12792
- acted: zod.z.boolean()
12805
+ acted: zod.z.boolean(),
12806
+ /**
12807
+ * Confirmed releases this apply tried and the hub did not accept. Empty when
12808
+ * every one landed (or there was nothing to hand back). Absent on a result
12809
+ * that never got that far.
12810
+ */
12811
+ unreleasedClaims: zod.z.array(UnreleasedClaimSchema).optional()
12793
12812
  });
12794
12813
  var composerCapability = {
12795
12814
  name: "composer",
@@ -60326,20 +60345,68 @@ var BatteryStatusSchema = zod.z.object({
60326
60345
  */
60327
60346
  binary: zod.z.boolean().optional()
60328
60347
  });
60348
+ var BATTERY_DEVICE_TYPES = [
60349
+ require_err_msg.DeviceType.Camera,
60350
+ require_err_msg.DeviceType.Sensor,
60351
+ require_err_msg.DeviceType.Button,
60352
+ require_err_msg.DeviceType.Switch,
60353
+ require_err_msg.DeviceType.PetFeeder,
60354
+ require_err_msg.DeviceType.Container,
60355
+ require_err_msg.DeviceType.Thermostat
60356
+ ];
60357
+ /** Generic Customize target for the percentage reading (D936). */
60358
+ var batteryCustomize = {
60359
+ version: 1,
60360
+ targets: [{
60361
+ id: "percentage",
60362
+ cardinality: "scalar",
60363
+ vocabulary: {
60364
+ cap: "battery",
60365
+ stateField: "percentage"
60366
+ },
60367
+ deviceTypes: BATTERY_DEVICE_TYPES,
60368
+ apply: "add-or-replace",
60369
+ path: "percentage",
60370
+ sources: [{
60371
+ kind: "field",
60372
+ valueKinds: ["number", "string"],
60373
+ transforms: [{ kind: "identity" }, {
60374
+ kind: "linear",
60375
+ defaultScale: 1,
60376
+ defaultOffset: 0,
60377
+ clampMin: 0,
60378
+ clampMax: 100
60379
+ }]
60380
+ }],
60381
+ companions: [
60382
+ {
60383
+ kind: "constant",
60384
+ path: "charging",
60385
+ value: "unknown",
60386
+ when: "add"
60387
+ },
60388
+ {
60389
+ kind: "constant",
60390
+ path: "sleeping",
60391
+ value: false,
60392
+ when: "add"
60393
+ },
60394
+ {
60395
+ kind: "clock",
60396
+ path: "lastUpdated",
60397
+ when: "add"
60398
+ }
60399
+ ],
60400
+ sourceReport: { status: "assignment-status" },
60401
+ advancedExpression: true
60402
+ }]
60403
+ };
60329
60404
  var batteryCapability = {
60330
60405
  name: "battery",
60331
60406
  scope: "device",
60332
60407
  deviceNative: true,
60333
60408
  mode: "singleton",
60334
- deviceTypes: [
60335
- require_err_msg.DeviceType.Camera,
60336
- require_err_msg.DeviceType.Sensor,
60337
- require_err_msg.DeviceType.Button,
60338
- require_err_msg.DeviceType.Switch,
60339
- require_err_msg.DeviceType.PetFeeder,
60340
- require_err_msg.DeviceType.Container,
60341
- require_err_msg.DeviceType.Thermostat
60342
- ],
60409
+ deviceTypes: BATTERY_DEVICE_TYPES,
60343
60410
  methods: {
60344
60411
  /**
60345
60412
  * Explicitly wake the camera from low-power sleep ahead of a
@@ -60423,6 +60490,7 @@ onStatusChanged: { data: zod.z.object({
60423
60490
  kind: "gauge",
60424
60491
  unit: "%"
60425
60492
  } } },
60493
+ customize: batteryCustomize,
60426
60494
  /** Clock fields: written, but excluded from the compare that decides
60427
60495
  * whether persisting is worth a SQLite commit. */
60428
60496
  volatileStateFields: ["lastUpdated"]
@@ -61621,6 +61689,106 @@ var ConsumablesStatusSchema = zod.z.object({
61621
61689
  items: zod.z.array(ConsumableItemSchema),
61622
61690
  lastChangedAt: zod.z.number()
61623
61691
  });
61692
+ /** Synthesize seed for a link-built status (no native provider).
61693
+ *
61694
+ * ⚠ NO LIVE CALLER since 2026-08-08 (device-links deleted; see
61695
+ * `CapabilityStatusSchema.empty`). The wiring guidance below was written for
61696
+ * exactly the case the operator is asking about again — a Dreame's HA
61697
+ * consumable-life sensors — so it is kept for that conversation, not because
61698
+ * anything reads it today. */
61699
+ var EMPTY_STATUS = {
61700
+ items: [],
61701
+ lastChangedAt: 0
61702
+ };
61703
+ /** Seed for a NEW link-built consumable item. `key`/`label` are overwritten
61704
+ * with the link's `itemKey` (see `status.itemArray`), so the placeholder
61705
+ * empty strings never survive into a validated item. Link-built items are
61706
+ * not resettable — there is no native provider to receive `reset()`.
61707
+ *
61708
+ * Wiring guidance (HA vacuum consumable-life sensors):
61709
+ * - a percent-remaining source (`numeric-sensor`, unit '%') → `level` via
61710
+ * `identity` (or `linear` scale 1 offset 0 clamp [0,100] to be safe);
61711
+ * - an hours-remaining source (e.g. Dreame 'Main Brush Time Left', unit 'h')
61712
+ * → `level` via `linear` with scale = 100 / max-hours for that item
61713
+ * (e.g. main brush 300 h → scale 0.3333) + clamp [0,100];
61714
+ * - a discrete source (`enum-sensor`, e.g. mop pad 'installed') → `status`
61715
+ * via `enum-map` (e.g. { installed: 'ok', missing: 'replace' }).
61716
+ * A numeric→'replace' THRESHOLD (level < 10 → 'replace') is NOT expressible
61717
+ * with the current transform kinds — leave `status` null (valid) until the
61718
+ * expression transform lands. */
61719
+ /** Generic Customize target for one consumable item (D936). Native rows stay read-only. */
61720
+ var consumablesCustomize = {
61721
+ version: 1,
61722
+ targets: [{
61723
+ id: "items",
61724
+ cardinality: "keyedArray",
61725
+ vocabulary: { cap: "consumables" },
61726
+ deviceTypes: Object.values(require_err_msg.DeviceType),
61727
+ apply: "add",
61728
+ path: "items",
61729
+ keyField: "key",
61730
+ labelField: "label",
61731
+ itemSchema: ConsumableItemSchema,
61732
+ nativeItems: "read-only",
61733
+ sourceReport: { status: "assignment-status" },
61734
+ fields: [
61735
+ {
61736
+ path: "level",
61737
+ sources: [{
61738
+ kind: "numeric",
61739
+ transforms: [{ kind: "identity" }, {
61740
+ kind: "linear",
61741
+ defaultScale: 1,
61742
+ defaultOffset: 0,
61743
+ clampMin: 0,
61744
+ clampMax: 100
61745
+ }]
61746
+ }]
61747
+ },
61748
+ {
61749
+ path: "remaining.value",
61750
+ sources: [{
61751
+ kind: "numeric",
61752
+ transforms: [{ kind: "identity" }]
61753
+ }],
61754
+ literals: [{
61755
+ path: "remaining.unit",
61756
+ values: [...ConsumableRemainingUnitSchema.options]
61757
+ }]
61758
+ },
61759
+ {
61760
+ path: "status",
61761
+ sources: [{
61762
+ kind: "enum",
61763
+ transforms: [{
61764
+ kind: "enum-map",
61765
+ outputValues: [...ConsumableStatusSchema.options],
61766
+ unmapped: null
61767
+ }]
61768
+ }]
61769
+ }
61770
+ ],
61771
+ traits: [{
61772
+ path: "kind",
61773
+ values: [...ConsumableKindSchema.options],
61774
+ defaultValue: "wear"
61775
+ }, {
61776
+ path: "form",
61777
+ values: [...ConsumableFormSchema.options],
61778
+ defaultValue: "part"
61779
+ }],
61780
+ companions: [{
61781
+ kind: "clock",
61782
+ path: "lastChangedAt",
61783
+ when: "add"
61784
+ }, {
61785
+ kind: "clock",
61786
+ path: "lastFetchedAt",
61787
+ when: "add"
61788
+ }],
61789
+ advancedExpression: true
61790
+ }]
61791
+ };
61624
61792
  var consumablesCapability = {
61625
61793
  name: "consumables",
61626
61794
  scope: "device",
@@ -61658,10 +61826,7 @@ reset: require_sleep.method(zod.z.object({
61658
61826
  status: {
61659
61827
  schema: ConsumablesStatusSchema,
61660
61828
  kind: "push",
61661
- empty: {
61662
- items: [],
61663
- lastChangedAt: 0
61664
- },
61829
+ empty: EMPTY_STATUS,
61665
61830
  itemArray: {
61666
61831
  path: "items",
61667
61832
  keyField: "key",
@@ -61697,6 +61862,7 @@ reset: require_sleep.method(zod.z.object({
61697
61862
  * brush's remaining life and a dishwasher's salt are each recorded the moment
61698
61863
  * their provider reports them; an item that appears later gets its series.
61699
61864
  */
61865
+ customize: consumablesCustomize,
61700
61866
  history: {
61701
61867
  fields: {},
61702
61868
  items: {
@@ -62499,6 +62665,38 @@ var dishwasherCapability = {
62499
62665
  };
62500
62666
  //#endregion
62501
62667
  //#region src/capabilities/doorbell.cap.ts
62668
+ /** A rise closer than this to the previous one is the same press (D671). */
62669
+ var DOORBELL_RISE_DEBOUNCE_MS = 2e3;
62670
+ /** Pulse override: a rising edge advances `lastPressedAt` and the press count. */
62671
+ var doorbellCustomize = {
62672
+ version: 1,
62673
+ targets: [{
62674
+ id: "pressed",
62675
+ cardinality: "event",
62676
+ shape: "pulse",
62677
+ vocabulary: {
62678
+ cap: "doorbell",
62679
+ eventName: "onPressed"
62680
+ },
62681
+ deviceTypes: [require_err_msg.DeviceType.Camera],
62682
+ apply: "add",
62683
+ applyAuthority: { kind: "composition-claim" },
62684
+ eventName: "onPressed",
62685
+ edges: ["rising"],
62686
+ timestampPath: "lastPressedAt",
62687
+ counterPath: "pressCountSinceStart",
62688
+ highWater: "composer-advance",
62689
+ combine: "any",
62690
+ debounce: {
62691
+ kind: "rising-edge",
62692
+ defaultDebounceMs: DOORBELL_RISE_DEBOUNCE_MS,
62693
+ changedAtRequired: true
62694
+ },
62695
+ sources: [{ kind: "binary" }, { kind: "switch" }],
62696
+ sourceReport: { status: "assignment-status" },
62697
+ advancedExpression: true
62698
+ }]
62699
+ };
62502
62700
  var DoorbellStatusSchema = zod.z.object({
62503
62701
  /** Ms epoch of the last press. null = never observed since this provider started. */
62504
62702
  lastPressedAt: zod.z.number().nullable(),
@@ -62565,7 +62763,8 @@ onPressed: {
62565
62763
  /**
62566
62764
  * History (D850): none — `pressCountSinceStart` resets with the addon, so it is not a monotonic meter; presses live in the events ledger.
62567
62765
  */
62568
- history: "none"
62766
+ history: "none",
62767
+ customize: doorbellCustomize
62569
62768
  };
62570
62769
  //#endregion
62571
62770
  //#region src/capabilities/enum-sensor.cap.ts
@@ -65312,6 +65511,44 @@ authKey: zod.z.string().optional() }), zod.z.object({
65312
65511
  //#endregion
65313
65512
  //#region src/capabilities/motion.cap.ts
65314
65513
  /**
65514
+ * Span timeout for a camera's attached sensors. This is the pipeline-runner
65515
+ * `motionCooldownMs` default: the window after which a heartbeat-only edge
65516
+ * no longer counts. The span does not declare a separate cooldown.
65517
+ */
65518
+ var MOTION_SPAN_TIMEOUT_MS = 3e4;
65519
+ /** Span override: start on a rising edge, end on a fall or this timeout. */
65520
+ var motionCustomize = {
65521
+ version: 1,
65522
+ targets: [{
65523
+ id: "detected",
65524
+ cardinality: "event",
65525
+ shape: "span",
65526
+ vocabulary: {
65527
+ cap: "motion",
65528
+ eventName: "onMotionChanged"
65529
+ },
65530
+ deviceTypes: [require_err_msg.DeviceType.Camera],
65531
+ apply: "replace",
65532
+ applyAuthority: {
65533
+ kind: "camera-sensors",
65534
+ timeoutField: "motionCooldownMs"
65535
+ },
65536
+ eventName: "onMotionChanged",
65537
+ start: "rising-edge",
65538
+ end: "falling-edge-or-timeout",
65539
+ timeoutMs: MOTION_SPAN_TIMEOUT_MS,
65540
+ combine: "any",
65541
+ sourceModes: [
65542
+ "in-addition",
65543
+ "confirm",
65544
+ "replace"
65545
+ ],
65546
+ sources: [{ kind: "binary" }, { kind: "switch" }],
65547
+ sourceReport: { status: "assignment-status" },
65548
+ advancedExpression: false
65549
+ }]
65550
+ };
65551
+ /**
65315
65552
  * Hardware / firmware motion sensor cap — binary detected state plus
65316
65553
  * a timestamp of the last observation. Distinct from
65317
65554
  * `motion-detection.cap.ts` which owns the LOCAL ML motion pipeline;
@@ -65475,7 +65712,8 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
65475
65712
  history: { fields: { detected: {
65476
65713
  kind: "boolean",
65477
65714
  excludeDeviceTypes: [require_err_msg.DeviceType.Camera]
65478
- } } }
65715
+ } } },
65716
+ customize: motionCustomize
65479
65717
  };
65480
65718
  //#endregion
65481
65719
  //#region src/capabilities/motion-trigger.cap.ts
@@ -69589,6 +69827,19 @@ var ptzAutotrackCapability = {
69589
69827
  history: "none"
69590
69828
  };
69591
69829
  //#endregion
69830
+ //#region src/running-state/defaults.ts
69831
+ var RUNNING_POWER_THRESHOLD_WATTS = 5;
69832
+ var RUNNING_POWER_START_DELAY_MS = 3e4;
69833
+ var RUNNING_POWER_STOP_DELAY_MS = 18e4;
69834
+ /** Before any provider reading — all fields unknown (D933). */
69835
+ var RUNNING_STATE_COLD = {
69836
+ running: null,
69837
+ since: null,
69838
+ source: "native",
69839
+ phase: null,
69840
+ lastFetchedAt: null
69841
+ };
69842
+ //#endregion
69592
69843
  //#region src/capabilities/running-state.cap.ts
69593
69844
  var RunningStateSourceSchema = zod.z.enum(["native", "assigned"]);
69594
69845
  var RunningStateStatusSchema = zod.z.object({
@@ -69598,19 +69849,100 @@ var RunningStateStatusSchema = zod.z.object({
69598
69849
  since: zod.z.number().nullable(),
69599
69850
  source: RunningStateSourceSchema,
69600
69851
  phase: zod.z.string().nullable(),
69601
- lastFetchedAt: zod.z.number()
69852
+ /** null until a reading has been published (D393). */
69853
+ lastFetchedAt: zod.z.number().nullable()
69602
69854
  });
69603
69855
  var RunningFlipEventDataSchema = zod.z.object({
69604
69856
  deviceId: zod.z.number(),
69605
69857
  since: zod.z.number().nullable(),
69606
69858
  phase: zod.z.string().nullable()
69607
69859
  });
69860
+ var RUNNING_DEVICE_TYPES = Object.values(require_err_msg.DeviceType);
69861
+ /** Generic Customize target for the running boolean (D936). */
69862
+ var runningCustomize = {
69863
+ version: 1,
69864
+ targets: [{
69865
+ id: "running",
69866
+ cardinality: "scalar",
69867
+ vocabulary: {
69868
+ cap: "running-state",
69869
+ stateField: "running"
69870
+ },
69871
+ deviceTypes: [
69872
+ require_err_msg.DeviceType.Dishwasher,
69873
+ require_err_msg.DeviceType.Vacuum,
69874
+ require_err_msg.DeviceType.LawnMower,
69875
+ require_err_msg.DeviceType.MediaPlayer,
69876
+ require_err_msg.DeviceType.WaterHeater,
69877
+ require_err_msg.DeviceType.Humidifier,
69878
+ require_err_msg.DeviceType.Fan,
69879
+ require_err_msg.DeviceType.Climate,
69880
+ require_err_msg.DeviceType.Thermostat,
69881
+ require_err_msg.DeviceType.PetFeeder
69882
+ ],
69883
+ apply: "add-or-replace",
69884
+ path: "running",
69885
+ sources: [
69886
+ {
69887
+ kind: "switch",
69888
+ transforms: [{ kind: "identity" }]
69889
+ },
69890
+ {
69891
+ kind: "binary",
69892
+ transforms: [{ kind: "identity" }, { kind: "invert" }]
69893
+ },
69894
+ {
69895
+ kind: "numeric",
69896
+ requiredUnit: "W",
69897
+ transforms: [{
69898
+ kind: "threshold",
69899
+ comparison: "gte",
69900
+ defaultThreshold: 5,
69901
+ defaultStartDwellMs: RUNNING_POWER_START_DELAY_MS,
69902
+ defaultStopDwellMs: RUNNING_POWER_STOP_DELAY_MS,
69903
+ thresholdUnit: "W"
69904
+ }]
69905
+ }
69906
+ ],
69907
+ companions: [
69908
+ {
69909
+ kind: "constant",
69910
+ path: "source",
69911
+ value: "assigned",
69912
+ when: "always"
69913
+ },
69914
+ {
69915
+ kind: "constant",
69916
+ path: "phase",
69917
+ value: null,
69918
+ when: "always"
69919
+ },
69920
+ {
69921
+ kind: "clock",
69922
+ path: "lastFetchedAt",
69923
+ when: "always"
69924
+ },
69925
+ {
69926
+ kind: "transition-time",
69927
+ path: "since",
69928
+ sourceChangedAt: "prefer"
69929
+ }
69930
+ ],
69931
+ sourceReport: {
69932
+ status: "assignment-status",
69933
+ runtimeField: "source",
69934
+ nativeValue: "native",
69935
+ assignedValue: "assigned"
69936
+ },
69937
+ advancedExpression: true
69938
+ }]
69939
+ };
69608
69940
  var runningStateCapability = {
69609
69941
  name: "running-state",
69610
69942
  scope: "device",
69611
69943
  deviceNative: true,
69612
69944
  mode: "singleton",
69613
- deviceTypes: Object.values(require_err_msg.DeviceType),
69945
+ deviceTypes: RUNNING_DEVICE_TYPES,
69614
69946
  methods: {},
69615
69947
  events: {
69616
69948
  onStarted: { data: RunningFlipEventDataSchema },
@@ -69623,7 +69955,8 @@ var runningStateCapability = {
69623
69955
  runtimeState: RunningStateStatusSchema,
69624
69956
  durability: "restored",
69625
69957
  history: { fields: { running: { kind: "boolean" } } },
69626
- volatileStateFields: ["lastFetchedAt"]
69958
+ volatileStateFields: ["lastFetchedAt"],
69959
+ customize: runningCustomize
69627
69960
  };
69628
69961
  //#endregion
69629
69962
  //#region src/capabilities/reboot.cap.ts
@@ -75852,213 +76185,58 @@ var PIPELINE_OWNER_CAPABILITY_NAMES = [
75852
76185
  "pipeline-runner"
75853
76186
  ];
75854
76187
  //#endregion
75855
- //#region src/running-state/assignment.ts
75856
- function constant(literal) {
75857
- return {
75858
- kind: "expression",
75859
- expr: literal,
75860
- bindings: {}
75861
- };
75862
- }
75863
- function fromRead(source, cap, fieldPath) {
75864
- return {
75865
- kind: "from",
75866
- source,
75867
- cap,
75868
- fieldPath
75869
- };
75870
- }
75871
- function sortKeys(value) {
75872
- if (Array.isArray(value)) return value.map(sortKeys);
75873
- if (typeof value !== "object" || value === null) return value;
75874
- return Object.fromEntries(Object.entries(value).toSorted(([a], [b]) => a.localeCompare(b)).map(([key, inner]) => [key, sortKeys(inner)]));
75875
- }
75876
- function sameFeature(a, b) {
75877
- return JSON.stringify(sortKeys(a)) === JSON.stringify(sortKeys(b));
75878
- }
75879
- function booleanRunningField(input) {
75880
- if (input.source.kind !== "boolean") return null;
75881
- const read = fromRead(input.source.source, input.source.cap, input.source.fieldPath);
75882
- if (!input.invert) return read;
75883
- return {
75884
- kind: "expression",
75885
- expr: "!x",
75886
- bindings: { x: read }
75887
- };
75888
- }
75889
- function sinceField(input) {
75890
- if (input.source.kind === "boolean" && input.changedAtField !== null) return fromRead(input.source.source, input.source.cap, input.changedAtField);
75891
- return {
75892
- kind: "expression",
75893
- expr: "latchedAt(running)",
75894
- bindings: { running: fromRead(input.target, "running-state", "running") }
75895
- };
75896
- }
75897
- function powerRunningField(input) {
75898
- if (input.source.kind !== "number") return null;
75899
- if (!Number.isFinite(input.thresholdWatts) || !Number.isFinite(input.startDelayMs) || !Number.isFinite(input.stopDelayMs) || input.thresholdWatts < 0 || input.startDelayMs < 0 || input.stopDelayMs < 0) return null;
75900
- const read = fromRead(input.source.source, input.source.cap, input.source.fieldPath);
75901
- return {
75902
- kind: "expression",
75903
- expr: `dwell(x >= ${input.thresholdWatts}, ${input.startDelayMs}, ${input.stopDelayMs})`,
75904
- bindings: { x: read }
75905
- };
75906
- }
75907
- function runningAssignmentFeature(input) {
75908
- const running = input.source.kind === "number" ? powerRunningField(input) : booleanRunningField(input);
75909
- if (running === null) return null;
75910
- return {
75911
- kind: "fields",
75912
- cap: "running-state",
75913
- fields: {
75914
- source: constant("\"assigned\""),
75915
- phase: constant("null"),
75916
- lastFetchedAt: constant("now"),
75917
- running,
75918
- since: sinceField(input)
75919
- }
75920
- };
75921
- }
75922
- function booleanSourceFromRunningField(source) {
75923
- if (source === void 0) return null;
75924
- if (source.kind === "from") return {
75925
- source: source.source,
75926
- cap: source.cap,
75927
- fieldPath: source.fieldPath,
75928
- kind: "boolean"
75929
- };
75930
- if (source.kind !== "expression" || source.expr !== "!x") return null;
75931
- const x = source.bindings["x"];
75932
- if (x === void 0 || x.kind !== "from") return null;
75933
- return {
75934
- source: x.source,
75935
- cap: x.cap,
75936
- fieldPath: x.fieldPath,
75937
- kind: "boolean"
75938
- };
75939
- }
75940
- function recoverPowerRunning(running) {
75941
- if (running === void 0 || running.kind !== "expression") return null;
75942
- const match = /^dwell\(x >= ([\d.]+), (\d+), (\d+)\)$/.exec(running.expr);
75943
- if (match === null) return null;
75944
- const x = running.bindings["x"];
75945
- if (x === void 0 || x.kind !== "from") return null;
75946
- const thresholdWatts = Number(match[1]);
75947
- const startDelayMs = Number(match[2]);
75948
- const stopDelayMs = Number(match[3]);
75949
- if (!Number.isFinite(thresholdWatts) || !Number.isFinite(startDelayMs) || !Number.isFinite(stopDelayMs)) return null;
75950
- return {
75951
- source: {
75952
- ...x,
75953
- kind: "number"
75954
- },
75955
- invert: false,
75956
- thresholdWatts,
75957
- startDelayMs,
75958
- stopDelayMs
75959
- };
75960
- }
75961
- /** Recover what {@link runningAssignmentFeature} wrote, else null. */
75962
- function runningAssignmentRecovered(stored, target) {
75963
- if (stored.cap !== "running-state" || stored.kind !== "fields") return null;
75964
- const power = recoverPowerRunning(stored.fields["running"]);
75965
- if (power !== null) return power;
75966
- const booleanSource = booleanSourceFromRunningField(stored.fields["running"]);
75967
- if (booleanSource === null) return null;
75968
- const since = stored.fields["since"];
75969
- let changedAtField = null;
75970
- if (since?.kind === "from" && since.cap === booleanSource.cap && since.source.addonId === booleanSource.source.addonId && since.source.stableId === booleanSource.source.stableId) changedAtField = since.fieldPath;
75971
- const rebuilt = runningAssignmentFeature({
75972
- mode: "replace",
75973
- target,
75974
- source: booleanSource,
75975
- changedAtField,
75976
- invert: stored.fields["running"]?.kind === "expression" && stored.fields["running"].expr === "!x",
75977
- thresholdWatts: 0,
75978
- startDelayMs: 0,
75979
- stopDelayMs: 0
75980
- });
75981
- if (rebuilt === null) return null;
75982
- const { enabled: _e, ...rest } = stored;
75983
- if (!sameFeature(rest, rebuilt)) return null;
75984
- return {
75985
- source: booleanSource,
75986
- invert: stored.fields["running"]?.kind === "expression" && stored.fields["running"].expr === "!x",
75987
- thresholdWatts: 0,
75988
- startDelayMs: 0,
75989
- stopDelayMs: 0
75990
- };
75991
- }
75992
- function isRunningAssignmentFeature(stored, mode, target) {
75993
- const recovered = runningAssignmentRecovered(stored, target);
75994
- if (recovered === null) return false;
75995
- const rebuilt = recovered.source.kind === "number" ? runningAssignmentFeature({
75996
- mode,
75997
- target,
75998
- source: recovered.source,
75999
- changedAtField: null,
76000
- invert: false,
76001
- thresholdWatts: recovered.thresholdWatts,
76002
- startDelayMs: recovered.startDelayMs,
76003
- stopDelayMs: recovered.stopDelayMs
76004
- }) : runningAssignmentFeature({
76005
- mode,
76006
- target,
76007
- source: recovered.source,
76008
- changedAtField: stored.fields["since"]?.kind === "from" ? stored.fields["since"].fieldPath : null,
76009
- invert: recovered.invert,
76010
- thresholdWatts: 0,
76011
- startDelayMs: 0,
76012
- stopDelayMs: 0
76013
- });
76014
- if (rebuilt === null) return false;
76015
- const { enabled: _enabled, ...rest } = stored;
76016
- return sameFeature(rest, rebuilt);
76017
- }
76018
- //#endregion
76019
- //#region src/running-state/defaults.ts
76020
- var RUNNING_POWER_THRESHOLD_WATTS = 5;
76021
- var RUNNING_POWER_START_DELAY_MS = 3e4;
76022
- var RUNNING_POWER_STOP_DELAY_MS = 18e4;
76023
- //#endregion
76024
76188
  //#region src/running-state/from-operation.ts
76025
- function resolveSince(running, previous, sinceMs) {
76189
+ function programStartFromRemaining(running, remainingSeconds, fetchedAt) {
76190
+ if (!running || remainingSeconds === null || remainingSeconds === void 0) return null;
76191
+ if (remainingSeconds <= 0) return null;
76192
+ return fetchedAt - remainingSeconds * 1e3;
76193
+ }
76194
+ function resolveSince(running, previous, transitionAtMs, bootstrapSinceMs) {
76026
76195
  if (running === null) return null;
76027
- if ((previous?.running ?? null) !== running) return sinceMs;
76028
- return previous?.since ?? sinceMs;
76196
+ const prevRunning = previous?.running ?? null;
76197
+ if (prevRunning === null) return bootstrapSinceMs;
76198
+ if (prevRunning !== running) return transitionAtMs;
76199
+ return previous?.since ?? null;
76029
76200
  }
76030
- function nativeSlice(running, phase, previous, sinceMs, now) {
76201
+ function nativeSlice(running, phase, previous, transitionAtMs, fetchedAt, bootstrapSinceMs) {
76031
76202
  return {
76032
76203
  running,
76033
- since: resolveSince(running, previous, sinceMs),
76204
+ since: resolveSince(running, previous, transitionAtMs, bootstrapSinceMs),
76034
76205
  source: "native",
76035
76206
  phase: running === null ? null : phase,
76036
- lastFetchedAt: now
76207
+ lastFetchedAt: fetchedAt
76037
76208
  };
76038
76209
  }
76039
- function runningFromDishwasherOperation(operation, program, previous, now) {
76040
- if (operation === null) return nativeSlice(null, null, previous, now, now);
76041
- if (operation === "Run" || operation === "Aborting") return nativeSlice(true, program ?? operation, previous, now, now);
76042
- if (operation === "Pause") return nativeSlice(false, "Pause", previous, now, now);
76043
- return nativeSlice(false, operation, previous, now, now);
76044
- }
76045
- function runningFromVacuumState(state, previous, now) {
76046
- if (state === null) return nativeSlice(null, null, previous, now, now);
76047
- if (state === "cleaning" || state === "returning" || state === "drying") return nativeSlice(true, state, previous, now, now);
76048
- if (state === "paused") return nativeSlice(false, "paused", previous, now, now);
76049
- return nativeSlice(false, state, previous, now, now);
76050
- }
76051
- function runningFromLawnMower(activity, previous, now) {
76052
- if (activity === null) return nativeSlice(null, null, previous, now, now);
76053
- if (activity === "mowing") return nativeSlice(true, activity, previous, now, now);
76054
- if (activity === "paused") return nativeSlice(false, "paused", previous, now, now);
76055
- return nativeSlice(false, activity, previous, now, now);
76056
- }
76057
- function runningFromMediaPlayer(state, previous, now) {
76058
- if (state === null) return nativeSlice(null, null, previous, now, now);
76059
- if (state === "playing" || state === "buffering") return nativeSlice(true, state, previous, now, now);
76060
- if (state === "paused") return nativeSlice(false, "paused", previous, now, now);
76061
- return nativeSlice(false, state, previous, now, now);
76210
+ function runningFromDishwasherOperation(operation, program, previous, fetchedAt, remainingSeconds, transitionAt) {
76211
+ const transitionAtMs = transitionAt ?? fetchedAt;
76212
+ if (operation === null) return nativeSlice(null, null, previous, transitionAtMs, fetchedAt, null);
76213
+ if (operation === "Run" || operation === "Aborting") {
76214
+ const bootstrap = programStartFromRemaining(true, remainingSeconds, fetchedAt);
76215
+ return nativeSlice(true, program ?? operation, previous, transitionAtMs, fetchedAt, bootstrap);
76216
+ }
76217
+ if (operation === "Pause") return nativeSlice(false, "Pause", previous, transitionAtMs, fetchedAt, null);
76218
+ return nativeSlice(false, operation, previous, transitionAtMs, fetchedAt, null);
76219
+ }
76220
+ function runningFromVacuumState(state, previous, fetchedAt, transitionAt) {
76221
+ const transitionAtMs = transitionAt ?? fetchedAt;
76222
+ if (state === null) return nativeSlice(null, null, previous, transitionAtMs, fetchedAt, null);
76223
+ if (state === "cleaning" || state === "returning" || state === "drying") return nativeSlice(true, state, previous, transitionAtMs, fetchedAt, null);
76224
+ if (state === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
76225
+ return nativeSlice(false, state, previous, transitionAtMs, fetchedAt, null);
76226
+ }
76227
+ function runningFromLawnMower(activity, previous, fetchedAt, transitionAt) {
76228
+ const transitionAtMs = transitionAt ?? fetchedAt;
76229
+ if (activity === null) return nativeSlice(null, null, previous, transitionAtMs, fetchedAt, null);
76230
+ if (activity === "mowing") return nativeSlice(true, activity, previous, transitionAtMs, fetchedAt, null);
76231
+ if (activity === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
76232
+ return nativeSlice(false, activity, previous, transitionAtMs, fetchedAt, null);
76233
+ }
76234
+ function runningFromMediaPlayer(state, previous, fetchedAt, transitionAt) {
76235
+ const transitionAtMs = transitionAt ?? fetchedAt;
76236
+ if (state === null) return nativeSlice(null, null, previous, transitionAtMs, fetchedAt, null);
76237
+ if (state === "playing" || state === "buffering") return nativeSlice(true, state, previous, transitionAtMs, fetchedAt, null);
76238
+ if (state === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
76239
+ return nativeSlice(false, state, previous, transitionAtMs, fetchedAt, null);
76062
76240
  }
76063
76241
  //#endregion
76064
76242
  //#region src/clips/clip-event-labels.ts
@@ -76950,74 +77128,6 @@ function feederCustomizationExample(sources) {
76950
77128
  });
76951
77129
  }
76952
77130
  //#endregion
76953
- //#region src/composition/presets/doorbell-feature.ts
76954
- /**
76955
- * The doorbell of a camera as a customization (D671). ONE builder: the admin
76956
- * UI's Customize → Doorbell card writes every doorbell feature through it, and
76957
- * edits one only when it is exactly what this builds (`isDoorbellPresetFeature`)
76958
- * — a composed doorbell has one canonical shape.
76959
- */
76960
- /** A rise closer than this to the previous one is the same press (D671). */
76961
- var DOORBELL_RISE_DEBOUNCE_MS = 2e3;
76962
- /** Every source cap of `source` that `SOURCE_CAP_ACTIVE_FIELD` knows AND the device has bound. */
76963
- function doorbellFeatureSources(source, boundCaps) {
76964
- 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) => {
76965
- const activeField = require_composition.SOURCE_CAP_ACTIVE_FIELD[cap];
76966
- const changedAtField = require_composition.SOURCE_CAP_CHANGED_AT_FIELD[cap];
76967
- return activeField === void 0 || changedAtField === void 0 ? [] : [{
76968
- source,
76969
- cap,
76970
- activeField,
76971
- changedAtField
76972
- }];
76973
- });
76974
- }
76975
- /** The canonical D671 doorbell feature. Throws on zero sources. */
76976
- function buildDoorbellCompositionFeature(input) {
76977
- const sources = [...input.sources].toSorted((a, b) => `${a.source.addonId}/${a.source.stableId}#${a.cap}`.localeCompare(`${b.source.addonId}/${b.source.stableId}#${b.cap}`));
76978
- if (sources.length === 0) throw new Error("doorbell composition needs at least one source");
76979
- const edgeBindings = {};
76980
- sources.forEach((entry, index) => {
76981
- edgeBindings[`active${index}`] = {
76982
- kind: "from",
76983
- source: entry.source,
76984
- cap: entry.cap,
76985
- fieldPath: entry.activeField
76986
- };
76987
- edgeBindings[`changed${index}`] = {
76988
- kind: "from",
76989
- source: entry.source,
76990
- cap: entry.cap,
76991
- fieldPath: entry.changedAtField
76992
- };
76993
- });
76994
- return {
76995
- kind: "fields",
76996
- cap: "doorbell",
76997
- enabled: input.enabled,
76998
- fields: {
76999
- lastPressedAt: {
77000
- kind: "expression",
77001
- expr: `latest(${sources.map((_, index) => `rose(active${index}, changed${index}, ${DOORBELL_RISE_DEBOUNCE_MS})`).join(", ")})`,
77002
- bindings: edgeBindings
77003
- },
77004
- pressCountSinceStart: {
77005
- kind: "expression",
77006
- expr: "count(lastPressedAt)",
77007
- bindings: { lastPressedAt: {
77008
- kind: "from",
77009
- source: {
77010
- addonId: input.camera.addonId,
77011
- stableId: input.camera.stableId
77012
- },
77013
- cap: "doorbell",
77014
- fieldPath: "lastPressedAt"
77015
- } }
77016
- }
77017
- }
77018
- };
77019
- }
77020
- //#endregion
77021
77131
  //#region src/composition/presets/numeric-transforms.ts
77022
77132
  /**
77023
77133
  * Self-only invert / unit-convert composition features (D663). The Numeric
@@ -100291,6 +100401,1862 @@ function historyFieldsFor(capName) {
100291
100401
  return HISTORY_CATALOG[capName] ?? {};
100292
100402
  }
100293
100403
  //#endregion
100404
+ //#region src/generated/customize-catalog.ts
100405
+ /**
100406
+ * Customize catalog, projected from every `*.cap.ts` `customize` block.
100407
+ * 5 caps. Field keys are `runtimeState` paths. No Zod.
100408
+ */
100409
+ var CAP_CUSTOMIZE_CATALOG = {
100410
+ "battery": {
100411
+ version: 1,
100412
+ targets: [{
100413
+ id: "percentage",
100414
+ cardinality: "scalar",
100415
+ deviceTypes: [
100416
+ require_err_msg.DeviceType.Camera,
100417
+ require_err_msg.DeviceType.Sensor,
100418
+ require_err_msg.DeviceType.Button,
100419
+ require_err_msg.DeviceType.Switch,
100420
+ require_err_msg.DeviceType.PetFeeder,
100421
+ require_err_msg.DeviceType.Container,
100422
+ require_err_msg.DeviceType.Thermostat
100423
+ ],
100424
+ apply: "add-or-replace",
100425
+ vocabularyCap: "battery",
100426
+ vocabularyStateField: "percentage",
100427
+ sources: [{
100428
+ kind: "field",
100429
+ valueKinds: ["number", "string"],
100430
+ transformKinds: ["identity", "linear"]
100431
+ }],
100432
+ sourceReport: { status: "assignment-status" },
100433
+ advancedExpression: true,
100434
+ path: "percentage",
100435
+ valueKind: "number",
100436
+ nullable: true,
100437
+ companions: [
100438
+ {
100439
+ kind: "constant",
100440
+ path: "charging",
100441
+ value: "unknown",
100442
+ when: "add"
100443
+ },
100444
+ {
100445
+ kind: "constant",
100446
+ path: "sleeping",
100447
+ value: false,
100448
+ when: "add"
100449
+ },
100450
+ {
100451
+ kind: "clock",
100452
+ path: "lastUpdated",
100453
+ when: "add"
100454
+ }
100455
+ ]
100456
+ }]
100457
+ },
100458
+ "consumables": {
100459
+ version: 1,
100460
+ targets: [{
100461
+ id: "items",
100462
+ cardinality: "keyedArray",
100463
+ deviceTypes: [
100464
+ require_err_msg.DeviceType.Camera,
100465
+ require_err_msg.DeviceType.Hub,
100466
+ require_err_msg.DeviceType.Light,
100467
+ require_err_msg.DeviceType.Siren,
100468
+ require_err_msg.DeviceType.Switch,
100469
+ require_err_msg.DeviceType.Sensor,
100470
+ require_err_msg.DeviceType.Thermostat,
100471
+ require_err_msg.DeviceType.Climate,
100472
+ require_err_msg.DeviceType.Button,
100473
+ require_err_msg.DeviceType.EventEmitter,
100474
+ require_err_msg.DeviceType.Update,
100475
+ require_err_msg.DeviceType.Generic,
100476
+ require_err_msg.DeviceType.Notifier,
100477
+ require_err_msg.DeviceType.Script,
100478
+ require_err_msg.DeviceType.Automation,
100479
+ require_err_msg.DeviceType.Lock,
100480
+ require_err_msg.DeviceType.Cover,
100481
+ require_err_msg.DeviceType.Valve,
100482
+ require_err_msg.DeviceType.Humidifier,
100483
+ require_err_msg.DeviceType.WaterHeater,
100484
+ require_err_msg.DeviceType.Fan,
100485
+ require_err_msg.DeviceType.MediaPlayer,
100486
+ require_err_msg.DeviceType.AlarmPanel,
100487
+ require_err_msg.DeviceType.Control,
100488
+ require_err_msg.DeviceType.Presence,
100489
+ require_err_msg.DeviceType.Weather,
100490
+ require_err_msg.DeviceType.Vacuum,
100491
+ require_err_msg.DeviceType.LawnMower,
100492
+ require_err_msg.DeviceType.Container,
100493
+ require_err_msg.DeviceType.Image,
100494
+ require_err_msg.DeviceType.PetFeeder,
100495
+ require_err_msg.DeviceType.Dishwasher
100496
+ ],
100497
+ apply: "add",
100498
+ vocabularyCap: "consumables",
100499
+ sources: [],
100500
+ sourceReport: { status: "assignment-status" },
100501
+ advancedExpression: true,
100502
+ path: "items",
100503
+ keyField: "key",
100504
+ labelField: "label",
100505
+ nativeItems: "read-only",
100506
+ fields: [
100507
+ {
100508
+ path: "level",
100509
+ valueKind: "number",
100510
+ nullable: true,
100511
+ sources: [{
100512
+ kind: "numeric",
100513
+ transformKinds: ["identity", "linear"]
100514
+ }]
100515
+ },
100516
+ {
100517
+ path: "remaining.value",
100518
+ valueKind: "number",
100519
+ nullable: true,
100520
+ sources: [{
100521
+ kind: "numeric",
100522
+ transformKinds: ["identity"]
100523
+ }],
100524
+ literals: [{
100525
+ path: "remaining.unit",
100526
+ values: [
100527
+ "days",
100528
+ "hours",
100529
+ "cycles"
100530
+ ]
100531
+ }]
100532
+ },
100533
+ {
100534
+ path: "status",
100535
+ valueKind: "enum",
100536
+ nullable: true,
100537
+ enumValues: [
100538
+ "ok",
100539
+ "low",
100540
+ "empty",
100541
+ "full",
100542
+ "replace"
100543
+ ],
100544
+ sources: [{
100545
+ kind: "enum",
100546
+ transformKinds: ["enum-map"]
100547
+ }]
100548
+ }
100549
+ ],
100550
+ traits: [{
100551
+ path: "kind",
100552
+ values: [
100553
+ "wear",
100554
+ "supply",
100555
+ "waste"
100556
+ ],
100557
+ defaultValue: "wear"
100558
+ }, {
100559
+ path: "form",
100560
+ values: [
100561
+ "part",
100562
+ "tank",
100563
+ "product",
100564
+ "bin"
100565
+ ],
100566
+ defaultValue: "part"
100567
+ }],
100568
+ companions: [{
100569
+ kind: "clock",
100570
+ path: "lastChangedAt",
100571
+ when: "add"
100572
+ }, {
100573
+ kind: "clock",
100574
+ path: "lastFetchedAt",
100575
+ when: "add"
100576
+ }]
100577
+ }]
100578
+ },
100579
+ "doorbell": {
100580
+ version: 1,
100581
+ targets: [{
100582
+ id: "pressed",
100583
+ cardinality: "event",
100584
+ deviceTypes: [require_err_msg.DeviceType.Camera],
100585
+ apply: "add",
100586
+ vocabularyCap: "doorbell",
100587
+ vocabularyEvent: "onPressed",
100588
+ sources: [{
100589
+ kind: "binary",
100590
+ transformKinds: []
100591
+ }, {
100592
+ kind: "switch",
100593
+ transformKinds: []
100594
+ }],
100595
+ sourceReport: { status: "assignment-status" },
100596
+ advancedExpression: true,
100597
+ shape: "pulse",
100598
+ applyAuthority: { kind: "composition-claim" },
100599
+ eventName: "onPressed",
100600
+ combine: "any",
100601
+ edges: ["rising"],
100602
+ timestampPath: "lastPressedAt",
100603
+ counterPath: "pressCountSinceStart",
100604
+ highWater: "composer-advance",
100605
+ debounceMs: 2e3
100606
+ }]
100607
+ },
100608
+ "motion": {
100609
+ version: 1,
100610
+ targets: [{
100611
+ id: "detected",
100612
+ cardinality: "event",
100613
+ deviceTypes: [require_err_msg.DeviceType.Camera],
100614
+ apply: "replace",
100615
+ vocabularyCap: "motion",
100616
+ vocabularyEvent: "onMotionChanged",
100617
+ sources: [{
100618
+ kind: "binary",
100619
+ transformKinds: []
100620
+ }, {
100621
+ kind: "switch",
100622
+ transformKinds: []
100623
+ }],
100624
+ sourceReport: { status: "assignment-status" },
100625
+ advancedExpression: false,
100626
+ shape: "span",
100627
+ applyAuthority: {
100628
+ kind: "camera-sensors",
100629
+ timeoutField: "motionCooldownMs"
100630
+ },
100631
+ eventName: "onMotionChanged",
100632
+ combine: "any",
100633
+ start: "rising-edge",
100634
+ end: "falling-edge-or-timeout",
100635
+ timeoutMs: 3e4,
100636
+ sourceModes: [
100637
+ "in-addition",
100638
+ "confirm",
100639
+ "replace"
100640
+ ]
100641
+ }]
100642
+ },
100643
+ "running-state": {
100644
+ version: 1,
100645
+ targets: [{
100646
+ id: "running",
100647
+ cardinality: "scalar",
100648
+ deviceTypes: [
100649
+ require_err_msg.DeviceType.Dishwasher,
100650
+ require_err_msg.DeviceType.Vacuum,
100651
+ require_err_msg.DeviceType.LawnMower,
100652
+ require_err_msg.DeviceType.MediaPlayer,
100653
+ require_err_msg.DeviceType.WaterHeater,
100654
+ require_err_msg.DeviceType.Humidifier,
100655
+ require_err_msg.DeviceType.Fan,
100656
+ require_err_msg.DeviceType.Climate,
100657
+ require_err_msg.DeviceType.Thermostat,
100658
+ require_err_msg.DeviceType.PetFeeder
100659
+ ],
100660
+ apply: "add-or-replace",
100661
+ vocabularyCap: "running-state",
100662
+ vocabularyStateField: "running",
100663
+ sources: [
100664
+ {
100665
+ kind: "switch",
100666
+ transformKinds: ["identity"]
100667
+ },
100668
+ {
100669
+ kind: "binary",
100670
+ transformKinds: ["identity", "invert"]
100671
+ },
100672
+ {
100673
+ kind: "numeric",
100674
+ requiredUnit: "W",
100675
+ transformKinds: ["threshold"]
100676
+ }
100677
+ ],
100678
+ sourceReport: {
100679
+ status: "assignment-status",
100680
+ runtimeField: "source",
100681
+ nativeValue: "native",
100682
+ assignedValue: "assigned"
100683
+ },
100684
+ advancedExpression: true,
100685
+ path: "running",
100686
+ valueKind: "boolean",
100687
+ nullable: true,
100688
+ companions: [
100689
+ {
100690
+ kind: "constant",
100691
+ path: "source",
100692
+ value: "assigned",
100693
+ when: "always"
100694
+ },
100695
+ {
100696
+ kind: "constant",
100697
+ path: "phase",
100698
+ value: null,
100699
+ when: "always"
100700
+ },
100701
+ {
100702
+ kind: "clock",
100703
+ path: "lastFetchedAt",
100704
+ when: "always"
100705
+ },
100706
+ {
100707
+ kind: "transition-time",
100708
+ path: "since",
100709
+ sourceChangedAt: "prefer"
100710
+ }
100711
+ ]
100712
+ }]
100713
+ }
100714
+ };
100715
+ //#endregion
100716
+ //#region src/composition/customize/override-draft.ts
100717
+ /**
100718
+ * A saved Customize assignment (D936). The schema is the type: callers use
100719
+ * `z.infer`, they do not restate the shape.
100720
+ */
100721
+ var OverrideSourceSchema = zod.z.object({
100722
+ addonId: zod.z.string().min(1),
100723
+ stableId: zod.z.string().min(1),
100724
+ cap: zod.z.string().min(1),
100725
+ fieldPath: zod.z.string().min(1)
100726
+ });
100727
+ var IdentityTransformDraftSchema = zod.z.object({ kind: zod.z.literal("identity") });
100728
+ var InvertTransformDraftSchema = zod.z.object({ kind: zod.z.literal("invert") });
100729
+ var ThresholdTransformDraftSchema = zod.z.object({
100730
+ kind: zod.z.literal("threshold"),
100731
+ comparison: zod.z.enum(["gte", "lte"]),
100732
+ threshold: zod.z.number(),
100733
+ startDwellMs: zod.z.number().nonnegative(),
100734
+ stopDwellMs: zod.z.number().nonnegative()
100735
+ });
100736
+ var LinearTransformDraftSchema = zod.z.object({
100737
+ kind: zod.z.literal("linear"),
100738
+ scale: zod.z.number(),
100739
+ offset: zod.z.number(),
100740
+ clampMin: zod.z.number().optional(),
100741
+ clampMax: zod.z.number().optional()
100742
+ });
100743
+ var EnumMapTransformDraftSchema = zod.z.object({
100744
+ kind: zod.z.literal("enum-map"),
100745
+ mapping: zod.z.record(zod.z.string(), zod.z.string().nullable())
100746
+ });
100747
+ var NumberBridgeTransformDraftSchema = zod.z.object({ kind: zod.z.literal("number") });
100748
+ var CustomizeTransformDraftSchema = zod.z.discriminatedUnion("kind", [
100749
+ IdentityTransformDraftSchema,
100750
+ InvertTransformDraftSchema,
100751
+ ThresholdTransformDraftSchema,
100752
+ LinearTransformDraftSchema,
100753
+ EnumMapTransformDraftSchema,
100754
+ NumberBridgeTransformDraftSchema
100755
+ ]);
100756
+ var ScalarOverrideDraftSchema = zod.z.object({
100757
+ kind: zod.z.literal("scalar"),
100758
+ cap: zod.z.string().min(1),
100759
+ targetId: zod.z.string().min(1),
100760
+ source: OverrideSourceSchema,
100761
+ transform: CustomizeTransformDraftSchema
100762
+ });
100763
+ var KeyedArrayOverrideDraftSchema = zod.z.object({
100764
+ kind: zod.z.literal("keyedArray"),
100765
+ cap: zod.z.string().min(1),
100766
+ targetId: zod.z.string().min(1),
100767
+ key: zod.z.string().min(1),
100768
+ label: zod.z.string().min(1),
100769
+ fieldPath: zod.z.string().min(1),
100770
+ source: OverrideSourceSchema,
100771
+ transform: CustomizeTransformDraftSchema
100772
+ });
100773
+ var PulseOverrideDraftSchema = zod.z.object({
100774
+ kind: zod.z.literal("pulse"),
100775
+ cap: zod.z.string().min(1),
100776
+ targetId: zod.z.string().min(1),
100777
+ enabled: zod.z.boolean(),
100778
+ debounceMs: zod.z.number().nonnegative(),
100779
+ sources: zod.z.array(OverrideSourceSchema).min(1)
100780
+ });
100781
+ var SpanSourceDraftSchema = OverrideSourceSchema.extend({ mode: zod.z.enum([
100782
+ "in-addition",
100783
+ "confirm",
100784
+ "replace"
100785
+ ]).optional() });
100786
+ var SpanOverrideDraftSchema = zod.z.object({
100787
+ kind: zod.z.literal("span"),
100788
+ cap: zod.z.string().min(1),
100789
+ targetId: zod.z.string().min(1),
100790
+ timeoutMs: zod.z.number().nonnegative(),
100791
+ cooldownMs: zod.z.number().nonnegative().optional(),
100792
+ sources: zod.z.array(SpanSourceDraftSchema)
100793
+ });
100794
+ var OverrideDraftSchema = zod.z.discriminatedUnion("kind", [
100795
+ ScalarOverrideDraftSchema,
100796
+ KeyedArrayOverrideDraftSchema,
100797
+ PulseOverrideDraftSchema,
100798
+ SpanOverrideDraftSchema
100799
+ ]);
100800
+ /** Effective authority for one declared target. Not a second stored switch. */
100801
+ var CustomizeAssignmentStatusSchema = zod.z.object({
100802
+ targetId: zod.z.string().min(1),
100803
+ configured: zod.z.boolean(),
100804
+ source: zod.z.enum(["native", "assigned"]),
100805
+ state: zod.z.enum([
100806
+ "active",
100807
+ "stale",
100808
+ "released",
100809
+ "unavailable"
100810
+ ]),
100811
+ reason: zod.z.string().nullable()
100812
+ });
100813
+ //#endregion
100814
+ //#region src/composition/customize/field-source.ts
100815
+ function fromRead(source, cap, fieldPath) {
100816
+ return {
100817
+ kind: "from",
100818
+ source,
100819
+ cap,
100820
+ fieldPath
100821
+ };
100822
+ }
100823
+ function expression(expr, bindings) {
100824
+ return {
100825
+ kind: "expression",
100826
+ expr,
100827
+ bindings
100828
+ };
100829
+ }
100830
+ function literal(expr) {
100831
+ return expression(expr, {});
100832
+ }
100833
+ function isLiteral(source, expr) {
100834
+ return source?.kind === "expression" && source.expr === expr && Object.keys(source.bindings).length === 0;
100835
+ }
100836
+ //#endregion
100837
+ //#region src/composition/customize/scalar-expr.ts
100838
+ var UNSIGNED = /^\d+(?:\.\d+)?$/;
100839
+ var SIGNED = /^-?\d+(?:\.\d+)?$/;
100840
+ var DWELL = /^dwell\(x (>=|<=) (\d+(?:\.\d+)?), (\d+(?:\.\d+)?), (\d+(?:\.\d+)?)\)$/;
100841
+ var LINEAR_CLAMP = /^clamp\((x|number\(x\)) \* (-?\d+(?:\.\d+)?) \+ (-?\d+(?:\.\d+)?), (-?\d+(?:\.\d+)?), (-?\d+(?:\.\d+)?)\)$/;
100842
+ var LINEAR_BARE = /^(x|number\(x\)) \* (-?\d+(?:\.\d+)?) \+ (-?\d+(?:\.\d+)?)$/;
100843
+ var IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/;
100844
+ function unsignedToken(value) {
100845
+ return token(value, UNSIGNED);
100846
+ }
100847
+ function signedToken(value) {
100848
+ return token(value, SIGNED);
100849
+ }
100850
+ function constantExpr(value) {
100851
+ if (typeof value === "string") return JSON.stringify(value);
100852
+ if (typeof value === "number") return signedToken(value);
100853
+ if (typeof value === "boolean") return value ? "true" : "false";
100854
+ return "null";
100855
+ }
100856
+ function isIdentifier(path) {
100857
+ return IDENT.test(path);
100858
+ }
100859
+ function dwellExpr(comparison, threshold, start, stop) {
100860
+ return `dwell(x ${comparison === "gte" ? ">=" : "<="} ${threshold}, ${start}, ${stop})`;
100861
+ }
100862
+ function linearExpr(inner, scale, offset, clampMin, clampMax) {
100863
+ const arithmetic = `${inner} * ${scale} + ${offset}`;
100864
+ if (clampMin === null || clampMax === null) return arithmetic;
100865
+ return `clamp(${arithmetic}, ${clampMin}, ${clampMax})`;
100866
+ }
100867
+ function parseDwell(expr) {
100868
+ const match = DWELL.exec(expr);
100869
+ if (match === null) return null;
100870
+ const threshold = Number(match[2]);
100871
+ const startDwellMs = Number(match[3]);
100872
+ const stopDwellMs = Number(match[4]);
100873
+ if (!Number.isFinite(threshold) || !Number.isFinite(startDwellMs) || !Number.isFinite(stopDwellMs)) return null;
100874
+ return {
100875
+ comparison: match[1] === "<=" ? "lte" : "gte",
100876
+ threshold,
100877
+ startDwellMs,
100878
+ stopDwellMs
100879
+ };
100880
+ }
100881
+ function parseLinear(expr) {
100882
+ const clamped = LINEAR_CLAMP.exec(expr);
100883
+ if (clamped !== null) return linearFrom(clamped[1], clamped[2], clamped[3], clamped[4], clamped[5]);
100884
+ const bare = LINEAR_BARE.exec(expr);
100885
+ if (bare === null) return null;
100886
+ return linearFrom(bare[1], bare[2], bare[3], void 0, void 0);
100887
+ }
100888
+ function singleFrom(source) {
100889
+ if (source.kind === "from") return {
100890
+ cap: source.cap,
100891
+ fieldPath: source.fieldPath,
100892
+ addonId: source.source.addonId,
100893
+ stableId: source.source.stableId
100894
+ };
100895
+ if (source.kind !== "expression" || Object.keys(source.bindings).length !== 1) return null;
100896
+ const bound = source.bindings["x"];
100897
+ if (bound === void 0 || bound.kind !== "from") return null;
100898
+ return {
100899
+ cap: bound.cap,
100900
+ fieldPath: bound.fieldPath,
100901
+ addonId: bound.source.addonId,
100902
+ stableId: bound.source.stableId
100903
+ };
100904
+ }
100905
+ function token(value, pattern) {
100906
+ if (!Number.isFinite(value)) return null;
100907
+ const text = Object.is(value, -0) ? "0" : String(value);
100908
+ return pattern.test(text) ? text : null;
100909
+ }
100910
+ function linearFrom(inner, scale, offset, clampMin, clampMax) {
100911
+ if (inner !== "x" && inner !== "number(x)") return null;
100912
+ if (scale === void 0 || offset === void 0) return null;
100913
+ const parsedScale = Number(scale);
100914
+ const parsedOffset = Number(offset);
100915
+ if (!Number.isFinite(parsedScale) || !Number.isFinite(parsedOffset)) return null;
100916
+ if (clampMin === void 0 || clampMax === void 0) return {
100917
+ inner,
100918
+ scale: parsedScale,
100919
+ offset: parsedOffset
100920
+ };
100921
+ const parsedMin = Number(clampMin);
100922
+ const parsedMax = Number(clampMax);
100923
+ if (!Number.isFinite(parsedMin) || !Number.isFinite(parsedMax)) return null;
100924
+ return {
100925
+ inner,
100926
+ scale: parsedScale,
100927
+ offset: parsedOffset,
100928
+ clampMin: parsedMin,
100929
+ clampMax: parsedMax
100930
+ };
100931
+ }
100932
+ //#endregion
100933
+ //#region src/composition/customize/scalar-compile.ts
100934
+ var catalog$4 = CAP_CUSTOMIZE_CATALOG;
100935
+ function compileScalarOverride(input) {
100936
+ const target = catalogTarget$4(input.draft.cap, input.draft.targetId);
100937
+ if (target === null || target.cardinality !== "scalar" || target.path === void 0) return fail$2("target");
100938
+ if (input.draft.transform.kind === "enum-map") return fail$2("enum");
100939
+ const source = sourceSpec$1(target, input.sourceValueKind, input.draft.source.cap);
100940
+ if (source === null) return fail$2("source-kind");
100941
+ if (source.requiredUnit !== void 0 && input.sourceUnit !== source.requiredUnit) return fail$2("unit");
100942
+ const allowed = input.draft.transform.kind === "number" ? "identity" : input.draft.transform.kind;
100943
+ if (!source.transformKinds.includes(allowed)) return fail$2("transform");
100944
+ const value = compileValue$1(input);
100945
+ if (!value.ok) return value;
100946
+ const fields = compileCompanions$1(input, target, value.value);
100947
+ if (!fields.ok) return fields;
100948
+ return {
100949
+ ok: true,
100950
+ value: {
100951
+ kind: "fields",
100952
+ cap: input.draft.cap,
100953
+ fields: fields.value
100954
+ }
100955
+ };
100956
+ }
100957
+ function fail$2(reason) {
100958
+ return {
100959
+ ok: false,
100960
+ reason
100961
+ };
100962
+ }
100963
+ function catalogTarget$4(cap, targetId) {
100964
+ const entry = catalog$4[cap];
100965
+ if (entry === void 0) return null;
100966
+ return entry.targets.find((target) => target.id === targetId) ?? null;
100967
+ }
100968
+ function sourceSpec$1(target, valueKind, sourceCap) {
100969
+ if (valueKind === "boolean" && sourceCap === "switch") return target.sources.find((source) => source.kind === "switch") ?? null;
100970
+ if (valueKind === "boolean") return target.sources.find((source) => source.kind === "binary") ?? fieldSource(target, "boolean");
100971
+ if (valueKind === "number") return target.sources.find((source) => source.kind === "numeric") ?? fieldSource(target, "number");
100972
+ return fieldSource(target, "string");
100973
+ }
100974
+ function fieldSource(target, valueKind) {
100975
+ return target.sources.find((source) => source.kind === "field" && (source.valueKinds ?? []).includes(valueKind)) ?? null;
100976
+ }
100977
+ function compileValue$1(input) {
100978
+ const read = fromRead(refOf$1(input.draft), input.draft.source.cap, input.draft.source.fieldPath);
100979
+ const transform = input.draft.transform;
100980
+ if (transform.kind === "identity" || transform.kind === "number") return {
100981
+ ok: true,
100982
+ value: identityValue(read, input.sourceValueKind)
100983
+ };
100984
+ if (transform.kind === "invert") {
100985
+ if (input.sourceValueKind !== "boolean") return fail$2("source-kind");
100986
+ return {
100987
+ ok: true,
100988
+ value: expression("!x", { x: read })
100989
+ };
100990
+ }
100991
+ if (transform.kind === "threshold") return thresholdValue(transform, read);
100992
+ if (transform.kind === "linear") return linearValue$1(transform, read, input.sourceValueKind);
100993
+ return fail$2("transform");
100994
+ }
100995
+ function identityValue(read, valueKind) {
100996
+ if (valueKind === "string") return expression("number(x)", { x: read });
100997
+ return read;
100998
+ }
100999
+ function thresholdValue(transform, read) {
101000
+ const threshold = unsignedToken(transform.threshold);
101001
+ if (threshold === null) return fail$2("threshold");
101002
+ const start = unsignedToken(transform.startDwellMs);
101003
+ const stop = unsignedToken(transform.stopDwellMs);
101004
+ if (start === null || stop === null) return fail$2("dwell");
101005
+ return {
101006
+ ok: true,
101007
+ value: expression(dwellExpr(transform.comparison, threshold, start, stop), { x: read })
101008
+ };
101009
+ }
101010
+ function linearValue$1(transform, read, valueKind) {
101011
+ const scale = signedToken(transform.scale);
101012
+ const offset = signedToken(transform.offset);
101013
+ if (scale === null || offset === null) return fail$2("scale");
101014
+ const clamps = clampTokens$1(transform.clampMin, transform.clampMax);
101015
+ if (!clamps.ok) return clamps;
101016
+ return {
101017
+ ok: true,
101018
+ value: expression(linearExpr(valueKind === "string" ? "number(x)" : "x", scale, offset, clamps.value.min, clamps.value.max), { x: read })
101019
+ };
101020
+ }
101021
+ function clampTokens$1(clampMin, clampMax) {
101022
+ if (clampMin === void 0 && clampMax === void 0) return {
101023
+ ok: true,
101024
+ value: {
101025
+ min: null,
101026
+ max: null
101027
+ }
101028
+ };
101029
+ if (clampMin === void 0 || clampMax === void 0) return fail$2("clamp");
101030
+ const min = signedToken(clampMin);
101031
+ const max = signedToken(clampMax);
101032
+ if (min === null || max === null || clampMin > clampMax) return fail$2("clamp");
101033
+ return {
101034
+ ok: true,
101035
+ value: {
101036
+ min,
101037
+ max
101038
+ }
101039
+ };
101040
+ }
101041
+ function compileCompanions$1(input, target, value) {
101042
+ if (target.path === void 0) return fail$2("target");
101043
+ const path = target.path;
101044
+ return (target.companions ?? []).filter((companion) => companionIncluded$1(companion, input.apply)).reduce((acc, companion) => {
101045
+ if (!acc.ok) return acc;
101046
+ const built = companionField(input, path, companion);
101047
+ if (!built.ok) return {
101048
+ ok: false,
101049
+ reason: built.reason
101050
+ };
101051
+ return {
101052
+ ok: true,
101053
+ value: {
101054
+ ...acc.value,
101055
+ [companion.path]: built.value
101056
+ }
101057
+ };
101058
+ }, {
101059
+ ok: true,
101060
+ value: { [path]: value }
101061
+ });
101062
+ }
101063
+ function companionIncluded$1(companion, apply) {
101064
+ if (companion.kind === "transition-time") return true;
101065
+ return companion.when === "always" || apply === "add";
101066
+ }
101067
+ function companionField(input, path, companion) {
101068
+ if (companion.kind === "constant") {
101069
+ const expr = constantExpr(companion.value);
101070
+ if (expr === null) return fail$2("scale");
101071
+ return {
101072
+ ok: true,
101073
+ value: literal(expr)
101074
+ };
101075
+ }
101076
+ if (companion.kind === "clock") return {
101077
+ ok: true,
101078
+ value: literal("now")
101079
+ };
101080
+ return transitionField(input, path, companion.sourceChangedAt);
101081
+ }
101082
+ function transitionField(input, path, sourceChangedAt) {
101083
+ if (sourceChangedAt === "prefer" && input.sourceValueKind === "boolean" && input.changedAtField !== null && isIdentifier(input.changedAtField)) return {
101084
+ ok: true,
101085
+ value: fromRead(refOf$1(input.draft), input.draft.source.cap, input.changedAtField)
101086
+ };
101087
+ if (!isIdentifier(path)) return fail$2("transform");
101088
+ const bindings = { [path]: fromRead(input.device, input.draft.cap, path) };
101089
+ return {
101090
+ ok: true,
101091
+ value: expression(`latchedAt(${path})`, bindings)
101092
+ };
101093
+ }
101094
+ function refOf$1(draft) {
101095
+ return {
101096
+ addonId: draft.source.addonId,
101097
+ stableId: draft.source.stableId
101098
+ };
101099
+ }
101100
+ //#endregion
101101
+ //#region src/composition/customize/normalize.ts
101102
+ function sortKeys(value) {
101103
+ if (Array.isArray(value)) return value.map(sortKeys);
101104
+ if (typeof value !== "object" || value === null) return value;
101105
+ return Object.fromEntries(Object.entries(value).toSorted(([a], [b]) => a.localeCompare(b)).map(([key, inner]) => [key, sortKeys(inner)]));
101106
+ }
101107
+ /** Key order is not part of the stored contract. Array order is. */
101108
+ function normalizeStored(stored) {
101109
+ return sortKeys(stored);
101110
+ }
101111
+ function sameStored(a, b) {
101112
+ return JSON.stringify(normalizeStored(a)) === JSON.stringify(normalizeStored(b));
101113
+ }
101114
+ //#endregion
101115
+ //#region src/composition/customize/scalar-decode.ts
101116
+ var catalog$3 = CAP_CUSTOMIZE_CATALOG;
101117
+ function decodeScalarOverride(input) {
101118
+ const target = catalogTarget$3(input.cap, input.targetId);
101119
+ if (target === null || target.cardinality !== "scalar" || target.path === void 0) return null;
101120
+ if (input.feature.cap !== input.cap || input.feature.kind !== "fields") return null;
101121
+ const outputKind = scalarOutputKind(target.valueKind);
101122
+ if (outputKind === null) return null;
101123
+ const value = input.feature.fields[target.path];
101124
+ const read = readValue(value, outputKind, input.cap, input.targetId);
101125
+ if (read === null) return null;
101126
+ const apply = inferApply$1(target, input.feature.fields);
101127
+ if (apply === null) return null;
101128
+ const changedAtField = inferChangedAt(target, input.feature.fields, read);
101129
+ const sourceUnit = unitFor(target, read.sourceValueKind, read.draft.source.cap);
101130
+ const decoded = {
101131
+ ...read,
101132
+ apply,
101133
+ changedAtField,
101134
+ sourceUnit
101135
+ };
101136
+ return reproduces$1(decoded, input.device, input.feature) ? decoded : null;
101137
+ }
101138
+ function catalogTarget$3(cap, targetId) {
101139
+ const entry = catalog$3[cap];
101140
+ if (entry === void 0) return null;
101141
+ return entry.targets.find((target) => target.id === targetId) ?? null;
101142
+ }
101143
+ function scalarOutputKind(valueKind) {
101144
+ if (valueKind === "boolean" || valueKind === "number" || valueKind === "string") return valueKind;
101145
+ return null;
101146
+ }
101147
+ function readValue(field, outputKind, cap, targetId) {
101148
+ if (field === void 0) return null;
101149
+ if (field.kind === "from") return drafted(field, { kind: "identity" }, outputKind, cap, targetId);
101150
+ if (field.kind !== "expression") return null;
101151
+ if (field.expr === "number(x)" && outputKind === "number") return drafted(field, { kind: "identity" }, "string", cap, targetId);
101152
+ if (field.expr === "!x" && outputKind === "boolean") return drafted(field, { kind: "invert" }, "boolean", cap, targetId);
101153
+ const dwell = parseDwell(field.expr);
101154
+ if (dwell !== null) return drafted(field, {
101155
+ kind: "threshold",
101156
+ comparison: dwell.comparison,
101157
+ threshold: dwell.threshold,
101158
+ startDwellMs: dwell.startDwellMs,
101159
+ stopDwellMs: dwell.stopDwellMs
101160
+ }, "number", cap, targetId);
101161
+ const linear = parseLinear(field.expr);
101162
+ if (linear === null || outputKind !== "number") return null;
101163
+ return drafted(field, {
101164
+ kind: "linear",
101165
+ scale: linear.scale,
101166
+ offset: linear.offset,
101167
+ ...linear.clampMin === void 0 || linear.clampMax === void 0 ? {} : {
101168
+ clampMin: linear.clampMin,
101169
+ clampMax: linear.clampMax
101170
+ }
101171
+ }, linear.inner === "number(x)" ? "string" : "number", cap, targetId);
101172
+ }
101173
+ function drafted(field, transform, sourceValueKind, cap, targetId) {
101174
+ const bound = singleFrom(field);
101175
+ if (bound === null) return null;
101176
+ return {
101177
+ sourceValueKind,
101178
+ draft: {
101179
+ kind: "scalar",
101180
+ cap,
101181
+ targetId,
101182
+ source: {
101183
+ addonId: bound.addonId,
101184
+ stableId: bound.stableId,
101185
+ cap: bound.cap,
101186
+ fieldPath: bound.fieldPath
101187
+ },
101188
+ transform
101189
+ }
101190
+ };
101191
+ }
101192
+ function inferApply$1(target, fields) {
101193
+ const addPaths = (target.companions ?? []).flatMap((companion) => companion.kind !== "transition-time" && companion.when === "add" ? [companion.path] : []);
101194
+ if (addPaths.length === 0) return "replace";
101195
+ const present = addPaths.filter((path) => fields[path] !== void 0);
101196
+ if (present.length === addPaths.length) return "add";
101197
+ if (present.length === 0) return "replace";
101198
+ return null;
101199
+ }
101200
+ function inferChangedAt(target, fields, read) {
101201
+ if (read.sourceValueKind !== "boolean") return null;
101202
+ const transition = (target.companions ?? []).find((companion) => companion.kind === "transition-time");
101203
+ if (transition === void 0 || transition.sourceChangedAt !== "prefer") return null;
101204
+ const since = fields[transition.path];
101205
+ if (since?.kind !== "from") return null;
101206
+ if (since.cap !== read.draft.source.cap) return null;
101207
+ if (since.source.addonId !== read.draft.source.addonId || since.source.stableId !== read.draft.source.stableId) return null;
101208
+ return since.fieldPath;
101209
+ }
101210
+ function unitFor(target, valueKind, sourceCap) {
101211
+ if (valueKind === "boolean" && sourceCap === "switch") return null;
101212
+ if (valueKind === "number") return target.sources.find((source) => source.kind === "numeric")?.requiredUnit ?? null;
101213
+ return null;
101214
+ }
101215
+ function reproduces$1(decoded, device, stored) {
101216
+ const compiled = compileScalarOverride({
101217
+ draft: decoded.draft,
101218
+ device,
101219
+ apply: decoded.apply,
101220
+ sourceValueKind: decoded.sourceValueKind,
101221
+ changedAtField: decoded.changedAtField,
101222
+ sourceUnit: decoded.sourceUnit
101223
+ });
101224
+ if (!compiled.ok) return false;
101225
+ return sameFeature$2(compiled.value, stored);
101226
+ }
101227
+ function sameFeature$2(compiled, stored) {
101228
+ return sameStored(wrap$2(withoutEnabled(compiled)), wrap$2(withoutEnabled(stored)));
101229
+ }
101230
+ function withoutEnabled(feature) {
101231
+ const { enabled: _enabled, ...rest } = feature;
101232
+ return rest;
101233
+ }
101234
+ function wrap$2(feature) {
101235
+ return {
101236
+ family: "composition",
101237
+ target: {
101238
+ addonId: "t",
101239
+ stableId: "t"
101240
+ },
101241
+ feature
101242
+ };
101243
+ }
101244
+ //#endregion
101245
+ //#region src/composition/customize/scalar-status.ts
101246
+ function projectScalarAssignment(input) {
101247
+ if (input.stored.kind === "pending") return unanswered$1(input.targetId, "pending", null);
101248
+ if (input.stored.kind === "unknown") return unanswered$1(input.targetId, "unknown", input.stored.reason ?? "unknown");
101249
+ if (input.stored.value === null) return native$2(input.targetId);
101250
+ const decoded = decodeScalarOverride({
101251
+ feature: input.stored.value,
101252
+ device: input.device,
101253
+ cap: input.cap,
101254
+ targetId: input.targetId
101255
+ });
101256
+ if (decoded === null) return {
101257
+ text: "unknown",
101258
+ status: status$1(input.targetId, true, "assigned", "unavailable", "not-canonical")
101259
+ };
101260
+ return projectDecoded$1(input, decoded.apply, sourceLabel(decoded.draft.source.cap, decoded.draft.source.fieldPath));
101261
+ }
101262
+ function projectDecoded$1(input, apply, label) {
101263
+ if (input.sourcePresence === "pending") return {
101264
+ text: "pending",
101265
+ status: status$1(input.targetId, true, "assigned", "stale", null)
101266
+ };
101267
+ if (input.sourcePresence === "unknown") return {
101268
+ text: "unknown",
101269
+ status: status$1(input.targetId, true, "assigned", "stale", input.sourceUnknownReason ?? "unknown")
101270
+ };
101271
+ if (input.sourcePresence === "absent" && apply === "replace") return {
101272
+ text: "Native · source missing",
101273
+ status: status$1(input.targetId, true, "native", "released", "source-missing")
101274
+ };
101275
+ if (input.sourcePresence === "absent") return {
101276
+ text: `Assigned · ${label}`,
101277
+ status: status$1(input.targetId, true, "assigned", "unavailable", "source-missing")
101278
+ };
101279
+ return {
101280
+ text: `Assigned · ${label}`,
101281
+ status: status$1(input.targetId, true, "assigned", "active", null)
101282
+ };
101283
+ }
101284
+ function native$2(targetId) {
101285
+ return {
101286
+ text: "Native",
101287
+ status: status$1(targetId, false, "native", "active", null)
101288
+ };
101289
+ }
101290
+ function unanswered$1(targetId, text, reason) {
101291
+ return {
101292
+ text,
101293
+ status: status$1(targetId, false, "native", text === "pending" ? "unavailable" : "stale", reason)
101294
+ };
101295
+ }
101296
+ function sourceLabel(cap, fieldPath) {
101297
+ return `${cap}.${fieldPath}`;
101298
+ }
101299
+ function status$1(targetId, configured, source, state, reason) {
101300
+ return {
101301
+ targetId,
101302
+ configured,
101303
+ source,
101304
+ state,
101305
+ reason
101306
+ };
101307
+ }
101308
+ //#endregion
101309
+ //#region src/composition/customize/event-compile.ts
101310
+ var catalog$2 = CAP_CUSTOMIZE_CATALOG;
101311
+ function compilePulseOverride(input) {
101312
+ const target = catalogTarget$2(input.draft.cap, input.draft.targetId);
101313
+ if (target === null || target.shape !== "pulse") return fail$1("target");
101314
+ const timestampPath = target.timestampPath;
101315
+ const counterPath = target.counterPath;
101316
+ if (timestampPath === void 0 || counterPath === void 0 || !isIdentifier(timestampPath) || !isIdentifier(counterPath)) return fail$1("path");
101317
+ if (!(target.edges ?? []).includes("rising")) return fail$1("edge");
101318
+ const pairs = pairSources(input);
101319
+ if (!pairs.ok) return pairs;
101320
+ if (pairs.value.length === 0) return fail$1("sources");
101321
+ const debounce = unsignedToken(input.draft.debounceMs);
101322
+ if (debounce === null) return fail$1("debounce");
101323
+ const ordered = pairs.value.toSorted((a, b) => pairKey(a).localeCompare(pairKey(b)));
101324
+ return {
101325
+ ok: true,
101326
+ value: {
101327
+ kind: "fields",
101328
+ cap: input.draft.cap,
101329
+ enabled: input.draft.enabled,
101330
+ fields: {
101331
+ [timestampPath]: expression(pulseExpr(ordered.length, debounce), pulseBindings(ordered)),
101332
+ [counterPath]: expression(`count(${timestampPath})`, { [timestampPath]: fromRead(input.device, input.draft.cap, timestampPath) })
101333
+ }
101334
+ }
101335
+ };
101336
+ }
101337
+ function compileSpanOverride(input) {
101338
+ const target = catalogTarget$2(input.draft.cap, input.draft.targetId);
101339
+ if (target === null || target.shape !== "span") return fail$1("target");
101340
+ if (target.applyAuthority?.kind !== "camera-sensors") return fail$1("authority");
101341
+ if (input.draft.timeoutMs < 0 || !Number.isFinite(input.draft.timeoutMs)) return fail$1("timeout");
101342
+ if (target.cooldownMs === void 0 && input.draft.cooldownMs !== void 0) return fail$1("cooldown");
101343
+ if (input.draft.cooldownMs !== void 0 && input.draft.cooldownMs < 0) return fail$1("cooldown");
101344
+ const sensors = sensorEntries(input.draft.sources, input.device, target.sourceModes);
101345
+ if (!sensors.ok) return sensors;
101346
+ if (sensors.value.length === 0) return {
101347
+ ok: true,
101348
+ value: {
101349
+ config: null,
101350
+ timeoutMs: input.draft.timeoutMs,
101351
+ cooldownMs: input.draft.cooldownMs
101352
+ }
101353
+ };
101354
+ const parsed = CameraSensorsConfigSchema.safeParse({ sensors: sensors.value });
101355
+ if (!parsed.success) {
101356
+ const issue = parsed.error.issues[0];
101357
+ return fail$1(issue === void 0 ? "cameraSensors" : issue.message);
101358
+ }
101359
+ return {
101360
+ ok: true,
101361
+ value: {
101362
+ config: parsed.data,
101363
+ timeoutMs: input.draft.timeoutMs,
101364
+ cooldownMs: input.draft.cooldownMs
101365
+ }
101366
+ };
101367
+ }
101368
+ function pairSources(input) {
101369
+ if (input.changedAtFields.length !== input.draft.sources.length) return fail$1("changed-at");
101370
+ const pairs = input.draft.sources.map((source, index) => {
101371
+ return {
101372
+ source,
101373
+ changedAtField: input.changedAtFields[index] ?? ""
101374
+ };
101375
+ });
101376
+ if (pairs.some((pair) => pair.changedAtField.length === 0 || pair.source.fieldPath.length === 0)) return fail$1("changed-at");
101377
+ return {
101378
+ ok: true,
101379
+ value: pairs
101380
+ };
101381
+ }
101382
+ function pairKey(pair) {
101383
+ return `${pair.source.addonId}/${pair.source.stableId}#${pair.source.cap}#${pair.source.fieldPath}`;
101384
+ }
101385
+ function pulseExpr(count, debounce) {
101386
+ const roses = [];
101387
+ for (let index = 0; index < count; index += 1) roses.push(`rose(active${index}, changed${index}, ${debounce})`);
101388
+ return `latest(${roses.join(", ")})`;
101389
+ }
101390
+ function pulseBindings(pairs) {
101391
+ const bindings = {};
101392
+ pairs.forEach((pair, index) => {
101393
+ const ref = {
101394
+ addonId: pair.source.addonId,
101395
+ stableId: pair.source.stableId
101396
+ };
101397
+ bindings[`active${index}`] = fromRead(ref, pair.source.cap, pair.source.fieldPath);
101398
+ bindings[`changed${index}`] = fromRead(ref, pair.source.cap, pair.changedAtField);
101399
+ });
101400
+ return bindings;
101401
+ }
101402
+ function sensorEntries(sources, device, modes) {
101403
+ const entries = [];
101404
+ for (const source of sources) {
101405
+ if (source.addonId === device.addonId && source.stableId === device.stableId) return fail$1("self");
101406
+ const mode = source.mode ?? "in-addition";
101407
+ if (modes !== void 0 && !modes.includes(mode)) return fail$1("mode");
101408
+ if (modes === void 0 && source.mode !== void 0 && source.mode !== "in-addition") return fail$1("mode");
101409
+ entries.push({
101410
+ addonId: source.addonId,
101411
+ stableId: source.stableId,
101412
+ mode
101413
+ });
101414
+ }
101415
+ return {
101416
+ ok: true,
101417
+ value: entries
101418
+ };
101419
+ }
101420
+ function catalogTarget$2(cap, targetId) {
101421
+ const entry = catalog$2[cap];
101422
+ if (entry === void 0) return null;
101423
+ return entry.targets.find((target) => target.id === targetId) ?? null;
101424
+ }
101425
+ function fail$1(reason) {
101426
+ return {
101427
+ ok: false,
101428
+ reason
101429
+ };
101430
+ }
101431
+ //#endregion
101432
+ //#region src/composition/customize/event-decode.ts
101433
+ var ROSE_SOURCE = String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
101434
+ function decodePulseOverride(input) {
101435
+ if (input.feature.cap !== input.cap || input.feature.kind !== "fields") return null;
101436
+ if (input.feature.enabled === void 0) return null;
101437
+ const timestamp = input.feature.fields[input.timestampPath];
101438
+ const counter = input.feature.fields[input.counterPath];
101439
+ if (timestamp === void 0 || counter === void 0) return null;
101440
+ if (Object.keys(input.feature.fields).length !== 2) return null;
101441
+ const edges = readEdges(timestamp);
101442
+ if (edges === null) return null;
101443
+ if (readCount(counter, input) === null) return null;
101444
+ const draft = {
101445
+ kind: "pulse",
101446
+ cap: input.cap,
101447
+ targetId: input.targetId,
101448
+ enabled: input.feature.enabled,
101449
+ debounceMs: edges.debounceMs,
101450
+ sources: edges.sources
101451
+ };
101452
+ const decoded = {
101453
+ draft,
101454
+ changedAtFields: edges.changedAtFields
101455
+ };
101456
+ const compiled = compilePulseOverride({
101457
+ draft,
101458
+ device: input.device,
101459
+ changedAtFields: edges.changedAtFields
101460
+ });
101461
+ if (!compiled.ok) return null;
101462
+ return sameFeature$1(compiled.value, input.feature) ? decoded : null;
101463
+ }
101464
+ function readEdges(field) {
101465
+ if (field.kind !== "expression" || !field.expr.startsWith("latest(") || !field.expr.endsWith(")")) return null;
101466
+ const inner = field.expr.slice(7, -1);
101467
+ const found = [...inner.matchAll(new RegExp(ROSE_SOURCE, "g"))];
101468
+ if (found.length === 0 || found.map((match) => match[0]).join(", ") !== inner) return null;
101469
+ if (Object.keys(field.bindings).length !== found.length * 2) return null;
101470
+ const rows = found.map((match, index) => readRose(match, index, field.bindings));
101471
+ if (rows.some((row) => row === null)) return null;
101472
+ const edges = rows.filter((row) => row !== null);
101473
+ const debounceMs = edges[0]?.debounceMs;
101474
+ if (debounceMs === void 0 || edges.some((row) => row.debounceMs !== debounceMs)) return null;
101475
+ return {
101476
+ debounceMs,
101477
+ sources: edges.map((row) => row.source),
101478
+ changedAtFields: edges.map((row) => row.changedAtField)
101479
+ };
101480
+ }
101481
+ function readRose(match, index, bindings) {
101482
+ const activeIndex = Number(match[1]);
101483
+ const changedIndex = Number(match[2]);
101484
+ const debounceMs = Number(match[3]);
101485
+ if (activeIndex !== index || changedIndex !== index || !Number.isFinite(debounceMs)) return null;
101486
+ const active = fromBinding(bindings[`active${index}`]);
101487
+ const changed = fromBinding(bindings[`changed${index}`]);
101488
+ if (active === null || changed === null) return null;
101489
+ if (active.cap !== changed.cap) return null;
101490
+ if (active.source.addonId !== changed.source.addonId) return null;
101491
+ if (active.source.stableId !== changed.source.stableId) return null;
101492
+ return {
101493
+ debounceMs,
101494
+ changedAtField: changed.fieldPath,
101495
+ source: {
101496
+ addonId: active.source.addonId,
101497
+ stableId: active.source.stableId,
101498
+ cap: active.cap,
101499
+ fieldPath: active.fieldPath
101500
+ }
101501
+ };
101502
+ }
101503
+ function fromBinding(value) {
101504
+ if (value === void 0 || value.kind !== "from") return null;
101505
+ return value;
101506
+ }
101507
+ function readCount(field, input) {
101508
+ if (field.kind !== "expression" || field.expr !== `count(${input.timestampPath})`) return null;
101509
+ const binding = fromBinding(field.bindings[input.timestampPath]);
101510
+ if (binding === null) return null;
101511
+ if (Object.keys(field.bindings).length !== 1) return null;
101512
+ if (binding.cap !== input.cap || binding.fieldPath !== input.timestampPath) return null;
101513
+ if (binding.source.addonId !== input.device.addonId) return null;
101514
+ if (binding.source.stableId !== input.device.stableId) return null;
101515
+ return true;
101516
+ }
101517
+ function sameFeature$1(left, right) {
101518
+ return sameStored(wrap$1(left), wrap$1(right));
101519
+ }
101520
+ function wrap$1(feature) {
101521
+ return {
101522
+ family: "composition",
101523
+ target: {
101524
+ addonId: "t",
101525
+ stableId: "t"
101526
+ },
101527
+ feature
101528
+ };
101529
+ }
101530
+ //#endregion
101531
+ //#region src/composition/customize/event-eval.ts
101532
+ var INITIAL_PULSE = {
101533
+ priorActive: void 0,
101534
+ lastPressedAt: null,
101535
+ count: 0,
101536
+ acceptedAt: null
101537
+ };
101538
+ var INITIAL_SPAN = {
101539
+ open: false,
101540
+ startedAt: null,
101541
+ endedAt: null,
101542
+ quietUntil: null,
101543
+ priorActive: void 0
101544
+ };
101545
+ function stepPulse(state, sample, debounceMs) {
101546
+ if (sample.kind === "unread" || debounceMs < 0) return state;
101547
+ if (state.priorActive === void 0) return {
101548
+ ...state,
101549
+ priorActive: sample.active
101550
+ };
101551
+ if (!sample.active) return {
101552
+ ...state,
101553
+ priorActive: false
101554
+ };
101555
+ if (state.priorActive) return state;
101556
+ const at = finite(sample.changedAt);
101557
+ if (at === null) return {
101558
+ ...state,
101559
+ priorActive: true
101560
+ };
101561
+ if (state.acceptedAt !== null && at - state.acceptedAt < debounceMs) return {
101562
+ ...state,
101563
+ priorActive: true
101564
+ };
101565
+ return {
101566
+ priorActive: true,
101567
+ lastPressedAt: at,
101568
+ count: state.count + 1,
101569
+ acceptedAt: at
101570
+ };
101571
+ }
101572
+ function stepSpan(state, sample, timing) {
101573
+ const timed = expire(state, timing);
101574
+ if (sample.kind === "unread" || timing.timeoutMs < 0 || timing.cooldownMs < 0) return timed;
101575
+ if (timed.priorActive === void 0) return {
101576
+ ...timed,
101577
+ priorActive: sample.active
101578
+ };
101579
+ if (timed.open && timed.priorActive && !sample.active) return finish(timed, finite(sample.changedAt) ?? timing.nowMs, timing.cooldownMs, false);
101580
+ if (!sample.active) return {
101581
+ ...timed,
101582
+ priorActive: false
101583
+ };
101584
+ if (timed.priorActive || timed.open) return {
101585
+ ...timed,
101586
+ priorActive: true
101587
+ };
101588
+ const at = finite(sample.changedAt) ?? timing.nowMs;
101589
+ if (timed.quietUntil !== null && at < timed.quietUntil) return {
101590
+ ...timed,
101591
+ priorActive: true
101592
+ };
101593
+ return {
101594
+ open: true,
101595
+ startedAt: at,
101596
+ endedAt: null,
101597
+ quietUntil: null,
101598
+ priorActive: true
101599
+ };
101600
+ }
101601
+ function expire(state, timing) {
101602
+ if (!state.open || state.startedAt === null) return state;
101603
+ const deadline = state.startedAt + timing.timeoutMs;
101604
+ if (timing.nowMs < deadline) return state;
101605
+ return finish(state, deadline, timing.cooldownMs, state.priorActive === true);
101606
+ }
101607
+ function finish(state, endedAt, cooldownMs, priorActive) {
101608
+ return {
101609
+ open: false,
101610
+ startedAt: state.startedAt,
101611
+ endedAt,
101612
+ quietUntil: cooldownMs > 0 ? endedAt + cooldownMs : null,
101613
+ priorActive
101614
+ };
101615
+ }
101616
+ function finite(value) {
101617
+ return value !== null && Number.isFinite(value) ? value : null;
101618
+ }
101619
+ //#endregion
101620
+ //#region src/composition/customize/event-status.ts
101621
+ function projectPulseAssignment(input) {
101622
+ if (input.stored.kind === "pending") return held(input.targetId, "pending", null);
101623
+ if (input.stored.kind === "unknown") return held(input.targetId, "unknown", input.stored.reason ?? "unknown");
101624
+ if (input.stored.value === null) return native$1(input.targetId);
101625
+ const decoded = decodePulseOverride({
101626
+ feature: input.stored.value,
101627
+ device: input.device,
101628
+ cap: input.cap,
101629
+ targetId: input.targetId,
101630
+ timestampPath: input.timestampPath,
101631
+ counterPath: input.counterPath
101632
+ });
101633
+ if (decoded === null) return {
101634
+ text: "unknown",
101635
+ status: row(input.targetId, true, "assigned", "unavailable", "not-canonical")
101636
+ };
101637
+ if (input.sourcePresence === "pending") return {
101638
+ text: "pending",
101639
+ status: row(input.targetId, true, "assigned", "stale", null)
101640
+ };
101641
+ if (input.sourcePresence === "unknown") return {
101642
+ text: "unknown",
101643
+ status: row(input.targetId, true, "assigned", "stale", input.sourceUnknownReason ?? "unknown")
101644
+ };
101645
+ if (input.sourcePresence === "absent" && input.apply === "replace") return {
101646
+ text: "Native · source missing",
101647
+ status: row(input.targetId, true, "native", "released", "source-missing")
101648
+ };
101649
+ if (input.sourcePresence === "absent") return {
101650
+ text: "Assigned · source missing",
101651
+ status: row(input.targetId, true, "assigned", "unavailable", "source-missing")
101652
+ };
101653
+ const source = decoded.draft.sources[0];
101654
+ return {
101655
+ text: `Assigned · ${source === void 0 ? "assigned" : `${source.cap}.${source.fieldPath}`}`,
101656
+ status: row(input.targetId, true, "assigned", "active", null)
101657
+ };
101658
+ }
101659
+ function projectSpanAssignment(targetId, stored) {
101660
+ if (stored.kind === "pending") return {
101661
+ text: "pending",
101662
+ writable: false,
101663
+ rows: [],
101664
+ status: row(targetId, false, "native", "unavailable", null)
101665
+ };
101666
+ if (stored.kind === "unknown") return {
101667
+ text: "unknown",
101668
+ writable: false,
101669
+ rows: [],
101670
+ status: row(targetId, false, "native", "stale", stored.reason ?? "unknown")
101671
+ };
101672
+ if (stored.value.state === "unreadable") return {
101673
+ text: "unreadable",
101674
+ writable: false,
101675
+ rows: [],
101676
+ status: row(targetId, false, "assigned", "unavailable", stored.value.reason)
101677
+ };
101678
+ if (stored.value.state === "not-configured") return {
101679
+ text: "Native",
101680
+ writable: true,
101681
+ rows: [],
101682
+ status: row(targetId, false, "native", "active", null)
101683
+ };
101684
+ const rows = stored.value.sensors.map(sensorRow);
101685
+ const reason = spanReason(stored.value);
101686
+ return {
101687
+ text: rows.length === 0 ? "Native" : "Assigned",
101688
+ writable: true,
101689
+ rows,
101690
+ status: row(targetId, rows.length > 0, "assigned", "active", reason)
101691
+ };
101692
+ }
101693
+ function spanReason(status) {
101694
+ if (status.notForwarded !== void 0) return status.notForwarded;
101695
+ if (status.notEnforced !== void 0) return status.notEnforced;
101696
+ return status.sensors.map(attachmentReason).find((reason) => reason !== null) ?? null;
101697
+ }
101698
+ function sensorRow(sensor) {
101699
+ return {
101700
+ key: `${sensor.addonId}/${sensor.stableId}`,
101701
+ addonId: sensor.addonId,
101702
+ stableId: sensor.stableId,
101703
+ name: sensor.state === "missing" || sensor.state === "unreadable" ? sensor.stableId : sensor.name,
101704
+ mode: sensor.mode,
101705
+ state: sensor.state,
101706
+ reason: attachmentReason(sensor)
101707
+ };
101708
+ }
101709
+ function attachmentReason(sensor) {
101710
+ switch (sensor.state) {
101711
+ case "ready": return null;
101712
+ case "offline":
101713
+ case "missing":
101714
+ case "unsupported":
101715
+ case "unreadable": return sensor.reason;
101716
+ }
101717
+ }
101718
+ function native$1(targetId) {
101719
+ return {
101720
+ text: "Native",
101721
+ status: row(targetId, false, "native", "active", null)
101722
+ };
101723
+ }
101724
+ function held(targetId, text, reason) {
101725
+ return {
101726
+ text,
101727
+ status: row(targetId, false, "native", text === "pending" ? "unavailable" : "stale", reason)
101728
+ };
101729
+ }
101730
+ function row(targetId, configured, source, state, reason) {
101731
+ return {
101732
+ targetId,
101733
+ configured,
101734
+ source,
101735
+ state,
101736
+ reason
101737
+ };
101738
+ }
101739
+ //#endregion
101740
+ //#region src/composition/customize/keyed-array-expr.ts
101741
+ var STEP = /^x == ("(?:\\.|[^"\\])*") \? ("(?:\\.|[^"\\])*"|null) : ([\s\S]+)$/;
101742
+ function enumMapExpr(mapping) {
101743
+ const keys = Object.keys(mapping).toSorted();
101744
+ if (keys.length === 0) return null;
101745
+ return keys.reduceRight((rest, key) => {
101746
+ if (rest === null) return null;
101747
+ const value = mapping[key];
101748
+ if (value === void 0) return null;
101749
+ const rhs = value === null ? "null" : JSON.stringify(value);
101750
+ return `x == ${JSON.stringify(key)} ? ${rhs} : ${rest}`;
101751
+ }, "null");
101752
+ }
101753
+ function parseEnumMap(expr) {
101754
+ const mapping = {};
101755
+ let rest = expr;
101756
+ while (rest !== "null") {
101757
+ const match = STEP.exec(rest);
101758
+ if (match === null || match[1] === void 0 || match[2] === void 0 || match[3] === void 0) return null;
101759
+ const key = jsonString(match[1]);
101760
+ const value = match[2] === "null" ? null : jsonString(match[2]);
101761
+ if (key === null || match[2] !== "null" && value === null) return null;
101762
+ if (Object.prototype.hasOwnProperty.call(mapping, key)) return null;
101763
+ mapping[key] = value;
101764
+ rest = match[3];
101765
+ }
101766
+ return Object.keys(mapping).length === 0 ? null : mapping;
101767
+ }
101768
+ function enumMapDraft(mapping) {
101769
+ return {
101770
+ kind: "enum-map",
101771
+ mapping: { ...mapping }
101772
+ };
101773
+ }
101774
+ function jsonString(token) {
101775
+ try {
101776
+ const parsed = JSON.parse(token);
101777
+ return typeof parsed === "string" ? parsed : null;
101778
+ } catch {
101779
+ return null;
101780
+ }
101781
+ }
101782
+ //#endregion
101783
+ //#region src/composition/customize/keyed-array-compile.ts
101784
+ var catalog$1 = CAP_CUSTOMIZE_CATALOG;
101785
+ function compileKeyedArrayOverride(input) {
101786
+ const target = catalogTarget$1(input.cap, input.targetId);
101787
+ if (target === null || target.cardinality !== "keyedArray") return fail("target");
101788
+ if (input.items.length === 0) return fail("items");
101789
+ if (input.items.some((item) => item.draft.cap !== input.cap || item.draft.targetId !== input.targetId)) return fail("target");
101790
+ const keys = input.items.map((item) => item.draft.key);
101791
+ if (new Set(keys).size !== keys.length) return fail("key");
101792
+ const built = input.items.reduce((acc, item) => {
101793
+ if (!acc.ok) return acc;
101794
+ const entry = compileItem(target, item);
101795
+ if (!entry.ok) return entry;
101796
+ return {
101797
+ ok: true,
101798
+ value: {
101799
+ ...acc.value,
101800
+ [item.draft.key]: entry.value
101801
+ }
101802
+ };
101803
+ }, {
101804
+ ok: true,
101805
+ value: {}
101806
+ });
101807
+ if (!built.ok) return built;
101808
+ const fields = compileCompanions(target, input.apply);
101809
+ if (!fields.ok) return fields;
101810
+ return {
101811
+ ok: true,
101812
+ value: {
101813
+ kind: "fields",
101814
+ cap: input.cap,
101815
+ fields: fields.value,
101816
+ items: { ...built.value }
101817
+ }
101818
+ };
101819
+ }
101820
+ /** Put one compiled item into an existing feature. Other items stay as stored. */
101821
+ function mergeKeyedArrayItem(current, compiled, key) {
101822
+ const item = compiled.items?.[key];
101823
+ if (item === void 0) return null;
101824
+ return {
101825
+ kind: "fields",
101826
+ cap: compiled.cap,
101827
+ ...current?.enabled === void 0 ? {} : { enabled: current.enabled },
101828
+ fields: current === null ? compiled.fields : current.fields,
101829
+ items: {
101830
+ ...current?.items,
101831
+ [key]: item
101832
+ }
101833
+ };
101834
+ }
101835
+ /** The feature without item `key`. Null when that item was the last one. */
101836
+ function withoutKeyedArrayItem(feature, key) {
101837
+ const rest = Object.fromEntries(Object.entries(feature.items ?? {}).filter(([name]) => name !== key));
101838
+ if (Object.keys(rest).length === 0) return null;
101839
+ return {
101840
+ ...feature,
101841
+ items: rest
101842
+ };
101843
+ }
101844
+ function fail(reason) {
101845
+ return {
101846
+ ok: false,
101847
+ reason
101848
+ };
101849
+ }
101850
+ function catalogTarget$1(cap, targetId) {
101851
+ const entry = catalog$1[cap];
101852
+ if (entry === void 0) return null;
101853
+ return entry.targets.find((target) => target.id === targetId) ?? null;
101854
+ }
101855
+ function compileItem(target, item) {
101856
+ if (!require_composition.COMPOSITION_ITEM_KEY_RE.test(item.draft.key) || item.draft.label.trim() === "") return fail("key");
101857
+ const field = (target.fields ?? []).find((entry) => entry.path === item.draft.fieldPath);
101858
+ if (field === void 0) return fail("field");
101859
+ const source = sourceSpec(field, item);
101860
+ if (source === null) return fail("source-kind");
101861
+ if (source.requiredUnit !== void 0 && item.sourceUnit !== source.requiredUnit) return fail("unit");
101862
+ const allowed = item.draft.transform.kind;
101863
+ if (!source.transformKinds.includes(allowed)) return fail("transform");
101864
+ const value = compileValue(item, field);
101865
+ if (!value.ok) return value;
101866
+ const fields = compileLiterals(target, field, item, value.value);
101867
+ if (!fields.ok) return fields;
101868
+ return {
101869
+ ok: true,
101870
+ value: {
101871
+ label: item.draft.label.trim(),
101872
+ fields: fields.value
101873
+ }
101874
+ };
101875
+ }
101876
+ function sourceSpec(field, item) {
101877
+ if (item.sourceValueKind === "number") return field.sources.find((source) => source.kind === "numeric") ?? null;
101878
+ if (item.sourceValueKind === "enum" || item.sourceValueKind === "string") return field.sources.find((source) => source.kind === "enum") ?? null;
101879
+ return null;
101880
+ }
101881
+ function compileValue(item, field) {
101882
+ const read = fromRead(refOf(item.draft), item.draft.source.cap, item.draft.source.fieldPath);
101883
+ const transform = item.draft.transform;
101884
+ if (transform.kind === "identity") return {
101885
+ ok: true,
101886
+ value: read
101887
+ };
101888
+ if (transform.kind === "linear") return linearValue(transform, read);
101889
+ if (transform.kind === "enum-map") return enumValue(transform, read, field);
101890
+ return fail("transform");
101891
+ }
101892
+ function linearValue(transform, read) {
101893
+ const scale = signedToken(transform.scale);
101894
+ const offset = signedToken(transform.offset);
101895
+ if (scale === null || offset === null) return fail("scale");
101896
+ const clamps = clampTokens(transform.clampMin, transform.clampMax);
101897
+ if (!clamps.ok) return clamps;
101898
+ return {
101899
+ ok: true,
101900
+ value: expression(linearExpr("x", scale, offset, clamps.value.min, clamps.value.max), { x: read })
101901
+ };
101902
+ }
101903
+ function clampTokens(clampMin, clampMax) {
101904
+ if (clampMin === void 0 && clampMax === void 0) return {
101905
+ ok: true,
101906
+ value: {
101907
+ min: null,
101908
+ max: null
101909
+ }
101910
+ };
101911
+ if (clampMin === void 0 || clampMax === void 0) return fail("clamp");
101912
+ const min = signedToken(clampMin);
101913
+ const max = signedToken(clampMax);
101914
+ if (min === null || max === null || clampMin > clampMax) return fail("clamp");
101915
+ return {
101916
+ ok: true,
101917
+ value: {
101918
+ min,
101919
+ max
101920
+ }
101921
+ };
101922
+ }
101923
+ function enumValue(transform, read, field) {
101924
+ const allowed = new Set(field.enumValues ?? []);
101925
+ const entries = Object.entries(transform.mapping);
101926
+ if (entries.length === 0) return fail("enum");
101927
+ if (entries.some(([key, value]) => key.length === 0 || value !== null && !allowed.has(value))) return fail("enum");
101928
+ const expr = enumMapExpr(transform.mapping);
101929
+ if (expr === null) return fail("enum");
101930
+ return {
101931
+ ok: true,
101932
+ value: expression(expr, { x: read })
101933
+ };
101934
+ }
101935
+ function compileLiterals(target, field, item, value) {
101936
+ const required = new Set((field.literals ?? []).map((literalSpec) => literalSpec.path));
101937
+ const traits = new Map((target.traits ?? []).map((trait) => [trait.path, new Set(trait.values)]));
101938
+ if ([...required].filter((path) => !item.literals.some((literalSpec) => literalSpec.path === path)).length > 0) return fail("literal");
101939
+ return item.literals.reduce((acc, entry) => {
101940
+ if (!acc.ok) return acc;
101941
+ if (entry.path === field.path || acc.value[entry.path] !== void 0) return fail("literal");
101942
+ const allowed = allowedLiteral(field, traits, entry.path);
101943
+ if (allowed === null || !allowed.has(entry.value)) return fail("literal");
101944
+ const expr = constantExpr(entry.value);
101945
+ if (expr === null) return fail("literal");
101946
+ return {
101947
+ ok: true,
101948
+ value: {
101949
+ ...acc.value,
101950
+ [entry.path]: literal(expr)
101951
+ }
101952
+ };
101953
+ }, {
101954
+ ok: true,
101955
+ value: { [field.path]: value }
101956
+ });
101957
+ }
101958
+ function allowedLiteral(field, traits, path) {
101959
+ const trait = traits.get(path);
101960
+ if (trait !== void 0) return trait;
101961
+ const required = (field.literals ?? []).find((entry) => entry.path === path);
101962
+ return required === void 0 ? null : new Set(required.values);
101963
+ }
101964
+ function compileCompanions(target, apply) {
101965
+ return (target.companions ?? []).filter((companion) => companionIncluded(companion, apply)).reduce((acc, companion) => {
101966
+ if (!acc.ok) return acc;
101967
+ if (companion.kind !== "clock") return fail("companion");
101968
+ return {
101969
+ ok: true,
101970
+ value: {
101971
+ ...acc.value,
101972
+ [companion.path]: literal("now")
101973
+ }
101974
+ };
101975
+ }, {
101976
+ ok: true,
101977
+ value: {}
101978
+ });
101979
+ }
101980
+ function companionIncluded(companion, apply) {
101981
+ if (companion.kind === "transition-time") return false;
101982
+ return companion.when === "always" || apply === "add";
101983
+ }
101984
+ function refOf(draft) {
101985
+ return {
101986
+ addonId: draft.source.addonId,
101987
+ stableId: draft.source.stableId
101988
+ };
101989
+ }
101990
+ //#endregion
101991
+ //#region src/composition/customize/keyed-array-decode.ts
101992
+ var catalog = CAP_CUSTOMIZE_CATALOG;
101993
+ function readKeyedArrayItems(feature, cap, targetId) {
101994
+ const target = catalogTarget(cap, targetId);
101995
+ if (target === null || target.cardinality !== "keyedArray" || feature.cap !== cap) return null;
101996
+ const apply = inferApply(target, feature.fields);
101997
+ const canonical = apply !== null && companionsMatch(target, feature.fields, apply);
101998
+ const items = Object.entries(feature.items ?? {}).map(([key, item]) => viewOf(target, cap, targetId, key, item, canonical));
101999
+ return {
102000
+ canonical,
102001
+ apply: apply ?? "add",
102002
+ items
102003
+ };
102004
+ }
102005
+ function decodeKeyedArrayOverride(input) {
102006
+ const read = readKeyedArrayItems(input.feature, input.cap, input.targetId);
102007
+ if (read === null || !read.canonical) return null;
102008
+ if (read.items.some((item) => item.compile === null)) return null;
102009
+ const compiles = read.items.flatMap((item) => item.compile === null ? [] : [item.compile]);
102010
+ const compiled = compileKeyedArrayOverride({
102011
+ cap: input.cap,
102012
+ targetId: input.targetId,
102013
+ device: input.device,
102014
+ apply: read.apply,
102015
+ items: compiles
102016
+ });
102017
+ if (!compiled.ok) return null;
102018
+ return sameFeature(compiled.value, input.feature) ? read : null;
102019
+ }
102020
+ function viewOf(target, cap, targetId, key, item, canonical) {
102021
+ const blank = {
102022
+ key,
102023
+ label: item.label,
102024
+ recognized: false,
102025
+ compile: null
102026
+ };
102027
+ if (!canonical) return blank;
102028
+ const compile = compileOf(target, cap, targetId, key, item);
102029
+ if (compile === null) return blank;
102030
+ return {
102031
+ key,
102032
+ label: item.label,
102033
+ recognized: true,
102034
+ compile
102035
+ };
102036
+ }
102037
+ function compileOf(target, cap, targetId, key, item) {
102038
+ const assigned = assignedField(target, item);
102039
+ if (assigned === null) return null;
102040
+ const literals = literalFields(target, assigned.field, item, assigned.path);
102041
+ if (literals === null) return null;
102042
+ const draft = draftOf(cap, targetId, key, item.label, assigned);
102043
+ if (draft === null) return null;
102044
+ const compile = {
102045
+ draft,
102046
+ sourceValueKind: assigned.sourceValueKind,
102047
+ sourceUnit: null,
102048
+ literals
102049
+ };
102050
+ return reproduces(cap, targetId, key, compile, item) ? compile : null;
102051
+ }
102052
+ function assignedField(target, item) {
102053
+ const paths = Object.keys(item.fields).filter((path) => !isConstant(item.fields[path]));
102054
+ if (paths.length !== 1) return null;
102055
+ const path = paths[0];
102056
+ if (path === void 0) return null;
102057
+ const field = (target.fields ?? []).find((entry) => entry.path === path);
102058
+ const source = item.fields[path];
102059
+ if (field === void 0 || source === void 0) return null;
102060
+ const read = readTransform(source, field);
102061
+ if (read === null) return null;
102062
+ return {
102063
+ path,
102064
+ field,
102065
+ source,
102066
+ ...read
102067
+ };
102068
+ }
102069
+ function readTransform(source, field) {
102070
+ if (source.kind === "from") return field.valueKind === "enum" ? {
102071
+ sourceValueKind: "enum",
102072
+ transform: { kind: "identity" }
102073
+ } : {
102074
+ sourceValueKind: "number",
102075
+ transform: { kind: "identity" }
102076
+ };
102077
+ if (source.kind !== "expression") return null;
102078
+ const mapped = parseEnumMap(source.expr);
102079
+ if (mapped !== null && field.valueKind === "enum") return {
102080
+ sourceValueKind: "enum",
102081
+ transform: enumMapDraft(mapped)
102082
+ };
102083
+ const linear = parseLinear(source.expr);
102084
+ if (linear === null || linear.inner !== "x" || field.valueKind !== "number") return null;
102085
+ return {
102086
+ sourceValueKind: "number",
102087
+ transform: {
102088
+ kind: "linear",
102089
+ scale: linear.scale,
102090
+ offset: linear.offset,
102091
+ ...linear.clampMin === void 0 || linear.clampMax === void 0 ? {} : {
102092
+ clampMin: linear.clampMin,
102093
+ clampMax: linear.clampMax
102094
+ }
102095
+ }
102096
+ };
102097
+ }
102098
+ function literalFields(target, field, item, assignedPath) {
102099
+ const required = new Set((field.literals ?? []).map((entry) => entry.path));
102100
+ const traits = new Set((target.traits ?? []).map((trait) => trait.path));
102101
+ const found = Object.keys(item.fields).filter((path) => path !== assignedPath);
102102
+ if (found.some((path) => !required.has(path) && !traits.has(path))) return null;
102103
+ if ([...required].some((path) => !found.includes(path))) return null;
102104
+ const literals = found.map((path) => literalValue(item.fields[path], path));
102105
+ if (literals.some((entry) => entry === null)) return null;
102106
+ return literals.flatMap((entry) => entry === null ? [] : [entry]);
102107
+ }
102108
+ function literalValue(source, path) {
102109
+ if (source?.kind !== "expression" || Object.keys(source.bindings).length !== 0) return null;
102110
+ if (!(source.expr.startsWith("\"") && source.expr.endsWith("\""))) return null;
102111
+ try {
102112
+ const parsed = JSON.parse(source.expr);
102113
+ return typeof parsed === "string" ? {
102114
+ path,
102115
+ value: parsed
102116
+ } : null;
102117
+ } catch {
102118
+ return null;
102119
+ }
102120
+ }
102121
+ function draftOf(cap, targetId, key, label, assigned) {
102122
+ const bound = singleFrom(assigned.source);
102123
+ if (bound === null) return null;
102124
+ return {
102125
+ kind: "keyedArray",
102126
+ cap,
102127
+ targetId,
102128
+ key,
102129
+ label,
102130
+ fieldPath: assigned.path,
102131
+ source: {
102132
+ addonId: bound.addonId,
102133
+ stableId: bound.stableId,
102134
+ cap: bound.cap,
102135
+ fieldPath: bound.fieldPath
102136
+ },
102137
+ transform: assigned.transform
102138
+ };
102139
+ }
102140
+ function reproduces(cap, targetId, key, compile, item) {
102141
+ const compiled = compileKeyedArrayOverride({
102142
+ cap,
102143
+ targetId,
102144
+ device: {
102145
+ addonId: "t",
102146
+ stableId: "t"
102147
+ },
102148
+ apply: "add",
102149
+ items: [compile]
102150
+ });
102151
+ if (!compiled.ok) return false;
102152
+ const written = compiled.value.items?.[key];
102153
+ if (written === void 0) return false;
102154
+ return JSON.stringify(written) === JSON.stringify(item);
102155
+ }
102156
+ function isConstant(source) {
102157
+ return source?.kind === "expression" && Object.keys(source.bindings).length === 0;
102158
+ }
102159
+ function inferApply(target, fields) {
102160
+ const addPaths = (target.companions ?? []).flatMap((companion) => companion.kind !== "transition-time" && companion.when === "add" ? [companion.path] : []);
102161
+ if (addPaths.length === 0) return "replace";
102162
+ const present = addPaths.filter((path) => fields[path] !== void 0);
102163
+ if (present.length === addPaths.length) return "add";
102164
+ if (present.length === 0) return "replace";
102165
+ return null;
102166
+ }
102167
+ function companionsMatch(target, fields, apply) {
102168
+ const expected = (target.companions ?? []).flatMap((companion) => {
102169
+ if (companion.kind === "transition-time") return [];
102170
+ if (companion.when === "always" || apply === "add") return [companion.path];
102171
+ return [];
102172
+ });
102173
+ if (Object.keys(fields).toSorted().join(",") !== [...expected].toSorted().join(",")) return false;
102174
+ return expected.every((path) => isLiteral(fields[path], "now"));
102175
+ }
102176
+ function catalogTarget(cap, targetId) {
102177
+ const entry = catalog[cap];
102178
+ if (entry === void 0) return null;
102179
+ return entry.targets.find((target) => target.id === targetId) ?? null;
102180
+ }
102181
+ function sameFeature(compiled, stored) {
102182
+ return sameStored(wrap(stripEnabled(compiled)), wrap(stripEnabled(stored)));
102183
+ }
102184
+ function stripEnabled(feature) {
102185
+ const { enabled: _enabled, ...rest } = feature;
102186
+ return rest;
102187
+ }
102188
+ function wrap(feature) {
102189
+ return {
102190
+ family: "composition",
102191
+ target: {
102192
+ addonId: "t",
102193
+ stableId: "t"
102194
+ },
102195
+ feature
102196
+ };
102197
+ }
102198
+ //#endregion
102199
+ //#region src/composition/customize/keyed-array-status.ts
102200
+ function projectKeyedArrayAssignment(input) {
102201
+ if (input.stored.kind === "pending") return unanswered(input.targetId, "pending", null);
102202
+ if (input.stored.kind === "unknown") return unanswered(input.targetId, "unknown", input.stored.reason ?? "unknown");
102203
+ if (input.stored.value === null) return native(input.targetId);
102204
+ const read = readKeyedArrayItems(input.stored.value, input.cap, input.targetId);
102205
+ const count = read?.items.filter((item) => item.recognized).length ?? 0;
102206
+ if (read === null || !read.canonical || count === 0) return {
102207
+ text: "unknown",
102208
+ assignedCount: 0,
102209
+ status: status(input.targetId, true, "assigned", "unavailable", "not-canonical")
102210
+ };
102211
+ return projectDecoded(input, count);
102212
+ }
102213
+ function projectDecoded(input, count) {
102214
+ const text = `${count} assigned`;
102215
+ if (input.sourcePresence === "pending") return {
102216
+ text: "pending",
102217
+ assignedCount: count,
102218
+ status: status(input.targetId, true, "assigned", "stale", null)
102219
+ };
102220
+ if (input.sourcePresence === "unknown") return {
102221
+ text: "unknown",
102222
+ assignedCount: count,
102223
+ status: status(input.targetId, true, "assigned", "stale", input.sourceUnknownReason ?? "unknown")
102224
+ };
102225
+ if (input.sourcePresence === "absent") return {
102226
+ text,
102227
+ assignedCount: count,
102228
+ status: status(input.targetId, true, "assigned", "unavailable", "source-missing")
102229
+ };
102230
+ return {
102231
+ text,
102232
+ assignedCount: count,
102233
+ status: status(input.targetId, true, "assigned", "active", null)
102234
+ };
102235
+ }
102236
+ function native(targetId) {
102237
+ return {
102238
+ text: "Native",
102239
+ assignedCount: 0,
102240
+ status: status(targetId, false, "native", "active", null)
102241
+ };
102242
+ }
102243
+ function unanswered(targetId, text, reason) {
102244
+ return {
102245
+ text,
102246
+ assignedCount: 0,
102247
+ status: status(targetId, false, "native", text === "pending" ? "unavailable" : "stale", reason)
102248
+ };
102249
+ }
102250
+ function status(targetId, configured, source, state, reason) {
102251
+ return {
102252
+ targetId,
102253
+ configured,
102254
+ source,
102255
+ state,
102256
+ reason
102257
+ };
102258
+ }
102259
+ //#endregion
100294
102260
  //#region src/generated/scope-presets.ts
100295
102261
  var SCOPE_PRESETS = [
100296
102262
  {
@@ -111026,6 +112992,7 @@ exports.CAMSTACK_EVENT_PREFIX = CAMSTACK_EVENT_PREFIX;
111026
112992
  exports.CAM_PROFILE_ORDER = require_sleep.CAM_PROFILE_ORDER;
111027
112993
  exports.CAPABILITY_NAMES = CAPABILITY_NAMES;
111028
112994
  exports.CAPABILITY_ROUTER_KEYS = CAPABILITY_ROUTER_KEYS;
112995
+ exports.CAP_CUSTOMIZE_CATALOG = CAP_CUSTOMIZE_CATALOG;
111029
112996
  exports.CAP_NAMES_WITH_STATUS = CAP_NAMES_WITH_STATUS;
111030
112997
  exports.CAP_NODE_PIN_CONTEXT_KEY = require_sleep.CAP_NODE_PIN_CONTEXT_KEY;
111031
112998
  exports.CAP_PROVIDER_KIND_MAP = CAP_PROVIDER_KIND_MAP;
@@ -111254,6 +113221,7 @@ exports.CredentialScopeSchema = CredentialScopeSchema;
111254
113221
  exports.CredentialTokenClaimsSchema = CredentialTokenClaimsSchema;
111255
113222
  exports.CustomActionInputSchema = CustomActionInputSchema;
111256
113223
  exports.CustomModelDescriptorSchema = CustomModelDescriptorSchema;
113224
+ exports.CustomizeAssignmentStatusSchema = CustomizeAssignmentStatusSchema;
111257
113225
  exports.DATABASE_SNAPSHOT_PARTIAL_SUFFIX = DATABASE_SNAPSHOT_PARTIAL_SUFFIX;
111258
113226
  exports.DATABASE_SNAPSHOT_SUFFIX = DATABASE_SNAPSHOT_SUFFIX;
111259
113227
  exports.DATABASE_SNAPSHOT_TIMEOUT_MS = DATABASE_SNAPSHOT_TIMEOUT_MS;
@@ -111595,6 +113563,8 @@ exports.ICON_ENTRIES = ICON_ENTRIES;
111595
113563
  exports.ICON_KEYS = ICON_KEYS;
111596
113564
  exports.ICON_VIEWER_MODULES = ICON_VIEWER_MODULES;
111597
113565
  exports.INFERENCE_DEVICE_EXCLUSION_REASONS = INFERENCE_DEVICE_EXCLUSION_REASONS;
113566
+ exports.INITIAL_PULSE = INITIAL_PULSE;
113567
+ exports.INITIAL_SPAN = INITIAL_SPAN;
111598
113568
  exports.INVERTIBLE_CAPS = INVERTIBLE_CAPS;
111599
113569
  exports.IconKeySchema = IconKeySchema;
111600
113570
  exports.ImageContractSchema = ImageContractSchema;
@@ -111776,6 +113746,7 @@ exports.MOTION_CROP_MAX_REGIONS = MOTION_CROP_MAX_REGIONS;
111776
113746
  exports.MOTION_CROP_MOTION_PAD = MOTION_CROP_MOTION_PAD;
111777
113747
  exports.MOTION_CROP_TRACKED_PAD = MOTION_CROP_TRACKED_PAD;
111778
113748
  exports.MOTION_SOURCE_LABELS = MOTION_SOURCE_LABELS;
113749
+ exports.MOTION_SPAN_TIMEOUT_MS = MOTION_SPAN_TIMEOUT_MS;
111779
113750
  exports.MOTION_TRIGGER_FEATURE = MOTION_TRIGGER_FEATURE;
111780
113751
  exports.ManagedModelCatalogEntrySchema = ManagedModelCatalogEntrySchema;
111781
113752
  exports.ManagedModelExtraFileSchema = ManagedModelExtraFileSchema;
@@ -112151,6 +114122,7 @@ exports.OsdTemplateBindingSchema = OsdTemplateBindingSchema;
112151
114122
  exports.OsdTemplateFormatSchema = OsdTemplateFormatSchema;
112152
114123
  exports.OsdTemplatePickSchema = OsdTemplatePickSchema;
112153
114124
  exports.OsdTemplateTokenKindSchema = OsdTemplateTokenKindSchema;
114125
+ exports.OverrideDraftSchema = OverrideDraftSchema;
112154
114126
  exports.PEER_BYTES_CHUNK_BYTES = require_sleep.PEER_BYTES_CHUNK_BYTES;
112155
114127
  exports.PEER_BYTES_MAX_OUTSTANDING = require_sleep.PEER_BYTES_MAX_OUTSTANDING;
112156
114128
  exports.PEER_BYTES_STALL_MS = require_sleep.PEER_BYTES_STALL_MS;
@@ -112314,6 +114286,7 @@ exports.ROOT_SUPPLIABLE_STEP_IDS = ROOT_SUPPLIABLE_STEP_IDS;
112314
114286
  exports.RUNNING_POWER_START_DELAY_MS = RUNNING_POWER_START_DELAY_MS;
112315
114287
  exports.RUNNING_POWER_STOP_DELAY_MS = RUNNING_POWER_STOP_DELAY_MS;
112316
114288
  exports.RUNNING_POWER_THRESHOLD_WATTS = RUNNING_POWER_THRESHOLD_WATTS;
114289
+ exports.RUNNING_STATE_COLD = RUNNING_STATE_COLD;
112317
114290
  exports.RUNTIME_DEFAULTS = require_sleep.RUNTIME_DEFAULTS;
112318
114291
  exports.RUNTIME_STATE_POLICY = RUNTIME_STATE_POLICY;
112319
114292
  exports.RUNTIME_STATE_REFRESH_MISS_COOLDOWN_MS = RUNTIME_STATE_REFRESH_MISS_COOLDOWN_MS;
@@ -112742,6 +114715,7 @@ exports.UninstallNodeResultSchema = UninstallNodeResultSchema;
112742
114715
  exports.UninstallPackageResultSchema = UninstallPackageResultSchema;
112743
114716
  exports.UnitConversionError = UnitConversionError;
112744
114717
  exports.UnknownRecordKindError = require_sleep.UnknownRecordKindError;
114718
+ exports.UnreleasedClaimSchema = UnreleasedClaimSchema;
112745
114719
  exports.UnstampedEventMediaCountSchema = UnstampedEventMediaCountSchema;
112746
114720
  exports.UnstampedRowsSchema = UnstampedRowsSchema;
112747
114721
  exports.UpdateBlockerSchema = UpdateBlockerSchema;
@@ -112906,7 +114880,6 @@ exports.buildCapabilityLookup = buildCapabilityLookup;
112906
114880
  exports.buildDeviceAdminUrl = buildDeviceAdminUrl;
112907
114881
  exports.buildDeviceEnrollmentLink = buildDeviceEnrollmentLink;
112908
114882
  exports.buildDeviceSignatureMessage = buildDeviceSignatureMessage;
112909
- exports.buildDoorbellCompositionFeature = buildDoorbellCompositionFeature;
112910
114883
  exports.buildEventKindDescriptor = buildEventKindDescriptor;
112911
114884
  exports.buildFfmpegArgs = require_composition.buildFfmpegArgs;
112912
114885
  exports.buildFrigateClassMap = buildFrigateClassMap;
@@ -112980,6 +114953,10 @@ exports.commitWatchdogRestart = commitWatchdogRestart;
112980
114953
  exports.compareToTarget = compareToTarget;
112981
114954
  exports.compileExpression = require_composition.compileExpression;
112982
114955
  exports.compileExpressionSafe = require_composition.compileExpressionSafe;
114956
+ exports.compileKeyedArrayOverride = compileKeyedArrayOverride;
114957
+ exports.compilePulseOverride = compilePulseOverride;
114958
+ exports.compileScalarOverride = compileScalarOverride;
114959
+ exports.compileSpanOverride = compileSpanOverride;
112983
114960
  exports.composeSwitchedOff = composeSwitchedOff;
112984
114961
  exports.composedDeviceRef = require_composition.composedDeviceRef;
112985
114962
  exports.composedDeviceStableId = require_composition.composedDeviceStableId;
@@ -113044,6 +115021,9 @@ exports.dayOfWeekToIndex = dayOfWeekToIndex;
113044
115021
  exports.declarationOwnerNodeId = declarationOwnerNodeId;
113045
115022
  exports.declarationsOf = require_sleep.declarationsOf;
113046
115023
  exports.declareLogChannel = declareLogChannel;
115024
+ exports.decodeKeyedArrayOverride = decodeKeyedArrayOverride;
115025
+ exports.decodePulseOverride = decodePulseOverride;
115026
+ exports.decodeScalarOverride = decodeScalarOverride;
113047
115027
  exports.decodeVectorBase64 = decodeVectorBase64;
113048
115028
  exports.decoderCapability = decoderCapability;
113049
115029
  exports.defaultDeliveryForSection = defaultDeliveryForSection;
@@ -113102,7 +115082,6 @@ exports.dishwasherCapability = dishwasherCapability;
113102
115082
  exports.doActionSelectValue = doActionSelectValue;
113103
115083
  exports.dominantClipLabels = dominantClipLabels;
113104
115084
  exports.doorbellCapability = doorbellCapability;
113105
- exports.doorbellFeatureSources = doorbellFeatureSources;
113106
115085
  exports.droppedConditionsForKind = droppedConditionsForKind;
113107
115086
  exports.edgetpuDelegateDevice = edgetpuDelegateDevice;
113108
115087
  exports.effectiveStepSettings = effectiveStepSettings;
@@ -113280,7 +115259,6 @@ exports.isRemovedModelId = isRemovedModelId;
113280
115259
  exports.isRestoredCap = isRestoredCap;
113281
115260
  exports.isRetiredClearKey = isRetiredClearKey;
113282
115261
  exports.isRootSuppliableStepId = isRootSuppliableStepId;
113283
- exports.isRunningAssignmentFeature = isRunningAssignmentFeature;
113284
115262
  exports.isSameAddonId = isSameAddonId;
113285
115263
  exports.isScheduleActive = isScheduleActive;
113286
115264
  exports.isSecretClear = require_sleep.isSecretClear;
@@ -113355,6 +115333,7 @@ exports.measuredDetectorCells = measuredDetectorCells;
113355
115333
  exports.mediaPlayerCapability = mediaPlayerCapability;
113356
115334
  exports.memoizePinnedFfmpeg = memoizePinnedFfmpeg;
113357
115335
  exports.mergeClipLabels = mergeClipLabels;
115336
+ exports.mergeKeyedArrayItem = mergeKeyedArrayItem;
113358
115337
  exports.mergeSecretStatePaths = require_sleep.mergeSecretStatePaths;
113359
115338
  exports.mergeSettingsBags = mergeSettingsBags;
113360
115339
  exports.mergeSourceInfo = mergeSourceInfo;
@@ -113481,6 +115460,10 @@ exports.pressureSensorCapability = pressureSensorCapability;
113481
115460
  exports.principalMayReachAddon = principalMayReachAddon;
113482
115461
  exports.privacyMaskCapability = privacyMaskCapability;
113483
115462
  exports.procedureAuthKey = procedureAuthKey;
115463
+ exports.projectKeyedArrayAssignment = projectKeyedArrayAssignment;
115464
+ exports.projectPulseAssignment = projectPulseAssignment;
115465
+ exports.projectScalarAssignment = projectScalarAssignment;
115466
+ exports.projectSpanAssignment = projectSpanAssignment;
113484
115467
  exports.projectSubjectPath = projectSubjectPath;
113485
115468
  exports.providerMotionEvent = providerMotionEvent;
113486
115469
  exports.ptzAutotrackCapability = ptzAutotrackCapability;
@@ -113496,6 +115479,7 @@ exports.readErrorI18n = require_sleep.readErrorI18n;
113496
115479
  exports.readFaceRescoreIntervalMinutes = readFaceRescoreIntervalMinutes;
113497
115480
  exports.readHubMotionDetected = readHubMotionDetected;
113498
115481
  exports.readHubMotionStatus = readHubMotionStatus;
115482
+ exports.readKeyedArrayItems = readKeyedArrayItems;
113499
115483
  exports.readMotionTriggeredBy = readMotionTriggeredBy;
113500
115484
  exports.readNativeLeaseOverride = readNativeLeaseOverride;
113501
115485
  exports.readNodePin = require_sleep.readNodePin;
@@ -113598,8 +115582,6 @@ exports.ruleSectionOf = ruleSectionOf;
113598
115582
  exports.ruleSeedForSection = ruleSeedForSection;
113599
115583
  exports.ruleTriggerZoneIds = ruleTriggerZoneIds;
113600
115584
  exports.runInferenceStep = runInferenceStep;
113601
- exports.runningAssignmentFeature = runningAssignmentFeature;
113602
- exports.runningAssignmentRecovered = runningAssignmentRecovered;
113603
115585
  exports.runningFromDishwasherOperation = runningFromDishwasherOperation;
113604
115586
  exports.runningFromLawnMower = runningFromLawnMower;
113605
115587
  exports.runningFromMediaPlayer = runningFromMediaPlayer;
@@ -113662,7 +115644,9 @@ exports.startReachabilityPoll = startReachabilityPoll;
113662
115644
  exports.stateLabel = stateLabel;
113663
115645
  exports.stateVocabularyFor = stateVocabularyFor;
113664
115646
  exports.stepModelRunsOnFormat = stepModelRunsOnFormat;
115647
+ exports.stepPulse = stepPulse;
113665
115648
  exports.stepSettingSource = stepSettingSource;
115649
+ exports.stepSpan = stepSpan;
113666
115650
  exports.storageAdminCapability = storageAdminCapability;
113667
115651
  exports.storageCapability = storageCapability;
113668
115652
  exports.storageEvictableCapability = storageEvictableCapability;
@@ -113780,6 +115764,7 @@ exports.withLocationMode = withLocationMode;
113780
115764
  exports.withSystemEventClasses = withSystemEventClasses;
113781
115765
  exports.withoutCallerStamp = require_sleep.withoutCallerStamp;
113782
115766
  exports.withoutField = withoutField;
115767
+ exports.withoutKeyedArrayItem = withoutKeyedArrayItem;
113783
115768
  exports.writeModelBoundSetting = writeModelBoundSetting;
113784
115769
  exports.zodEntriesToConfigUI = zodEntriesToConfigUI;
113785
115770
  exports.zoneAnalyticsCapability = zoneAnalyticsCapability;