@camstack/types 1.2.406 → 1.2.407
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capabilities/battery.cap.d.ts +46 -0
- package/dist/capabilities/capability-definition.d.ts +8 -0
- package/dist/capabilities/consumables.cap.d.ts +110 -0
- package/dist/capabilities/customize-catalog.d.ts +72 -0
- package/dist/capabilities/customize-spec.d.ts +202 -0
- package/dist/capabilities/doorbell.cap.d.ts +39 -0
- package/dist/capabilities/index.d.ts +2 -2
- package/dist/capabilities/motion.cap.d.ts +39 -0
- package/dist/capabilities/running-state.cap.d.ts +68 -4
- package/dist/catalogs/sensor-active-state.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/client.mjs +1 -1
- package/dist/composition/customize/__fixtures__/refs.d.ts +27 -0
- package/dist/composition/customize/__fixtures__/stored-cases.d.ts +13 -0
- package/dist/composition/customize/event-compile.d.ts +20 -0
- package/dist/composition/customize/event-decode.d.ts +19 -0
- package/dist/composition/customize/event-eval.d.ts +35 -0
- package/dist/composition/customize/event-status.d.ts +49 -0
- package/dist/composition/customize/field-source.d.ts +5 -0
- package/dist/composition/customize/keyed-array-compile.d.ts +26 -0
- package/dist/composition/customize/keyed-array-decode.d.ts +20 -0
- package/dist/composition/customize/keyed-array-expr.d.ts +10 -0
- package/dist/composition/customize/keyed-array-status.d.ts +22 -0
- package/dist/composition/customize/normalize.d.ts +4 -0
- package/dist/composition/customize/override-draft.d.ts +311 -0
- package/dist/composition/customize/scalar-compile.d.ts +13 -0
- package/dist/composition/customize/scalar-decode.d.ts +17 -0
- package/dist/composition/customize/scalar-expr.d.ts +33 -0
- package/dist/composition/customize/scalar-status.d.ts +31 -0
- package/dist/composition/customize/stored.d.ts +15 -0
- package/dist/composition/index.d.ts +0 -1
- package/dist/{composition-xz-ud5EQ.mjs → composition-BJ8iAZb3.mjs} +1 -1
- package/dist/{composition-RmnnN39T.js → composition-CSLSFGTO.js} +1 -1
- package/dist/generated/customize-catalog.d.ts +229 -0
- package/dist/index.d.ts +14 -1
- package/dist/index.js +2245 -290
- package/dist/index.mjs +2223 -286
- package/dist/node.js +1 -1
- package/dist/node.mjs +1 -1
- package/dist/running-state/defaults.d.ts +3 -0
- package/dist/running-state/from-operation.d.ts +4 -4
- package/package.json +1 -1
- package/dist/composition/presets/doorbell-feature.d.ts +0 -20
- 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-
|
|
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");
|
|
@@ -60326,20 +60326,68 @@ var BatteryStatusSchema = zod.z.object({
|
|
|
60326
60326
|
*/
|
|
60327
60327
|
binary: zod.z.boolean().optional()
|
|
60328
60328
|
});
|
|
60329
|
+
var BATTERY_DEVICE_TYPES = [
|
|
60330
|
+
require_err_msg.DeviceType.Camera,
|
|
60331
|
+
require_err_msg.DeviceType.Sensor,
|
|
60332
|
+
require_err_msg.DeviceType.Button,
|
|
60333
|
+
require_err_msg.DeviceType.Switch,
|
|
60334
|
+
require_err_msg.DeviceType.PetFeeder,
|
|
60335
|
+
require_err_msg.DeviceType.Container,
|
|
60336
|
+
require_err_msg.DeviceType.Thermostat
|
|
60337
|
+
];
|
|
60338
|
+
/** Generic Customize target for the percentage reading (D936). */
|
|
60339
|
+
var batteryCustomize = {
|
|
60340
|
+
version: 1,
|
|
60341
|
+
targets: [{
|
|
60342
|
+
id: "percentage",
|
|
60343
|
+
cardinality: "scalar",
|
|
60344
|
+
vocabulary: {
|
|
60345
|
+
cap: "battery",
|
|
60346
|
+
stateField: "percentage"
|
|
60347
|
+
},
|
|
60348
|
+
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
60349
|
+
apply: "add-or-replace",
|
|
60350
|
+
path: "percentage",
|
|
60351
|
+
sources: [{
|
|
60352
|
+
kind: "field",
|
|
60353
|
+
valueKinds: ["number", "string"],
|
|
60354
|
+
transforms: [{ kind: "identity" }, {
|
|
60355
|
+
kind: "linear",
|
|
60356
|
+
defaultScale: 1,
|
|
60357
|
+
defaultOffset: 0,
|
|
60358
|
+
clampMin: 0,
|
|
60359
|
+
clampMax: 100
|
|
60360
|
+
}]
|
|
60361
|
+
}],
|
|
60362
|
+
companions: [
|
|
60363
|
+
{
|
|
60364
|
+
kind: "constant",
|
|
60365
|
+
path: "charging",
|
|
60366
|
+
value: "unknown",
|
|
60367
|
+
when: "add"
|
|
60368
|
+
},
|
|
60369
|
+
{
|
|
60370
|
+
kind: "constant",
|
|
60371
|
+
path: "sleeping",
|
|
60372
|
+
value: false,
|
|
60373
|
+
when: "add"
|
|
60374
|
+
},
|
|
60375
|
+
{
|
|
60376
|
+
kind: "clock",
|
|
60377
|
+
path: "lastUpdated",
|
|
60378
|
+
when: "add"
|
|
60379
|
+
}
|
|
60380
|
+
],
|
|
60381
|
+
sourceReport: { status: "assignment-status" },
|
|
60382
|
+
advancedExpression: true
|
|
60383
|
+
}]
|
|
60384
|
+
};
|
|
60329
60385
|
var batteryCapability = {
|
|
60330
60386
|
name: "battery",
|
|
60331
60387
|
scope: "device",
|
|
60332
60388
|
deviceNative: true,
|
|
60333
60389
|
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
|
-
],
|
|
60390
|
+
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
60343
60391
|
methods: {
|
|
60344
60392
|
/**
|
|
60345
60393
|
* Explicitly wake the camera from low-power sleep ahead of a
|
|
@@ -60423,6 +60471,7 @@ onStatusChanged: { data: zod.z.object({
|
|
|
60423
60471
|
kind: "gauge",
|
|
60424
60472
|
unit: "%"
|
|
60425
60473
|
} } },
|
|
60474
|
+
customize: batteryCustomize,
|
|
60426
60475
|
/** Clock fields: written, but excluded from the compare that decides
|
|
60427
60476
|
* whether persisting is worth a SQLite commit. */
|
|
60428
60477
|
volatileStateFields: ["lastUpdated"]
|
|
@@ -61621,6 +61670,106 @@ var ConsumablesStatusSchema = zod.z.object({
|
|
|
61621
61670
|
items: zod.z.array(ConsumableItemSchema),
|
|
61622
61671
|
lastChangedAt: zod.z.number()
|
|
61623
61672
|
});
|
|
61673
|
+
/** Synthesize seed for a link-built status (no native provider).
|
|
61674
|
+
*
|
|
61675
|
+
* ⚠ NO LIVE CALLER since 2026-08-08 (device-links deleted; see
|
|
61676
|
+
* `CapabilityStatusSchema.empty`). The wiring guidance below was written for
|
|
61677
|
+
* exactly the case the operator is asking about again — a Dreame's HA
|
|
61678
|
+
* consumable-life sensors — so it is kept for that conversation, not because
|
|
61679
|
+
* anything reads it today. */
|
|
61680
|
+
var EMPTY_STATUS = {
|
|
61681
|
+
items: [],
|
|
61682
|
+
lastChangedAt: 0
|
|
61683
|
+
};
|
|
61684
|
+
/** Seed for a NEW link-built consumable item. `key`/`label` are overwritten
|
|
61685
|
+
* with the link's `itemKey` (see `status.itemArray`), so the placeholder
|
|
61686
|
+
* empty strings never survive into a validated item. Link-built items are
|
|
61687
|
+
* not resettable — there is no native provider to receive `reset()`.
|
|
61688
|
+
*
|
|
61689
|
+
* Wiring guidance (HA vacuum consumable-life sensors):
|
|
61690
|
+
* - a percent-remaining source (`numeric-sensor`, unit '%') → `level` via
|
|
61691
|
+
* `identity` (or `linear` scale 1 offset 0 clamp [0,100] to be safe);
|
|
61692
|
+
* - an hours-remaining source (e.g. Dreame 'Main Brush Time Left', unit 'h')
|
|
61693
|
+
* → `level` via `linear` with scale = 100 / max-hours for that item
|
|
61694
|
+
* (e.g. main brush 300 h → scale 0.3333) + clamp [0,100];
|
|
61695
|
+
* - a discrete source (`enum-sensor`, e.g. mop pad 'installed') → `status`
|
|
61696
|
+
* via `enum-map` (e.g. { installed: 'ok', missing: 'replace' }).
|
|
61697
|
+
* A numeric→'replace' THRESHOLD (level < 10 → 'replace') is NOT expressible
|
|
61698
|
+
* with the current transform kinds — leave `status` null (valid) until the
|
|
61699
|
+
* expression transform lands. */
|
|
61700
|
+
/** Generic Customize target for one consumable item (D936). Native rows stay read-only. */
|
|
61701
|
+
var consumablesCustomize = {
|
|
61702
|
+
version: 1,
|
|
61703
|
+
targets: [{
|
|
61704
|
+
id: "items",
|
|
61705
|
+
cardinality: "keyedArray",
|
|
61706
|
+
vocabulary: { cap: "consumables" },
|
|
61707
|
+
deviceTypes: Object.values(require_err_msg.DeviceType),
|
|
61708
|
+
apply: "add",
|
|
61709
|
+
path: "items",
|
|
61710
|
+
keyField: "key",
|
|
61711
|
+
labelField: "label",
|
|
61712
|
+
itemSchema: ConsumableItemSchema,
|
|
61713
|
+
nativeItems: "read-only",
|
|
61714
|
+
sourceReport: { status: "assignment-status" },
|
|
61715
|
+
fields: [
|
|
61716
|
+
{
|
|
61717
|
+
path: "level",
|
|
61718
|
+
sources: [{
|
|
61719
|
+
kind: "numeric",
|
|
61720
|
+
transforms: [{ kind: "identity" }, {
|
|
61721
|
+
kind: "linear",
|
|
61722
|
+
defaultScale: 1,
|
|
61723
|
+
defaultOffset: 0,
|
|
61724
|
+
clampMin: 0,
|
|
61725
|
+
clampMax: 100
|
|
61726
|
+
}]
|
|
61727
|
+
}]
|
|
61728
|
+
},
|
|
61729
|
+
{
|
|
61730
|
+
path: "remaining.value",
|
|
61731
|
+
sources: [{
|
|
61732
|
+
kind: "numeric",
|
|
61733
|
+
transforms: [{ kind: "identity" }]
|
|
61734
|
+
}],
|
|
61735
|
+
literals: [{
|
|
61736
|
+
path: "remaining.unit",
|
|
61737
|
+
values: [...ConsumableRemainingUnitSchema.options]
|
|
61738
|
+
}]
|
|
61739
|
+
},
|
|
61740
|
+
{
|
|
61741
|
+
path: "status",
|
|
61742
|
+
sources: [{
|
|
61743
|
+
kind: "enum",
|
|
61744
|
+
transforms: [{
|
|
61745
|
+
kind: "enum-map",
|
|
61746
|
+
outputValues: [...ConsumableStatusSchema.options],
|
|
61747
|
+
unmapped: null
|
|
61748
|
+
}]
|
|
61749
|
+
}]
|
|
61750
|
+
}
|
|
61751
|
+
],
|
|
61752
|
+
traits: [{
|
|
61753
|
+
path: "kind",
|
|
61754
|
+
values: [...ConsumableKindSchema.options],
|
|
61755
|
+
defaultValue: "wear"
|
|
61756
|
+
}, {
|
|
61757
|
+
path: "form",
|
|
61758
|
+
values: [...ConsumableFormSchema.options],
|
|
61759
|
+
defaultValue: "part"
|
|
61760
|
+
}],
|
|
61761
|
+
companions: [{
|
|
61762
|
+
kind: "clock",
|
|
61763
|
+
path: "lastChangedAt",
|
|
61764
|
+
when: "add"
|
|
61765
|
+
}, {
|
|
61766
|
+
kind: "clock",
|
|
61767
|
+
path: "lastFetchedAt",
|
|
61768
|
+
when: "add"
|
|
61769
|
+
}],
|
|
61770
|
+
advancedExpression: true
|
|
61771
|
+
}]
|
|
61772
|
+
};
|
|
61624
61773
|
var consumablesCapability = {
|
|
61625
61774
|
name: "consumables",
|
|
61626
61775
|
scope: "device",
|
|
@@ -61658,10 +61807,7 @@ reset: require_sleep.method(zod.z.object({
|
|
|
61658
61807
|
status: {
|
|
61659
61808
|
schema: ConsumablesStatusSchema,
|
|
61660
61809
|
kind: "push",
|
|
61661
|
-
empty:
|
|
61662
|
-
items: [],
|
|
61663
|
-
lastChangedAt: 0
|
|
61664
|
-
},
|
|
61810
|
+
empty: EMPTY_STATUS,
|
|
61665
61811
|
itemArray: {
|
|
61666
61812
|
path: "items",
|
|
61667
61813
|
keyField: "key",
|
|
@@ -61697,6 +61843,7 @@ reset: require_sleep.method(zod.z.object({
|
|
|
61697
61843
|
* brush's remaining life and a dishwasher's salt are each recorded the moment
|
|
61698
61844
|
* their provider reports them; an item that appears later gets its series.
|
|
61699
61845
|
*/
|
|
61846
|
+
customize: consumablesCustomize,
|
|
61700
61847
|
history: {
|
|
61701
61848
|
fields: {},
|
|
61702
61849
|
items: {
|
|
@@ -62499,6 +62646,38 @@ var dishwasherCapability = {
|
|
|
62499
62646
|
};
|
|
62500
62647
|
//#endregion
|
|
62501
62648
|
//#region src/capabilities/doorbell.cap.ts
|
|
62649
|
+
/** A rise closer than this to the previous one is the same press (D671). */
|
|
62650
|
+
var DOORBELL_RISE_DEBOUNCE_MS = 2e3;
|
|
62651
|
+
/** Pulse override: a rising edge advances `lastPressedAt` and the press count. */
|
|
62652
|
+
var doorbellCustomize = {
|
|
62653
|
+
version: 1,
|
|
62654
|
+
targets: [{
|
|
62655
|
+
id: "pressed",
|
|
62656
|
+
cardinality: "event",
|
|
62657
|
+
shape: "pulse",
|
|
62658
|
+
vocabulary: {
|
|
62659
|
+
cap: "doorbell",
|
|
62660
|
+
eventName: "onPressed"
|
|
62661
|
+
},
|
|
62662
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
62663
|
+
apply: "add",
|
|
62664
|
+
applyAuthority: { kind: "composition-claim" },
|
|
62665
|
+
eventName: "onPressed",
|
|
62666
|
+
edges: ["rising"],
|
|
62667
|
+
timestampPath: "lastPressedAt",
|
|
62668
|
+
counterPath: "pressCountSinceStart",
|
|
62669
|
+
highWater: "composer-advance",
|
|
62670
|
+
combine: "any",
|
|
62671
|
+
debounce: {
|
|
62672
|
+
kind: "rising-edge",
|
|
62673
|
+
defaultDebounceMs: DOORBELL_RISE_DEBOUNCE_MS,
|
|
62674
|
+
changedAtRequired: true
|
|
62675
|
+
},
|
|
62676
|
+
sources: [{ kind: "binary" }, { kind: "switch" }],
|
|
62677
|
+
sourceReport: { status: "assignment-status" },
|
|
62678
|
+
advancedExpression: true
|
|
62679
|
+
}]
|
|
62680
|
+
};
|
|
62502
62681
|
var DoorbellStatusSchema = zod.z.object({
|
|
62503
62682
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
62504
62683
|
lastPressedAt: zod.z.number().nullable(),
|
|
@@ -62565,7 +62744,8 @@ onPressed: {
|
|
|
62565
62744
|
/**
|
|
62566
62745
|
* History (D850): none — `pressCountSinceStart` resets with the addon, so it is not a monotonic meter; presses live in the events ledger.
|
|
62567
62746
|
*/
|
|
62568
|
-
history: "none"
|
|
62747
|
+
history: "none",
|
|
62748
|
+
customize: doorbellCustomize
|
|
62569
62749
|
};
|
|
62570
62750
|
//#endregion
|
|
62571
62751
|
//#region src/capabilities/enum-sensor.cap.ts
|
|
@@ -65312,6 +65492,44 @@ authKey: zod.z.string().optional() }), zod.z.object({
|
|
|
65312
65492
|
//#endregion
|
|
65313
65493
|
//#region src/capabilities/motion.cap.ts
|
|
65314
65494
|
/**
|
|
65495
|
+
* Span timeout for a camera's attached sensors. This is the pipeline-runner
|
|
65496
|
+
* `motionCooldownMs` default: the window after which a heartbeat-only edge
|
|
65497
|
+
* no longer counts. The span does not declare a separate cooldown.
|
|
65498
|
+
*/
|
|
65499
|
+
var MOTION_SPAN_TIMEOUT_MS = 3e4;
|
|
65500
|
+
/** Span override: start on a rising edge, end on a fall or this timeout. */
|
|
65501
|
+
var motionCustomize = {
|
|
65502
|
+
version: 1,
|
|
65503
|
+
targets: [{
|
|
65504
|
+
id: "detected",
|
|
65505
|
+
cardinality: "event",
|
|
65506
|
+
shape: "span",
|
|
65507
|
+
vocabulary: {
|
|
65508
|
+
cap: "motion",
|
|
65509
|
+
eventName: "onMotionChanged"
|
|
65510
|
+
},
|
|
65511
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
65512
|
+
apply: "replace",
|
|
65513
|
+
applyAuthority: {
|
|
65514
|
+
kind: "camera-sensors",
|
|
65515
|
+
timeoutField: "motionCooldownMs"
|
|
65516
|
+
},
|
|
65517
|
+
eventName: "onMotionChanged",
|
|
65518
|
+
start: "rising-edge",
|
|
65519
|
+
end: "falling-edge-or-timeout",
|
|
65520
|
+
timeoutMs: MOTION_SPAN_TIMEOUT_MS,
|
|
65521
|
+
combine: "any",
|
|
65522
|
+
sourceModes: [
|
|
65523
|
+
"in-addition",
|
|
65524
|
+
"confirm",
|
|
65525
|
+
"replace"
|
|
65526
|
+
],
|
|
65527
|
+
sources: [{ kind: "binary" }, { kind: "switch" }],
|
|
65528
|
+
sourceReport: { status: "assignment-status" },
|
|
65529
|
+
advancedExpression: false
|
|
65530
|
+
}]
|
|
65531
|
+
};
|
|
65532
|
+
/**
|
|
65315
65533
|
* Hardware / firmware motion sensor cap — binary detected state plus
|
|
65316
65534
|
* a timestamp of the last observation. Distinct from
|
|
65317
65535
|
* `motion-detection.cap.ts` which owns the LOCAL ML motion pipeline;
|
|
@@ -65475,7 +65693,8 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
|
|
|
65475
65693
|
history: { fields: { detected: {
|
|
65476
65694
|
kind: "boolean",
|
|
65477
65695
|
excludeDeviceTypes: [require_err_msg.DeviceType.Camera]
|
|
65478
|
-
} } }
|
|
65696
|
+
} } },
|
|
65697
|
+
customize: motionCustomize
|
|
65479
65698
|
};
|
|
65480
65699
|
//#endregion
|
|
65481
65700
|
//#region src/capabilities/motion-trigger.cap.ts
|
|
@@ -69589,6 +69808,19 @@ var ptzAutotrackCapability = {
|
|
|
69589
69808
|
history: "none"
|
|
69590
69809
|
};
|
|
69591
69810
|
//#endregion
|
|
69811
|
+
//#region src/running-state/defaults.ts
|
|
69812
|
+
var RUNNING_POWER_THRESHOLD_WATTS = 5;
|
|
69813
|
+
var RUNNING_POWER_START_DELAY_MS = 3e4;
|
|
69814
|
+
var RUNNING_POWER_STOP_DELAY_MS = 18e4;
|
|
69815
|
+
/** Before any provider reading — all fields unknown (D933). */
|
|
69816
|
+
var RUNNING_STATE_COLD = {
|
|
69817
|
+
running: null,
|
|
69818
|
+
since: null,
|
|
69819
|
+
source: "native",
|
|
69820
|
+
phase: null,
|
|
69821
|
+
lastFetchedAt: null
|
|
69822
|
+
};
|
|
69823
|
+
//#endregion
|
|
69592
69824
|
//#region src/capabilities/running-state.cap.ts
|
|
69593
69825
|
var RunningStateSourceSchema = zod.z.enum(["native", "assigned"]);
|
|
69594
69826
|
var RunningStateStatusSchema = zod.z.object({
|
|
@@ -69598,19 +69830,100 @@ var RunningStateStatusSchema = zod.z.object({
|
|
|
69598
69830
|
since: zod.z.number().nullable(),
|
|
69599
69831
|
source: RunningStateSourceSchema,
|
|
69600
69832
|
phase: zod.z.string().nullable(),
|
|
69601
|
-
|
|
69833
|
+
/** null until a reading has been published (D393). */
|
|
69834
|
+
lastFetchedAt: zod.z.number().nullable()
|
|
69602
69835
|
});
|
|
69603
69836
|
var RunningFlipEventDataSchema = zod.z.object({
|
|
69604
69837
|
deviceId: zod.z.number(),
|
|
69605
69838
|
since: zod.z.number().nullable(),
|
|
69606
69839
|
phase: zod.z.string().nullable()
|
|
69607
69840
|
});
|
|
69841
|
+
var RUNNING_DEVICE_TYPES = Object.values(require_err_msg.DeviceType);
|
|
69842
|
+
/** Generic Customize target for the running boolean (D936). */
|
|
69843
|
+
var runningCustomize = {
|
|
69844
|
+
version: 1,
|
|
69845
|
+
targets: [{
|
|
69846
|
+
id: "running",
|
|
69847
|
+
cardinality: "scalar",
|
|
69848
|
+
vocabulary: {
|
|
69849
|
+
cap: "running-state",
|
|
69850
|
+
stateField: "running"
|
|
69851
|
+
},
|
|
69852
|
+
deviceTypes: [
|
|
69853
|
+
require_err_msg.DeviceType.Dishwasher,
|
|
69854
|
+
require_err_msg.DeviceType.Vacuum,
|
|
69855
|
+
require_err_msg.DeviceType.LawnMower,
|
|
69856
|
+
require_err_msg.DeviceType.MediaPlayer,
|
|
69857
|
+
require_err_msg.DeviceType.WaterHeater,
|
|
69858
|
+
require_err_msg.DeviceType.Humidifier,
|
|
69859
|
+
require_err_msg.DeviceType.Fan,
|
|
69860
|
+
require_err_msg.DeviceType.Climate,
|
|
69861
|
+
require_err_msg.DeviceType.Thermostat,
|
|
69862
|
+
require_err_msg.DeviceType.PetFeeder
|
|
69863
|
+
],
|
|
69864
|
+
apply: "add-or-replace",
|
|
69865
|
+
path: "running",
|
|
69866
|
+
sources: [
|
|
69867
|
+
{
|
|
69868
|
+
kind: "switch",
|
|
69869
|
+
transforms: [{ kind: "identity" }]
|
|
69870
|
+
},
|
|
69871
|
+
{
|
|
69872
|
+
kind: "binary",
|
|
69873
|
+
transforms: [{ kind: "identity" }, { kind: "invert" }]
|
|
69874
|
+
},
|
|
69875
|
+
{
|
|
69876
|
+
kind: "numeric",
|
|
69877
|
+
requiredUnit: "W",
|
|
69878
|
+
transforms: [{
|
|
69879
|
+
kind: "threshold",
|
|
69880
|
+
comparison: "gte",
|
|
69881
|
+
defaultThreshold: 5,
|
|
69882
|
+
defaultStartDwellMs: RUNNING_POWER_START_DELAY_MS,
|
|
69883
|
+
defaultStopDwellMs: RUNNING_POWER_STOP_DELAY_MS,
|
|
69884
|
+
thresholdUnit: "W"
|
|
69885
|
+
}]
|
|
69886
|
+
}
|
|
69887
|
+
],
|
|
69888
|
+
companions: [
|
|
69889
|
+
{
|
|
69890
|
+
kind: "constant",
|
|
69891
|
+
path: "source",
|
|
69892
|
+
value: "assigned",
|
|
69893
|
+
when: "always"
|
|
69894
|
+
},
|
|
69895
|
+
{
|
|
69896
|
+
kind: "constant",
|
|
69897
|
+
path: "phase",
|
|
69898
|
+
value: null,
|
|
69899
|
+
when: "always"
|
|
69900
|
+
},
|
|
69901
|
+
{
|
|
69902
|
+
kind: "clock",
|
|
69903
|
+
path: "lastFetchedAt",
|
|
69904
|
+
when: "always"
|
|
69905
|
+
},
|
|
69906
|
+
{
|
|
69907
|
+
kind: "transition-time",
|
|
69908
|
+
path: "since",
|
|
69909
|
+
sourceChangedAt: "prefer"
|
|
69910
|
+
}
|
|
69911
|
+
],
|
|
69912
|
+
sourceReport: {
|
|
69913
|
+
status: "assignment-status",
|
|
69914
|
+
runtimeField: "source",
|
|
69915
|
+
nativeValue: "native",
|
|
69916
|
+
assignedValue: "assigned"
|
|
69917
|
+
},
|
|
69918
|
+
advancedExpression: true
|
|
69919
|
+
}]
|
|
69920
|
+
};
|
|
69608
69921
|
var runningStateCapability = {
|
|
69609
69922
|
name: "running-state",
|
|
69610
69923
|
scope: "device",
|
|
69611
69924
|
deviceNative: true,
|
|
69612
69925
|
mode: "singleton",
|
|
69613
|
-
deviceTypes:
|
|
69926
|
+
deviceTypes: RUNNING_DEVICE_TYPES,
|
|
69614
69927
|
methods: {},
|
|
69615
69928
|
events: {
|
|
69616
69929
|
onStarted: { data: RunningFlipEventDataSchema },
|
|
@@ -69623,7 +69936,8 @@ var runningStateCapability = {
|
|
|
69623
69936
|
runtimeState: RunningStateStatusSchema,
|
|
69624
69937
|
durability: "restored",
|
|
69625
69938
|
history: { fields: { running: { kind: "boolean" } } },
|
|
69626
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
69939
|
+
volatileStateFields: ["lastFetchedAt"],
|
|
69940
|
+
customize: runningCustomize
|
|
69627
69941
|
};
|
|
69628
69942
|
//#endregion
|
|
69629
69943
|
//#region src/capabilities/reboot.cap.ts
|
|
@@ -75852,213 +76166,58 @@ var PIPELINE_OWNER_CAPABILITY_NAMES = [
|
|
|
75852
76166
|
"pipeline-runner"
|
|
75853
76167
|
];
|
|
75854
76168
|
//#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
76169
|
//#region src/running-state/from-operation.ts
|
|
76025
|
-
function
|
|
76170
|
+
function programStartFromRemaining(running, remainingSeconds, fetchedAt) {
|
|
76171
|
+
if (!running || remainingSeconds === null || remainingSeconds === void 0) return null;
|
|
76172
|
+
if (remainingSeconds <= 0) return null;
|
|
76173
|
+
return fetchedAt - remainingSeconds * 1e3;
|
|
76174
|
+
}
|
|
76175
|
+
function resolveSince(running, previous, transitionAtMs, bootstrapSinceMs) {
|
|
76026
76176
|
if (running === null) return null;
|
|
76027
|
-
|
|
76028
|
-
|
|
76177
|
+
const prevRunning = previous?.running ?? null;
|
|
76178
|
+
if (prevRunning === null) return bootstrapSinceMs;
|
|
76179
|
+
if (prevRunning !== running) return transitionAtMs;
|
|
76180
|
+
return previous?.since ?? null;
|
|
76029
76181
|
}
|
|
76030
|
-
function nativeSlice(running, phase, previous,
|
|
76182
|
+
function nativeSlice(running, phase, previous, transitionAtMs, fetchedAt, bootstrapSinceMs) {
|
|
76031
76183
|
return {
|
|
76032
76184
|
running,
|
|
76033
|
-
since: resolveSince(running, previous,
|
|
76185
|
+
since: resolveSince(running, previous, transitionAtMs, bootstrapSinceMs),
|
|
76034
76186
|
source: "native",
|
|
76035
76187
|
phase: running === null ? null : phase,
|
|
76036
|
-
lastFetchedAt:
|
|
76188
|
+
lastFetchedAt: fetchedAt
|
|
76037
76189
|
};
|
|
76038
76190
|
}
|
|
76039
|
-
function runningFromDishwasherOperation(operation, program, previous,
|
|
76040
|
-
|
|
76041
|
-
if (operation ===
|
|
76042
|
-
if (operation === "
|
|
76043
|
-
|
|
76044
|
-
|
|
76045
|
-
|
|
76046
|
-
if (
|
|
76047
|
-
|
|
76048
|
-
|
|
76049
|
-
|
|
76050
|
-
|
|
76051
|
-
|
|
76052
|
-
if (
|
|
76053
|
-
if (
|
|
76054
|
-
|
|
76055
|
-
|
|
76056
|
-
|
|
76057
|
-
|
|
76058
|
-
if (
|
|
76059
|
-
if (
|
|
76060
|
-
if (
|
|
76061
|
-
return nativeSlice(false,
|
|
76191
|
+
function runningFromDishwasherOperation(operation, program, previous, fetchedAt, remainingSeconds, transitionAt) {
|
|
76192
|
+
const transitionAtMs = transitionAt ?? fetchedAt;
|
|
76193
|
+
if (operation === null) return nativeSlice(null, null, previous, transitionAtMs, fetchedAt, null);
|
|
76194
|
+
if (operation === "Run" || operation === "Aborting") {
|
|
76195
|
+
const bootstrap = programStartFromRemaining(true, remainingSeconds, fetchedAt);
|
|
76196
|
+
return nativeSlice(true, program ?? operation, previous, transitionAtMs, fetchedAt, bootstrap);
|
|
76197
|
+
}
|
|
76198
|
+
if (operation === "Pause") return nativeSlice(false, "Pause", previous, transitionAtMs, fetchedAt, null);
|
|
76199
|
+
return nativeSlice(false, operation, previous, transitionAtMs, fetchedAt, null);
|
|
76200
|
+
}
|
|
76201
|
+
function runningFromVacuumState(state, previous, fetchedAt, transitionAt) {
|
|
76202
|
+
const transitionAtMs = transitionAt ?? fetchedAt;
|
|
76203
|
+
if (state === null) return nativeSlice(null, null, previous, transitionAtMs, fetchedAt, null);
|
|
76204
|
+
if (state === "cleaning" || state === "returning" || state === "drying") return nativeSlice(true, state, previous, transitionAtMs, fetchedAt, null);
|
|
76205
|
+
if (state === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
|
|
76206
|
+
return nativeSlice(false, state, previous, transitionAtMs, fetchedAt, null);
|
|
76207
|
+
}
|
|
76208
|
+
function runningFromLawnMower(activity, previous, fetchedAt, transitionAt) {
|
|
76209
|
+
const transitionAtMs = transitionAt ?? fetchedAt;
|
|
76210
|
+
if (activity === null) return nativeSlice(null, null, previous, transitionAtMs, fetchedAt, null);
|
|
76211
|
+
if (activity === "mowing") return nativeSlice(true, activity, previous, transitionAtMs, fetchedAt, null);
|
|
76212
|
+
if (activity === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
|
|
76213
|
+
return nativeSlice(false, activity, previous, transitionAtMs, fetchedAt, null);
|
|
76214
|
+
}
|
|
76215
|
+
function runningFromMediaPlayer(state, previous, fetchedAt, transitionAt) {
|
|
76216
|
+
const transitionAtMs = transitionAt ?? fetchedAt;
|
|
76217
|
+
if (state === null) return nativeSlice(null, null, previous, transitionAtMs, fetchedAt, null);
|
|
76218
|
+
if (state === "playing" || state === "buffering") return nativeSlice(true, state, previous, transitionAtMs, fetchedAt, null);
|
|
76219
|
+
if (state === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
|
|
76220
|
+
return nativeSlice(false, state, previous, transitionAtMs, fetchedAt, null);
|
|
76062
76221
|
}
|
|
76063
76222
|
//#endregion
|
|
76064
76223
|
//#region src/clips/clip-event-labels.ts
|
|
@@ -76950,74 +77109,6 @@ function feederCustomizationExample(sources) {
|
|
|
76950
77109
|
});
|
|
76951
77110
|
}
|
|
76952
77111
|
//#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
77112
|
//#region src/composition/presets/numeric-transforms.ts
|
|
77022
77113
|
/**
|
|
77023
77114
|
* Self-only invert / unit-convert composition features (D663). The Numeric
|
|
@@ -100291,6 +100382,1852 @@ function historyFieldsFor(capName) {
|
|
|
100291
100382
|
return HISTORY_CATALOG[capName] ?? {};
|
|
100292
100383
|
}
|
|
100293
100384
|
//#endregion
|
|
100385
|
+
//#region src/generated/customize-catalog.ts
|
|
100386
|
+
/**
|
|
100387
|
+
* Customize catalog, projected from every `*.cap.ts` `customize` block.
|
|
100388
|
+
* 5 caps. Field keys are `runtimeState` paths. No Zod.
|
|
100389
|
+
*/
|
|
100390
|
+
var CAP_CUSTOMIZE_CATALOG = {
|
|
100391
|
+
"battery": {
|
|
100392
|
+
version: 1,
|
|
100393
|
+
targets: [{
|
|
100394
|
+
id: "percentage",
|
|
100395
|
+
cardinality: "scalar",
|
|
100396
|
+
deviceTypes: [
|
|
100397
|
+
require_err_msg.DeviceType.Camera,
|
|
100398
|
+
require_err_msg.DeviceType.Sensor,
|
|
100399
|
+
require_err_msg.DeviceType.Button,
|
|
100400
|
+
require_err_msg.DeviceType.Switch,
|
|
100401
|
+
require_err_msg.DeviceType.PetFeeder,
|
|
100402
|
+
require_err_msg.DeviceType.Container,
|
|
100403
|
+
require_err_msg.DeviceType.Thermostat
|
|
100404
|
+
],
|
|
100405
|
+
apply: "add-or-replace",
|
|
100406
|
+
vocabularyCap: "battery",
|
|
100407
|
+
vocabularyStateField: "percentage",
|
|
100408
|
+
sources: [{
|
|
100409
|
+
kind: "field",
|
|
100410
|
+
valueKinds: ["number", "string"],
|
|
100411
|
+
transformKinds: ["identity", "linear"]
|
|
100412
|
+
}],
|
|
100413
|
+
sourceReport: { status: "assignment-status" },
|
|
100414
|
+
advancedExpression: true,
|
|
100415
|
+
path: "percentage",
|
|
100416
|
+
valueKind: "number",
|
|
100417
|
+
nullable: true,
|
|
100418
|
+
companions: [
|
|
100419
|
+
{
|
|
100420
|
+
kind: "constant",
|
|
100421
|
+
path: "charging",
|
|
100422
|
+
value: "unknown",
|
|
100423
|
+
when: "add"
|
|
100424
|
+
},
|
|
100425
|
+
{
|
|
100426
|
+
kind: "constant",
|
|
100427
|
+
path: "sleeping",
|
|
100428
|
+
value: false,
|
|
100429
|
+
when: "add"
|
|
100430
|
+
},
|
|
100431
|
+
{
|
|
100432
|
+
kind: "clock",
|
|
100433
|
+
path: "lastUpdated",
|
|
100434
|
+
when: "add"
|
|
100435
|
+
}
|
|
100436
|
+
]
|
|
100437
|
+
}]
|
|
100438
|
+
},
|
|
100439
|
+
"consumables": {
|
|
100440
|
+
version: 1,
|
|
100441
|
+
targets: [{
|
|
100442
|
+
id: "items",
|
|
100443
|
+
cardinality: "keyedArray",
|
|
100444
|
+
deviceTypes: [
|
|
100445
|
+
require_err_msg.DeviceType.Camera,
|
|
100446
|
+
require_err_msg.DeviceType.Hub,
|
|
100447
|
+
require_err_msg.DeviceType.Light,
|
|
100448
|
+
require_err_msg.DeviceType.Siren,
|
|
100449
|
+
require_err_msg.DeviceType.Switch,
|
|
100450
|
+
require_err_msg.DeviceType.Sensor,
|
|
100451
|
+
require_err_msg.DeviceType.Thermostat,
|
|
100452
|
+
require_err_msg.DeviceType.Climate,
|
|
100453
|
+
require_err_msg.DeviceType.Button,
|
|
100454
|
+
require_err_msg.DeviceType.EventEmitter,
|
|
100455
|
+
require_err_msg.DeviceType.Update,
|
|
100456
|
+
require_err_msg.DeviceType.Generic,
|
|
100457
|
+
require_err_msg.DeviceType.Notifier,
|
|
100458
|
+
require_err_msg.DeviceType.Script,
|
|
100459
|
+
require_err_msg.DeviceType.Automation,
|
|
100460
|
+
require_err_msg.DeviceType.Lock,
|
|
100461
|
+
require_err_msg.DeviceType.Cover,
|
|
100462
|
+
require_err_msg.DeviceType.Valve,
|
|
100463
|
+
require_err_msg.DeviceType.Humidifier,
|
|
100464
|
+
require_err_msg.DeviceType.WaterHeater,
|
|
100465
|
+
require_err_msg.DeviceType.Fan,
|
|
100466
|
+
require_err_msg.DeviceType.MediaPlayer,
|
|
100467
|
+
require_err_msg.DeviceType.AlarmPanel,
|
|
100468
|
+
require_err_msg.DeviceType.Control,
|
|
100469
|
+
require_err_msg.DeviceType.Presence,
|
|
100470
|
+
require_err_msg.DeviceType.Weather,
|
|
100471
|
+
require_err_msg.DeviceType.Vacuum,
|
|
100472
|
+
require_err_msg.DeviceType.LawnMower,
|
|
100473
|
+
require_err_msg.DeviceType.Container,
|
|
100474
|
+
require_err_msg.DeviceType.Image,
|
|
100475
|
+
require_err_msg.DeviceType.PetFeeder,
|
|
100476
|
+
require_err_msg.DeviceType.Dishwasher
|
|
100477
|
+
],
|
|
100478
|
+
apply: "add",
|
|
100479
|
+
vocabularyCap: "consumables",
|
|
100480
|
+
sources: [],
|
|
100481
|
+
sourceReport: { status: "assignment-status" },
|
|
100482
|
+
advancedExpression: true,
|
|
100483
|
+
path: "items",
|
|
100484
|
+
keyField: "key",
|
|
100485
|
+
labelField: "label",
|
|
100486
|
+
nativeItems: "read-only",
|
|
100487
|
+
fields: [
|
|
100488
|
+
{
|
|
100489
|
+
path: "level",
|
|
100490
|
+
valueKind: "number",
|
|
100491
|
+
nullable: true,
|
|
100492
|
+
sources: [{
|
|
100493
|
+
kind: "numeric",
|
|
100494
|
+
transformKinds: ["identity", "linear"]
|
|
100495
|
+
}]
|
|
100496
|
+
},
|
|
100497
|
+
{
|
|
100498
|
+
path: "remaining.value",
|
|
100499
|
+
valueKind: "number",
|
|
100500
|
+
nullable: true,
|
|
100501
|
+
sources: [{
|
|
100502
|
+
kind: "numeric",
|
|
100503
|
+
transformKinds: ["identity"]
|
|
100504
|
+
}],
|
|
100505
|
+
literals: [{
|
|
100506
|
+
path: "remaining.unit",
|
|
100507
|
+
values: [
|
|
100508
|
+
"days",
|
|
100509
|
+
"hours",
|
|
100510
|
+
"cycles"
|
|
100511
|
+
]
|
|
100512
|
+
}]
|
|
100513
|
+
},
|
|
100514
|
+
{
|
|
100515
|
+
path: "status",
|
|
100516
|
+
valueKind: "enum",
|
|
100517
|
+
nullable: true,
|
|
100518
|
+
enumValues: [
|
|
100519
|
+
"ok",
|
|
100520
|
+
"low",
|
|
100521
|
+
"empty",
|
|
100522
|
+
"full",
|
|
100523
|
+
"replace"
|
|
100524
|
+
],
|
|
100525
|
+
sources: [{
|
|
100526
|
+
kind: "enum",
|
|
100527
|
+
transformKinds: ["enum-map"]
|
|
100528
|
+
}]
|
|
100529
|
+
}
|
|
100530
|
+
],
|
|
100531
|
+
traits: [{
|
|
100532
|
+
path: "kind",
|
|
100533
|
+
values: [
|
|
100534
|
+
"wear",
|
|
100535
|
+
"supply",
|
|
100536
|
+
"waste"
|
|
100537
|
+
],
|
|
100538
|
+
defaultValue: "wear"
|
|
100539
|
+
}, {
|
|
100540
|
+
path: "form",
|
|
100541
|
+
values: [
|
|
100542
|
+
"part",
|
|
100543
|
+
"tank",
|
|
100544
|
+
"product",
|
|
100545
|
+
"bin"
|
|
100546
|
+
],
|
|
100547
|
+
defaultValue: "part"
|
|
100548
|
+
}],
|
|
100549
|
+
companions: [{
|
|
100550
|
+
kind: "clock",
|
|
100551
|
+
path: "lastChangedAt",
|
|
100552
|
+
when: "add"
|
|
100553
|
+
}, {
|
|
100554
|
+
kind: "clock",
|
|
100555
|
+
path: "lastFetchedAt",
|
|
100556
|
+
when: "add"
|
|
100557
|
+
}]
|
|
100558
|
+
}]
|
|
100559
|
+
},
|
|
100560
|
+
"doorbell": {
|
|
100561
|
+
version: 1,
|
|
100562
|
+
targets: [{
|
|
100563
|
+
id: "pressed",
|
|
100564
|
+
cardinality: "event",
|
|
100565
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
100566
|
+
apply: "add",
|
|
100567
|
+
vocabularyCap: "doorbell",
|
|
100568
|
+
vocabularyEvent: "onPressed",
|
|
100569
|
+
sources: [{
|
|
100570
|
+
kind: "binary",
|
|
100571
|
+
transformKinds: []
|
|
100572
|
+
}, {
|
|
100573
|
+
kind: "switch",
|
|
100574
|
+
transformKinds: []
|
|
100575
|
+
}],
|
|
100576
|
+
sourceReport: { status: "assignment-status" },
|
|
100577
|
+
advancedExpression: true,
|
|
100578
|
+
shape: "pulse",
|
|
100579
|
+
applyAuthority: { kind: "composition-claim" },
|
|
100580
|
+
eventName: "onPressed",
|
|
100581
|
+
combine: "any",
|
|
100582
|
+
edges: ["rising"],
|
|
100583
|
+
timestampPath: "lastPressedAt",
|
|
100584
|
+
counterPath: "pressCountSinceStart",
|
|
100585
|
+
highWater: "composer-advance",
|
|
100586
|
+
debounceMs: 2e3
|
|
100587
|
+
}]
|
|
100588
|
+
},
|
|
100589
|
+
"motion": {
|
|
100590
|
+
version: 1,
|
|
100591
|
+
targets: [{
|
|
100592
|
+
id: "detected",
|
|
100593
|
+
cardinality: "event",
|
|
100594
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
100595
|
+
apply: "replace",
|
|
100596
|
+
vocabularyCap: "motion",
|
|
100597
|
+
vocabularyEvent: "onMotionChanged",
|
|
100598
|
+
sources: [{
|
|
100599
|
+
kind: "binary",
|
|
100600
|
+
transformKinds: []
|
|
100601
|
+
}, {
|
|
100602
|
+
kind: "switch",
|
|
100603
|
+
transformKinds: []
|
|
100604
|
+
}],
|
|
100605
|
+
sourceReport: { status: "assignment-status" },
|
|
100606
|
+
advancedExpression: false,
|
|
100607
|
+
shape: "span",
|
|
100608
|
+
applyAuthority: {
|
|
100609
|
+
kind: "camera-sensors",
|
|
100610
|
+
timeoutField: "motionCooldownMs"
|
|
100611
|
+
},
|
|
100612
|
+
eventName: "onMotionChanged",
|
|
100613
|
+
combine: "any",
|
|
100614
|
+
start: "rising-edge",
|
|
100615
|
+
end: "falling-edge-or-timeout",
|
|
100616
|
+
timeoutMs: 3e4,
|
|
100617
|
+
sourceModes: [
|
|
100618
|
+
"in-addition",
|
|
100619
|
+
"confirm",
|
|
100620
|
+
"replace"
|
|
100621
|
+
]
|
|
100622
|
+
}]
|
|
100623
|
+
},
|
|
100624
|
+
"running-state": {
|
|
100625
|
+
version: 1,
|
|
100626
|
+
targets: [{
|
|
100627
|
+
id: "running",
|
|
100628
|
+
cardinality: "scalar",
|
|
100629
|
+
deviceTypes: [
|
|
100630
|
+
require_err_msg.DeviceType.Dishwasher,
|
|
100631
|
+
require_err_msg.DeviceType.Vacuum,
|
|
100632
|
+
require_err_msg.DeviceType.LawnMower,
|
|
100633
|
+
require_err_msg.DeviceType.MediaPlayer,
|
|
100634
|
+
require_err_msg.DeviceType.WaterHeater,
|
|
100635
|
+
require_err_msg.DeviceType.Humidifier,
|
|
100636
|
+
require_err_msg.DeviceType.Fan,
|
|
100637
|
+
require_err_msg.DeviceType.Climate,
|
|
100638
|
+
require_err_msg.DeviceType.Thermostat,
|
|
100639
|
+
require_err_msg.DeviceType.PetFeeder
|
|
100640
|
+
],
|
|
100641
|
+
apply: "add-or-replace",
|
|
100642
|
+
vocabularyCap: "running-state",
|
|
100643
|
+
vocabularyStateField: "running",
|
|
100644
|
+
sources: [
|
|
100645
|
+
{
|
|
100646
|
+
kind: "switch",
|
|
100647
|
+
transformKinds: ["identity"]
|
|
100648
|
+
},
|
|
100649
|
+
{
|
|
100650
|
+
kind: "binary",
|
|
100651
|
+
transformKinds: ["identity", "invert"]
|
|
100652
|
+
},
|
|
100653
|
+
{
|
|
100654
|
+
kind: "numeric",
|
|
100655
|
+
requiredUnit: "W",
|
|
100656
|
+
transformKinds: ["threshold"]
|
|
100657
|
+
}
|
|
100658
|
+
],
|
|
100659
|
+
sourceReport: {
|
|
100660
|
+
status: "assignment-status",
|
|
100661
|
+
runtimeField: "source",
|
|
100662
|
+
nativeValue: "native",
|
|
100663
|
+
assignedValue: "assigned"
|
|
100664
|
+
},
|
|
100665
|
+
advancedExpression: true,
|
|
100666
|
+
path: "running",
|
|
100667
|
+
valueKind: "boolean",
|
|
100668
|
+
nullable: true,
|
|
100669
|
+
companions: [
|
|
100670
|
+
{
|
|
100671
|
+
kind: "constant",
|
|
100672
|
+
path: "source",
|
|
100673
|
+
value: "assigned",
|
|
100674
|
+
when: "always"
|
|
100675
|
+
},
|
|
100676
|
+
{
|
|
100677
|
+
kind: "constant",
|
|
100678
|
+
path: "phase",
|
|
100679
|
+
value: null,
|
|
100680
|
+
when: "always"
|
|
100681
|
+
},
|
|
100682
|
+
{
|
|
100683
|
+
kind: "clock",
|
|
100684
|
+
path: "lastFetchedAt",
|
|
100685
|
+
when: "always"
|
|
100686
|
+
},
|
|
100687
|
+
{
|
|
100688
|
+
kind: "transition-time",
|
|
100689
|
+
path: "since",
|
|
100690
|
+
sourceChangedAt: "prefer"
|
|
100691
|
+
}
|
|
100692
|
+
]
|
|
100693
|
+
}]
|
|
100694
|
+
}
|
|
100695
|
+
};
|
|
100696
|
+
//#endregion
|
|
100697
|
+
//#region src/composition/customize/override-draft.ts
|
|
100698
|
+
/**
|
|
100699
|
+
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
100700
|
+
* `z.infer`, they do not restate the shape.
|
|
100701
|
+
*/
|
|
100702
|
+
var OverrideSourceSchema = zod.z.object({
|
|
100703
|
+
addonId: zod.z.string().min(1),
|
|
100704
|
+
stableId: zod.z.string().min(1),
|
|
100705
|
+
cap: zod.z.string().min(1),
|
|
100706
|
+
fieldPath: zod.z.string().min(1)
|
|
100707
|
+
});
|
|
100708
|
+
var IdentityTransformDraftSchema = zod.z.object({ kind: zod.z.literal("identity") });
|
|
100709
|
+
var InvertTransformDraftSchema = zod.z.object({ kind: zod.z.literal("invert") });
|
|
100710
|
+
var ThresholdTransformDraftSchema = zod.z.object({
|
|
100711
|
+
kind: zod.z.literal("threshold"),
|
|
100712
|
+
comparison: zod.z.enum(["gte", "lte"]),
|
|
100713
|
+
threshold: zod.z.number(),
|
|
100714
|
+
startDwellMs: zod.z.number().nonnegative(),
|
|
100715
|
+
stopDwellMs: zod.z.number().nonnegative()
|
|
100716
|
+
});
|
|
100717
|
+
var LinearTransformDraftSchema = zod.z.object({
|
|
100718
|
+
kind: zod.z.literal("linear"),
|
|
100719
|
+
scale: zod.z.number(),
|
|
100720
|
+
offset: zod.z.number(),
|
|
100721
|
+
clampMin: zod.z.number().optional(),
|
|
100722
|
+
clampMax: zod.z.number().optional()
|
|
100723
|
+
});
|
|
100724
|
+
var EnumMapTransformDraftSchema = zod.z.object({
|
|
100725
|
+
kind: zod.z.literal("enum-map"),
|
|
100726
|
+
mapping: zod.z.record(zod.z.string(), zod.z.string().nullable())
|
|
100727
|
+
});
|
|
100728
|
+
var NumberBridgeTransformDraftSchema = zod.z.object({ kind: zod.z.literal("number") });
|
|
100729
|
+
var CustomizeTransformDraftSchema = zod.z.discriminatedUnion("kind", [
|
|
100730
|
+
IdentityTransformDraftSchema,
|
|
100731
|
+
InvertTransformDraftSchema,
|
|
100732
|
+
ThresholdTransformDraftSchema,
|
|
100733
|
+
LinearTransformDraftSchema,
|
|
100734
|
+
EnumMapTransformDraftSchema,
|
|
100735
|
+
NumberBridgeTransformDraftSchema
|
|
100736
|
+
]);
|
|
100737
|
+
var ScalarOverrideDraftSchema = zod.z.object({
|
|
100738
|
+
kind: zod.z.literal("scalar"),
|
|
100739
|
+
cap: zod.z.string().min(1),
|
|
100740
|
+
targetId: zod.z.string().min(1),
|
|
100741
|
+
source: OverrideSourceSchema,
|
|
100742
|
+
transform: CustomizeTransformDraftSchema
|
|
100743
|
+
});
|
|
100744
|
+
var KeyedArrayOverrideDraftSchema = zod.z.object({
|
|
100745
|
+
kind: zod.z.literal("keyedArray"),
|
|
100746
|
+
cap: zod.z.string().min(1),
|
|
100747
|
+
targetId: zod.z.string().min(1),
|
|
100748
|
+
key: zod.z.string().min(1),
|
|
100749
|
+
label: zod.z.string().min(1),
|
|
100750
|
+
fieldPath: zod.z.string().min(1),
|
|
100751
|
+
source: OverrideSourceSchema,
|
|
100752
|
+
transform: CustomizeTransformDraftSchema
|
|
100753
|
+
});
|
|
100754
|
+
var PulseOverrideDraftSchema = zod.z.object({
|
|
100755
|
+
kind: zod.z.literal("pulse"),
|
|
100756
|
+
cap: zod.z.string().min(1),
|
|
100757
|
+
targetId: zod.z.string().min(1),
|
|
100758
|
+
enabled: zod.z.boolean(),
|
|
100759
|
+
debounceMs: zod.z.number().nonnegative(),
|
|
100760
|
+
sources: zod.z.array(OverrideSourceSchema).min(1)
|
|
100761
|
+
});
|
|
100762
|
+
var SpanSourceDraftSchema = OverrideSourceSchema.extend({ mode: zod.z.enum([
|
|
100763
|
+
"in-addition",
|
|
100764
|
+
"confirm",
|
|
100765
|
+
"replace"
|
|
100766
|
+
]).optional() });
|
|
100767
|
+
var SpanOverrideDraftSchema = zod.z.object({
|
|
100768
|
+
kind: zod.z.literal("span"),
|
|
100769
|
+
cap: zod.z.string().min(1),
|
|
100770
|
+
targetId: zod.z.string().min(1),
|
|
100771
|
+
timeoutMs: zod.z.number().nonnegative(),
|
|
100772
|
+
cooldownMs: zod.z.number().nonnegative().optional(),
|
|
100773
|
+
sources: zod.z.array(SpanSourceDraftSchema)
|
|
100774
|
+
});
|
|
100775
|
+
var OverrideDraftSchema = zod.z.discriminatedUnion("kind", [
|
|
100776
|
+
ScalarOverrideDraftSchema,
|
|
100777
|
+
KeyedArrayOverrideDraftSchema,
|
|
100778
|
+
PulseOverrideDraftSchema,
|
|
100779
|
+
SpanOverrideDraftSchema
|
|
100780
|
+
]);
|
|
100781
|
+
/** Effective authority for one declared target. Not a second stored switch. */
|
|
100782
|
+
var CustomizeAssignmentStatusSchema = zod.z.object({
|
|
100783
|
+
targetId: zod.z.string().min(1),
|
|
100784
|
+
configured: zod.z.boolean(),
|
|
100785
|
+
source: zod.z.enum(["native", "assigned"]),
|
|
100786
|
+
state: zod.z.enum([
|
|
100787
|
+
"active",
|
|
100788
|
+
"stale",
|
|
100789
|
+
"released",
|
|
100790
|
+
"unavailable"
|
|
100791
|
+
]),
|
|
100792
|
+
reason: zod.z.string().nullable()
|
|
100793
|
+
});
|
|
100794
|
+
//#endregion
|
|
100795
|
+
//#region src/composition/customize/field-source.ts
|
|
100796
|
+
function fromRead(source, cap, fieldPath) {
|
|
100797
|
+
return {
|
|
100798
|
+
kind: "from",
|
|
100799
|
+
source,
|
|
100800
|
+
cap,
|
|
100801
|
+
fieldPath
|
|
100802
|
+
};
|
|
100803
|
+
}
|
|
100804
|
+
function expression(expr, bindings) {
|
|
100805
|
+
return {
|
|
100806
|
+
kind: "expression",
|
|
100807
|
+
expr,
|
|
100808
|
+
bindings
|
|
100809
|
+
};
|
|
100810
|
+
}
|
|
100811
|
+
function literal(expr) {
|
|
100812
|
+
return expression(expr, {});
|
|
100813
|
+
}
|
|
100814
|
+
function isLiteral(source, expr) {
|
|
100815
|
+
return source?.kind === "expression" && source.expr === expr && Object.keys(source.bindings).length === 0;
|
|
100816
|
+
}
|
|
100817
|
+
//#endregion
|
|
100818
|
+
//#region src/composition/customize/scalar-expr.ts
|
|
100819
|
+
var UNSIGNED = /^\d+(?:\.\d+)?$/;
|
|
100820
|
+
var SIGNED = /^-?\d+(?:\.\d+)?$/;
|
|
100821
|
+
var DWELL = /^dwell\(x (>=|<=) (\d+(?:\.\d+)?), (\d+(?:\.\d+)?), (\d+(?:\.\d+)?)\)$/;
|
|
100822
|
+
var LINEAR_CLAMP = /^clamp\((x|number\(x\)) \* (-?\d+(?:\.\d+)?) \+ (-?\d+(?:\.\d+)?), (-?\d+(?:\.\d+)?), (-?\d+(?:\.\d+)?)\)$/;
|
|
100823
|
+
var LINEAR_BARE = /^(x|number\(x\)) \* (-?\d+(?:\.\d+)?) \+ (-?\d+(?:\.\d+)?)$/;
|
|
100824
|
+
var IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
100825
|
+
function unsignedToken(value) {
|
|
100826
|
+
return token(value, UNSIGNED);
|
|
100827
|
+
}
|
|
100828
|
+
function signedToken(value) {
|
|
100829
|
+
return token(value, SIGNED);
|
|
100830
|
+
}
|
|
100831
|
+
function constantExpr(value) {
|
|
100832
|
+
if (typeof value === "string") return JSON.stringify(value);
|
|
100833
|
+
if (typeof value === "number") return signedToken(value);
|
|
100834
|
+
if (typeof value === "boolean") return value ? "true" : "false";
|
|
100835
|
+
return "null";
|
|
100836
|
+
}
|
|
100837
|
+
function isIdentifier(path) {
|
|
100838
|
+
return IDENT.test(path);
|
|
100839
|
+
}
|
|
100840
|
+
function dwellExpr(comparison, threshold, start, stop) {
|
|
100841
|
+
return `dwell(x ${comparison === "gte" ? ">=" : "<="} ${threshold}, ${start}, ${stop})`;
|
|
100842
|
+
}
|
|
100843
|
+
function linearExpr(inner, scale, offset, clampMin, clampMax) {
|
|
100844
|
+
const arithmetic = `${inner} * ${scale} + ${offset}`;
|
|
100845
|
+
if (clampMin === null || clampMax === null) return arithmetic;
|
|
100846
|
+
return `clamp(${arithmetic}, ${clampMin}, ${clampMax})`;
|
|
100847
|
+
}
|
|
100848
|
+
function parseDwell(expr) {
|
|
100849
|
+
const match = DWELL.exec(expr);
|
|
100850
|
+
if (match === null) return null;
|
|
100851
|
+
const threshold = Number(match[2]);
|
|
100852
|
+
const startDwellMs = Number(match[3]);
|
|
100853
|
+
const stopDwellMs = Number(match[4]);
|
|
100854
|
+
if (!Number.isFinite(threshold) || !Number.isFinite(startDwellMs) || !Number.isFinite(stopDwellMs)) return null;
|
|
100855
|
+
return {
|
|
100856
|
+
comparison: match[1] === "<=" ? "lte" : "gte",
|
|
100857
|
+
threshold,
|
|
100858
|
+
startDwellMs,
|
|
100859
|
+
stopDwellMs
|
|
100860
|
+
};
|
|
100861
|
+
}
|
|
100862
|
+
function parseLinear(expr) {
|
|
100863
|
+
const clamped = LINEAR_CLAMP.exec(expr);
|
|
100864
|
+
if (clamped !== null) return linearFrom(clamped[1], clamped[2], clamped[3], clamped[4], clamped[5]);
|
|
100865
|
+
const bare = LINEAR_BARE.exec(expr);
|
|
100866
|
+
if (bare === null) return null;
|
|
100867
|
+
return linearFrom(bare[1], bare[2], bare[3], void 0, void 0);
|
|
100868
|
+
}
|
|
100869
|
+
function singleFrom(source) {
|
|
100870
|
+
if (source.kind === "from") return {
|
|
100871
|
+
cap: source.cap,
|
|
100872
|
+
fieldPath: source.fieldPath,
|
|
100873
|
+
addonId: source.source.addonId,
|
|
100874
|
+
stableId: source.source.stableId
|
|
100875
|
+
};
|
|
100876
|
+
if (source.kind !== "expression" || Object.keys(source.bindings).length !== 1) return null;
|
|
100877
|
+
const bound = source.bindings["x"];
|
|
100878
|
+
if (bound === void 0 || bound.kind !== "from") return null;
|
|
100879
|
+
return {
|
|
100880
|
+
cap: bound.cap,
|
|
100881
|
+
fieldPath: bound.fieldPath,
|
|
100882
|
+
addonId: bound.source.addonId,
|
|
100883
|
+
stableId: bound.source.stableId
|
|
100884
|
+
};
|
|
100885
|
+
}
|
|
100886
|
+
function token(value, pattern) {
|
|
100887
|
+
if (!Number.isFinite(value)) return null;
|
|
100888
|
+
const text = Object.is(value, -0) ? "0" : String(value);
|
|
100889
|
+
return pattern.test(text) ? text : null;
|
|
100890
|
+
}
|
|
100891
|
+
function linearFrom(inner, scale, offset, clampMin, clampMax) {
|
|
100892
|
+
if (inner !== "x" && inner !== "number(x)") return null;
|
|
100893
|
+
if (scale === void 0 || offset === void 0) return null;
|
|
100894
|
+
const parsedScale = Number(scale);
|
|
100895
|
+
const parsedOffset = Number(offset);
|
|
100896
|
+
if (!Number.isFinite(parsedScale) || !Number.isFinite(parsedOffset)) return null;
|
|
100897
|
+
if (clampMin === void 0 || clampMax === void 0) return {
|
|
100898
|
+
inner,
|
|
100899
|
+
scale: parsedScale,
|
|
100900
|
+
offset: parsedOffset
|
|
100901
|
+
};
|
|
100902
|
+
const parsedMin = Number(clampMin);
|
|
100903
|
+
const parsedMax = Number(clampMax);
|
|
100904
|
+
if (!Number.isFinite(parsedMin) || !Number.isFinite(parsedMax)) return null;
|
|
100905
|
+
return {
|
|
100906
|
+
inner,
|
|
100907
|
+
scale: parsedScale,
|
|
100908
|
+
offset: parsedOffset,
|
|
100909
|
+
clampMin: parsedMin,
|
|
100910
|
+
clampMax: parsedMax
|
|
100911
|
+
};
|
|
100912
|
+
}
|
|
100913
|
+
//#endregion
|
|
100914
|
+
//#region src/composition/customize/scalar-compile.ts
|
|
100915
|
+
var catalog$4 = CAP_CUSTOMIZE_CATALOG;
|
|
100916
|
+
function compileScalarOverride(input) {
|
|
100917
|
+
const target = catalogTarget$4(input.draft.cap, input.draft.targetId);
|
|
100918
|
+
if (target === null || target.cardinality !== "scalar" || target.path === void 0) return fail$2("target");
|
|
100919
|
+
if (input.draft.transform.kind === "enum-map") return fail$2("enum");
|
|
100920
|
+
const source = sourceSpec$1(target, input.sourceValueKind, input.draft.source.cap);
|
|
100921
|
+
if (source === null) return fail$2("source-kind");
|
|
100922
|
+
if (source.requiredUnit !== void 0 && input.sourceUnit !== source.requiredUnit) return fail$2("unit");
|
|
100923
|
+
const allowed = input.draft.transform.kind === "number" ? "identity" : input.draft.transform.kind;
|
|
100924
|
+
if (!source.transformKinds.includes(allowed)) return fail$2("transform");
|
|
100925
|
+
const value = compileValue$1(input);
|
|
100926
|
+
if (!value.ok) return value;
|
|
100927
|
+
const fields = compileCompanions$1(input, target, value.value);
|
|
100928
|
+
if (!fields.ok) return fields;
|
|
100929
|
+
return {
|
|
100930
|
+
ok: true,
|
|
100931
|
+
value: {
|
|
100932
|
+
kind: "fields",
|
|
100933
|
+
cap: input.draft.cap,
|
|
100934
|
+
fields: fields.value
|
|
100935
|
+
}
|
|
100936
|
+
};
|
|
100937
|
+
}
|
|
100938
|
+
function fail$2(reason) {
|
|
100939
|
+
return {
|
|
100940
|
+
ok: false,
|
|
100941
|
+
reason
|
|
100942
|
+
};
|
|
100943
|
+
}
|
|
100944
|
+
function catalogTarget$4(cap, targetId) {
|
|
100945
|
+
const entry = catalog$4[cap];
|
|
100946
|
+
if (entry === void 0) return null;
|
|
100947
|
+
return entry.targets.find((target) => target.id === targetId) ?? null;
|
|
100948
|
+
}
|
|
100949
|
+
function sourceSpec$1(target, valueKind, sourceCap) {
|
|
100950
|
+
if (valueKind === "boolean" && sourceCap === "switch") return target.sources.find((source) => source.kind === "switch") ?? null;
|
|
100951
|
+
if (valueKind === "boolean") return target.sources.find((source) => source.kind === "binary") ?? fieldSource(target, "boolean");
|
|
100952
|
+
if (valueKind === "number") return target.sources.find((source) => source.kind === "numeric") ?? fieldSource(target, "number");
|
|
100953
|
+
return fieldSource(target, "string");
|
|
100954
|
+
}
|
|
100955
|
+
function fieldSource(target, valueKind) {
|
|
100956
|
+
return target.sources.find((source) => source.kind === "field" && (source.valueKinds ?? []).includes(valueKind)) ?? null;
|
|
100957
|
+
}
|
|
100958
|
+
function compileValue$1(input) {
|
|
100959
|
+
const read = fromRead(refOf$1(input.draft), input.draft.source.cap, input.draft.source.fieldPath);
|
|
100960
|
+
const transform = input.draft.transform;
|
|
100961
|
+
if (transform.kind === "identity" || transform.kind === "number") return {
|
|
100962
|
+
ok: true,
|
|
100963
|
+
value: identityValue(read, input.sourceValueKind)
|
|
100964
|
+
};
|
|
100965
|
+
if (transform.kind === "invert") {
|
|
100966
|
+
if (input.sourceValueKind !== "boolean") return fail$2("source-kind");
|
|
100967
|
+
return {
|
|
100968
|
+
ok: true,
|
|
100969
|
+
value: expression("!x", { x: read })
|
|
100970
|
+
};
|
|
100971
|
+
}
|
|
100972
|
+
if (transform.kind === "threshold") return thresholdValue(transform, read);
|
|
100973
|
+
if (transform.kind === "linear") return linearValue$1(transform, read, input.sourceValueKind);
|
|
100974
|
+
return fail$2("transform");
|
|
100975
|
+
}
|
|
100976
|
+
function identityValue(read, valueKind) {
|
|
100977
|
+
if (valueKind === "string") return expression("number(x)", { x: read });
|
|
100978
|
+
return read;
|
|
100979
|
+
}
|
|
100980
|
+
function thresholdValue(transform, read) {
|
|
100981
|
+
const threshold = unsignedToken(transform.threshold);
|
|
100982
|
+
if (threshold === null) return fail$2("threshold");
|
|
100983
|
+
const start = unsignedToken(transform.startDwellMs);
|
|
100984
|
+
const stop = unsignedToken(transform.stopDwellMs);
|
|
100985
|
+
if (start === null || stop === null) return fail$2("dwell");
|
|
100986
|
+
return {
|
|
100987
|
+
ok: true,
|
|
100988
|
+
value: expression(dwellExpr(transform.comparison, threshold, start, stop), { x: read })
|
|
100989
|
+
};
|
|
100990
|
+
}
|
|
100991
|
+
function linearValue$1(transform, read, valueKind) {
|
|
100992
|
+
const scale = signedToken(transform.scale);
|
|
100993
|
+
const offset = signedToken(transform.offset);
|
|
100994
|
+
if (scale === null || offset === null) return fail$2("scale");
|
|
100995
|
+
const clamps = clampTokens$1(transform.clampMin, transform.clampMax);
|
|
100996
|
+
if (!clamps.ok) return clamps;
|
|
100997
|
+
return {
|
|
100998
|
+
ok: true,
|
|
100999
|
+
value: expression(linearExpr(valueKind === "string" ? "number(x)" : "x", scale, offset, clamps.value.min, clamps.value.max), { x: read })
|
|
101000
|
+
};
|
|
101001
|
+
}
|
|
101002
|
+
function clampTokens$1(clampMin, clampMax) {
|
|
101003
|
+
if (clampMin === void 0 && clampMax === void 0) return {
|
|
101004
|
+
ok: true,
|
|
101005
|
+
value: {
|
|
101006
|
+
min: null,
|
|
101007
|
+
max: null
|
|
101008
|
+
}
|
|
101009
|
+
};
|
|
101010
|
+
if (clampMin === void 0 || clampMax === void 0) return fail$2("clamp");
|
|
101011
|
+
const min = signedToken(clampMin);
|
|
101012
|
+
const max = signedToken(clampMax);
|
|
101013
|
+
if (min === null || max === null || clampMin > clampMax) return fail$2("clamp");
|
|
101014
|
+
return {
|
|
101015
|
+
ok: true,
|
|
101016
|
+
value: {
|
|
101017
|
+
min,
|
|
101018
|
+
max
|
|
101019
|
+
}
|
|
101020
|
+
};
|
|
101021
|
+
}
|
|
101022
|
+
function compileCompanions$1(input, target, value) {
|
|
101023
|
+
if (target.path === void 0) return fail$2("target");
|
|
101024
|
+
const path = target.path;
|
|
101025
|
+
return (target.companions ?? []).filter((companion) => companionIncluded$1(companion, input.apply)).reduce((acc, companion) => {
|
|
101026
|
+
if (!acc.ok) return acc;
|
|
101027
|
+
const built = companionField(input, path, companion);
|
|
101028
|
+
if (!built.ok) return {
|
|
101029
|
+
ok: false,
|
|
101030
|
+
reason: built.reason
|
|
101031
|
+
};
|
|
101032
|
+
return {
|
|
101033
|
+
ok: true,
|
|
101034
|
+
value: {
|
|
101035
|
+
...acc.value,
|
|
101036
|
+
[companion.path]: built.value
|
|
101037
|
+
}
|
|
101038
|
+
};
|
|
101039
|
+
}, {
|
|
101040
|
+
ok: true,
|
|
101041
|
+
value: { [path]: value }
|
|
101042
|
+
});
|
|
101043
|
+
}
|
|
101044
|
+
function companionIncluded$1(companion, apply) {
|
|
101045
|
+
if (companion.kind === "transition-time") return true;
|
|
101046
|
+
return companion.when === "always" || apply === "add";
|
|
101047
|
+
}
|
|
101048
|
+
function companionField(input, path, companion) {
|
|
101049
|
+
if (companion.kind === "constant") {
|
|
101050
|
+
const expr = constantExpr(companion.value);
|
|
101051
|
+
if (expr === null) return fail$2("scale");
|
|
101052
|
+
return {
|
|
101053
|
+
ok: true,
|
|
101054
|
+
value: literal(expr)
|
|
101055
|
+
};
|
|
101056
|
+
}
|
|
101057
|
+
if (companion.kind === "clock") return {
|
|
101058
|
+
ok: true,
|
|
101059
|
+
value: literal("now")
|
|
101060
|
+
};
|
|
101061
|
+
return transitionField(input, path, companion.sourceChangedAt);
|
|
101062
|
+
}
|
|
101063
|
+
function transitionField(input, path, sourceChangedAt) {
|
|
101064
|
+
if (sourceChangedAt === "prefer" && input.sourceValueKind === "boolean" && input.changedAtField !== null && isIdentifier(input.changedAtField)) return {
|
|
101065
|
+
ok: true,
|
|
101066
|
+
value: fromRead(refOf$1(input.draft), input.draft.source.cap, input.changedAtField)
|
|
101067
|
+
};
|
|
101068
|
+
if (!isIdentifier(path)) return fail$2("transform");
|
|
101069
|
+
const bindings = { [path]: fromRead(input.device, input.draft.cap, path) };
|
|
101070
|
+
return {
|
|
101071
|
+
ok: true,
|
|
101072
|
+
value: expression(`latchedAt(${path})`, bindings)
|
|
101073
|
+
};
|
|
101074
|
+
}
|
|
101075
|
+
function refOf$1(draft) {
|
|
101076
|
+
return {
|
|
101077
|
+
addonId: draft.source.addonId,
|
|
101078
|
+
stableId: draft.source.stableId
|
|
101079
|
+
};
|
|
101080
|
+
}
|
|
101081
|
+
//#endregion
|
|
101082
|
+
//#region src/composition/customize/normalize.ts
|
|
101083
|
+
function sortKeys(value) {
|
|
101084
|
+
if (Array.isArray(value)) return value.map(sortKeys);
|
|
101085
|
+
if (typeof value !== "object" || value === null) return value;
|
|
101086
|
+
return Object.fromEntries(Object.entries(value).toSorted(([a], [b]) => a.localeCompare(b)).map(([key, inner]) => [key, sortKeys(inner)]));
|
|
101087
|
+
}
|
|
101088
|
+
/** Key order is not part of the stored contract. Array order is. */
|
|
101089
|
+
function normalizeStored(stored) {
|
|
101090
|
+
return sortKeys(stored);
|
|
101091
|
+
}
|
|
101092
|
+
function sameStored(a, b) {
|
|
101093
|
+
return JSON.stringify(normalizeStored(a)) === JSON.stringify(normalizeStored(b));
|
|
101094
|
+
}
|
|
101095
|
+
//#endregion
|
|
101096
|
+
//#region src/composition/customize/scalar-decode.ts
|
|
101097
|
+
var catalog$3 = CAP_CUSTOMIZE_CATALOG;
|
|
101098
|
+
function decodeScalarOverride(input) {
|
|
101099
|
+
const target = catalogTarget$3(input.cap, input.targetId);
|
|
101100
|
+
if (target === null || target.cardinality !== "scalar" || target.path === void 0) return null;
|
|
101101
|
+
if (input.feature.cap !== input.cap || input.feature.kind !== "fields") return null;
|
|
101102
|
+
const outputKind = scalarOutputKind(target.valueKind);
|
|
101103
|
+
if (outputKind === null) return null;
|
|
101104
|
+
const value = input.feature.fields[target.path];
|
|
101105
|
+
const read = readValue(value, outputKind, input.cap, input.targetId);
|
|
101106
|
+
if (read === null) return null;
|
|
101107
|
+
const apply = inferApply$1(target, input.feature.fields);
|
|
101108
|
+
if (apply === null) return null;
|
|
101109
|
+
const changedAtField = inferChangedAt(target, input.feature.fields, read);
|
|
101110
|
+
const sourceUnit = unitFor(target, read.sourceValueKind, read.draft.source.cap);
|
|
101111
|
+
const decoded = {
|
|
101112
|
+
...read,
|
|
101113
|
+
apply,
|
|
101114
|
+
changedAtField,
|
|
101115
|
+
sourceUnit
|
|
101116
|
+
};
|
|
101117
|
+
return reproduces$1(decoded, input.device, input.feature) ? decoded : null;
|
|
101118
|
+
}
|
|
101119
|
+
function catalogTarget$3(cap, targetId) {
|
|
101120
|
+
const entry = catalog$3[cap];
|
|
101121
|
+
if (entry === void 0) return null;
|
|
101122
|
+
return entry.targets.find((target) => target.id === targetId) ?? null;
|
|
101123
|
+
}
|
|
101124
|
+
function scalarOutputKind(valueKind) {
|
|
101125
|
+
if (valueKind === "boolean" || valueKind === "number" || valueKind === "string") return valueKind;
|
|
101126
|
+
return null;
|
|
101127
|
+
}
|
|
101128
|
+
function readValue(field, outputKind, cap, targetId) {
|
|
101129
|
+
if (field === void 0) return null;
|
|
101130
|
+
if (field.kind === "from") return drafted(field, { kind: "identity" }, outputKind, cap, targetId);
|
|
101131
|
+
if (field.kind !== "expression") return null;
|
|
101132
|
+
if (field.expr === "number(x)" && outputKind === "number") return drafted(field, { kind: "identity" }, "string", cap, targetId);
|
|
101133
|
+
if (field.expr === "!x" && outputKind === "boolean") return drafted(field, { kind: "invert" }, "boolean", cap, targetId);
|
|
101134
|
+
const dwell = parseDwell(field.expr);
|
|
101135
|
+
if (dwell !== null) return drafted(field, {
|
|
101136
|
+
kind: "threshold",
|
|
101137
|
+
comparison: dwell.comparison,
|
|
101138
|
+
threshold: dwell.threshold,
|
|
101139
|
+
startDwellMs: dwell.startDwellMs,
|
|
101140
|
+
stopDwellMs: dwell.stopDwellMs
|
|
101141
|
+
}, "number", cap, targetId);
|
|
101142
|
+
const linear = parseLinear(field.expr);
|
|
101143
|
+
if (linear === null || outputKind !== "number") return null;
|
|
101144
|
+
return drafted(field, {
|
|
101145
|
+
kind: "linear",
|
|
101146
|
+
scale: linear.scale,
|
|
101147
|
+
offset: linear.offset,
|
|
101148
|
+
...linear.clampMin === void 0 || linear.clampMax === void 0 ? {} : {
|
|
101149
|
+
clampMin: linear.clampMin,
|
|
101150
|
+
clampMax: linear.clampMax
|
|
101151
|
+
}
|
|
101152
|
+
}, linear.inner === "number(x)" ? "string" : "number", cap, targetId);
|
|
101153
|
+
}
|
|
101154
|
+
function drafted(field, transform, sourceValueKind, cap, targetId) {
|
|
101155
|
+
const bound = singleFrom(field);
|
|
101156
|
+
if (bound === null) return null;
|
|
101157
|
+
return {
|
|
101158
|
+
sourceValueKind,
|
|
101159
|
+
draft: {
|
|
101160
|
+
kind: "scalar",
|
|
101161
|
+
cap,
|
|
101162
|
+
targetId,
|
|
101163
|
+
source: {
|
|
101164
|
+
addonId: bound.addonId,
|
|
101165
|
+
stableId: bound.stableId,
|
|
101166
|
+
cap: bound.cap,
|
|
101167
|
+
fieldPath: bound.fieldPath
|
|
101168
|
+
},
|
|
101169
|
+
transform
|
|
101170
|
+
}
|
|
101171
|
+
};
|
|
101172
|
+
}
|
|
101173
|
+
function inferApply$1(target, fields) {
|
|
101174
|
+
const addPaths = (target.companions ?? []).flatMap((companion) => companion.kind !== "transition-time" && companion.when === "add" ? [companion.path] : []);
|
|
101175
|
+
if (addPaths.length === 0) return "replace";
|
|
101176
|
+
const present = addPaths.filter((path) => fields[path] !== void 0);
|
|
101177
|
+
if (present.length === addPaths.length) return "add";
|
|
101178
|
+
if (present.length === 0) return "replace";
|
|
101179
|
+
return null;
|
|
101180
|
+
}
|
|
101181
|
+
function inferChangedAt(target, fields, read) {
|
|
101182
|
+
if (read.sourceValueKind !== "boolean") return null;
|
|
101183
|
+
const transition = (target.companions ?? []).find((companion) => companion.kind === "transition-time");
|
|
101184
|
+
if (transition === void 0 || transition.sourceChangedAt !== "prefer") return null;
|
|
101185
|
+
const since = fields[transition.path];
|
|
101186
|
+
if (since?.kind !== "from") return null;
|
|
101187
|
+
if (since.cap !== read.draft.source.cap) return null;
|
|
101188
|
+
if (since.source.addonId !== read.draft.source.addonId || since.source.stableId !== read.draft.source.stableId) return null;
|
|
101189
|
+
return since.fieldPath;
|
|
101190
|
+
}
|
|
101191
|
+
function unitFor(target, valueKind, sourceCap) {
|
|
101192
|
+
if (valueKind === "boolean" && sourceCap === "switch") return null;
|
|
101193
|
+
if (valueKind === "number") return target.sources.find((source) => source.kind === "numeric")?.requiredUnit ?? null;
|
|
101194
|
+
return null;
|
|
101195
|
+
}
|
|
101196
|
+
function reproduces$1(decoded, device, stored) {
|
|
101197
|
+
const compiled = compileScalarOverride({
|
|
101198
|
+
draft: decoded.draft,
|
|
101199
|
+
device,
|
|
101200
|
+
apply: decoded.apply,
|
|
101201
|
+
sourceValueKind: decoded.sourceValueKind,
|
|
101202
|
+
changedAtField: decoded.changedAtField,
|
|
101203
|
+
sourceUnit: decoded.sourceUnit
|
|
101204
|
+
});
|
|
101205
|
+
if (!compiled.ok) return false;
|
|
101206
|
+
return sameFeature$2(compiled.value, stored);
|
|
101207
|
+
}
|
|
101208
|
+
function sameFeature$2(compiled, stored) {
|
|
101209
|
+
return sameStored(wrap$1(withoutEnabled(compiled)), wrap$1(withoutEnabled(stored)));
|
|
101210
|
+
}
|
|
101211
|
+
function withoutEnabled(feature) {
|
|
101212
|
+
const { enabled: _enabled, ...rest } = feature;
|
|
101213
|
+
return rest;
|
|
101214
|
+
}
|
|
101215
|
+
function wrap$1(feature) {
|
|
101216
|
+
return {
|
|
101217
|
+
family: "composition",
|
|
101218
|
+
target: {
|
|
101219
|
+
addonId: "t",
|
|
101220
|
+
stableId: "t"
|
|
101221
|
+
},
|
|
101222
|
+
feature
|
|
101223
|
+
};
|
|
101224
|
+
}
|
|
101225
|
+
//#endregion
|
|
101226
|
+
//#region src/composition/customize/scalar-status.ts
|
|
101227
|
+
function projectScalarAssignment(input) {
|
|
101228
|
+
if (input.stored.kind === "pending") return unanswered$1(input.targetId, "pending", null);
|
|
101229
|
+
if (input.stored.kind === "unknown") return unanswered$1(input.targetId, "unknown", input.stored.reason ?? "unknown");
|
|
101230
|
+
if (input.stored.value === null) return native$2(input.targetId);
|
|
101231
|
+
const decoded = decodeScalarOverride({
|
|
101232
|
+
feature: input.stored.value,
|
|
101233
|
+
device: input.device,
|
|
101234
|
+
cap: input.cap,
|
|
101235
|
+
targetId: input.targetId
|
|
101236
|
+
});
|
|
101237
|
+
if (decoded === null) return {
|
|
101238
|
+
text: "unknown",
|
|
101239
|
+
status: status$1(input.targetId, true, "assigned", "unavailable", "not-canonical")
|
|
101240
|
+
};
|
|
101241
|
+
return projectDecoded$1(input, decoded.apply, sourceLabel(decoded.draft.source.cap, decoded.draft.source.fieldPath));
|
|
101242
|
+
}
|
|
101243
|
+
function projectDecoded$1(input, apply, label) {
|
|
101244
|
+
if (input.sourcePresence === "pending") return {
|
|
101245
|
+
text: "pending",
|
|
101246
|
+
status: status$1(input.targetId, true, "assigned", "stale", null)
|
|
101247
|
+
};
|
|
101248
|
+
if (input.sourcePresence === "unknown") return {
|
|
101249
|
+
text: "unknown",
|
|
101250
|
+
status: status$1(input.targetId, true, "assigned", "stale", input.sourceUnknownReason ?? "unknown")
|
|
101251
|
+
};
|
|
101252
|
+
if (input.sourcePresence === "absent" && apply === "replace") return {
|
|
101253
|
+
text: "Native · source missing",
|
|
101254
|
+
status: status$1(input.targetId, true, "native", "released", "source-missing")
|
|
101255
|
+
};
|
|
101256
|
+
if (input.sourcePresence === "absent") return {
|
|
101257
|
+
text: `Assigned · ${label}`,
|
|
101258
|
+
status: status$1(input.targetId, true, "assigned", "unavailable", "source-missing")
|
|
101259
|
+
};
|
|
101260
|
+
return {
|
|
101261
|
+
text: `Assigned · ${label}`,
|
|
101262
|
+
status: status$1(input.targetId, true, "assigned", "active", null)
|
|
101263
|
+
};
|
|
101264
|
+
}
|
|
101265
|
+
function native$2(targetId) {
|
|
101266
|
+
return {
|
|
101267
|
+
text: "Native",
|
|
101268
|
+
status: status$1(targetId, false, "native", "active", null)
|
|
101269
|
+
};
|
|
101270
|
+
}
|
|
101271
|
+
function unanswered$1(targetId, text, reason) {
|
|
101272
|
+
return {
|
|
101273
|
+
text,
|
|
101274
|
+
status: status$1(targetId, false, "native", text === "pending" ? "unavailable" : "stale", reason)
|
|
101275
|
+
};
|
|
101276
|
+
}
|
|
101277
|
+
function sourceLabel(cap, fieldPath) {
|
|
101278
|
+
return `${cap}.${fieldPath}`;
|
|
101279
|
+
}
|
|
101280
|
+
function status$1(targetId, configured, source, state, reason) {
|
|
101281
|
+
return {
|
|
101282
|
+
targetId,
|
|
101283
|
+
configured,
|
|
101284
|
+
source,
|
|
101285
|
+
state,
|
|
101286
|
+
reason
|
|
101287
|
+
};
|
|
101288
|
+
}
|
|
101289
|
+
//#endregion
|
|
101290
|
+
//#region src/composition/customize/event-compile.ts
|
|
101291
|
+
var catalog$2 = CAP_CUSTOMIZE_CATALOG;
|
|
101292
|
+
function compilePulseOverride(input) {
|
|
101293
|
+
const target = catalogTarget$2(input.draft.cap, input.draft.targetId);
|
|
101294
|
+
if (target === null || target.shape !== "pulse") return fail$1("target");
|
|
101295
|
+
const timestampPath = target.timestampPath;
|
|
101296
|
+
const counterPath = target.counterPath;
|
|
101297
|
+
if (timestampPath === void 0 || counterPath === void 0 || !isIdentifier(timestampPath) || !isIdentifier(counterPath)) return fail$1("path");
|
|
101298
|
+
if (!(target.edges ?? []).includes("rising")) return fail$1("edge");
|
|
101299
|
+
const pairs = pairSources(input);
|
|
101300
|
+
if (!pairs.ok) return pairs;
|
|
101301
|
+
if (pairs.value.length === 0) return fail$1("sources");
|
|
101302
|
+
const debounce = unsignedToken(input.draft.debounceMs);
|
|
101303
|
+
if (debounce === null) return fail$1("debounce");
|
|
101304
|
+
const ordered = pairs.value.toSorted((a, b) => pairKey(a).localeCompare(pairKey(b)));
|
|
101305
|
+
return {
|
|
101306
|
+
ok: true,
|
|
101307
|
+
value: {
|
|
101308
|
+
kind: "fields",
|
|
101309
|
+
cap: input.draft.cap,
|
|
101310
|
+
enabled: input.draft.enabled,
|
|
101311
|
+
fields: {
|
|
101312
|
+
[timestampPath]: expression(pulseExpr(ordered.length, debounce), pulseBindings(ordered)),
|
|
101313
|
+
[counterPath]: expression(`count(${timestampPath})`, { [timestampPath]: fromRead(input.device, input.draft.cap, timestampPath) })
|
|
101314
|
+
}
|
|
101315
|
+
}
|
|
101316
|
+
};
|
|
101317
|
+
}
|
|
101318
|
+
function compileSpanOverride(input) {
|
|
101319
|
+
const target = catalogTarget$2(input.draft.cap, input.draft.targetId);
|
|
101320
|
+
if (target === null || target.shape !== "span") return fail$1("target");
|
|
101321
|
+
if (target.applyAuthority?.kind !== "camera-sensors") return fail$1("authority");
|
|
101322
|
+
if (input.draft.timeoutMs < 0 || !Number.isFinite(input.draft.timeoutMs)) return fail$1("timeout");
|
|
101323
|
+
if (target.cooldownMs === void 0 && input.draft.cooldownMs !== void 0) return fail$1("cooldown");
|
|
101324
|
+
if (input.draft.cooldownMs !== void 0 && input.draft.cooldownMs < 0) return fail$1("cooldown");
|
|
101325
|
+
const sensors = sensorEntries(input.draft.sources, input.device, target.sourceModes);
|
|
101326
|
+
if (!sensors.ok) return sensors;
|
|
101327
|
+
if (sensors.value.length === 0) return {
|
|
101328
|
+
ok: true,
|
|
101329
|
+
value: {
|
|
101330
|
+
config: null,
|
|
101331
|
+
timeoutMs: input.draft.timeoutMs,
|
|
101332
|
+
cooldownMs: input.draft.cooldownMs
|
|
101333
|
+
}
|
|
101334
|
+
};
|
|
101335
|
+
const parsed = CameraSensorsConfigSchema.safeParse({ sensors: sensors.value });
|
|
101336
|
+
if (!parsed.success) {
|
|
101337
|
+
const issue = parsed.error.issues[0];
|
|
101338
|
+
return fail$1(issue === void 0 ? "cameraSensors" : issue.message);
|
|
101339
|
+
}
|
|
101340
|
+
return {
|
|
101341
|
+
ok: true,
|
|
101342
|
+
value: {
|
|
101343
|
+
config: parsed.data,
|
|
101344
|
+
timeoutMs: input.draft.timeoutMs,
|
|
101345
|
+
cooldownMs: input.draft.cooldownMs
|
|
101346
|
+
}
|
|
101347
|
+
};
|
|
101348
|
+
}
|
|
101349
|
+
function pairSources(input) {
|
|
101350
|
+
if (input.changedAtFields.length !== input.draft.sources.length) return fail$1("changed-at");
|
|
101351
|
+
const pairs = input.draft.sources.map((source, index) => {
|
|
101352
|
+
return {
|
|
101353
|
+
source,
|
|
101354
|
+
changedAtField: input.changedAtFields[index] ?? ""
|
|
101355
|
+
};
|
|
101356
|
+
});
|
|
101357
|
+
if (pairs.some((pair) => pair.changedAtField.length === 0 || pair.source.fieldPath.length === 0)) return fail$1("changed-at");
|
|
101358
|
+
return {
|
|
101359
|
+
ok: true,
|
|
101360
|
+
value: pairs
|
|
101361
|
+
};
|
|
101362
|
+
}
|
|
101363
|
+
function pairKey(pair) {
|
|
101364
|
+
return `${pair.source.addonId}/${pair.source.stableId}#${pair.source.cap}#${pair.source.fieldPath}`;
|
|
101365
|
+
}
|
|
101366
|
+
function pulseExpr(count, debounce) {
|
|
101367
|
+
const roses = [];
|
|
101368
|
+
for (let index = 0; index < count; index += 1) roses.push(`rose(active${index}, changed${index}, ${debounce})`);
|
|
101369
|
+
return `latest(${roses.join(", ")})`;
|
|
101370
|
+
}
|
|
101371
|
+
function pulseBindings(pairs) {
|
|
101372
|
+
const bindings = {};
|
|
101373
|
+
pairs.forEach((pair, index) => {
|
|
101374
|
+
const ref = {
|
|
101375
|
+
addonId: pair.source.addonId,
|
|
101376
|
+
stableId: pair.source.stableId
|
|
101377
|
+
};
|
|
101378
|
+
bindings[`active${index}`] = fromRead(ref, pair.source.cap, pair.source.fieldPath);
|
|
101379
|
+
bindings[`changed${index}`] = fromRead(ref, pair.source.cap, pair.changedAtField);
|
|
101380
|
+
});
|
|
101381
|
+
return bindings;
|
|
101382
|
+
}
|
|
101383
|
+
function sensorEntries(sources, device, modes) {
|
|
101384
|
+
const entries = [];
|
|
101385
|
+
for (const source of sources) {
|
|
101386
|
+
if (source.addonId === device.addonId && source.stableId === device.stableId) return fail$1("self");
|
|
101387
|
+
const mode = source.mode ?? "in-addition";
|
|
101388
|
+
if (modes !== void 0 && !modes.includes(mode)) return fail$1("mode");
|
|
101389
|
+
if (modes === void 0 && source.mode !== void 0 && source.mode !== "in-addition") return fail$1("mode");
|
|
101390
|
+
entries.push({
|
|
101391
|
+
addonId: source.addonId,
|
|
101392
|
+
stableId: source.stableId,
|
|
101393
|
+
mode
|
|
101394
|
+
});
|
|
101395
|
+
}
|
|
101396
|
+
return {
|
|
101397
|
+
ok: true,
|
|
101398
|
+
value: entries
|
|
101399
|
+
};
|
|
101400
|
+
}
|
|
101401
|
+
function catalogTarget$2(cap, targetId) {
|
|
101402
|
+
const entry = catalog$2[cap];
|
|
101403
|
+
if (entry === void 0) return null;
|
|
101404
|
+
return entry.targets.find((target) => target.id === targetId) ?? null;
|
|
101405
|
+
}
|
|
101406
|
+
function fail$1(reason) {
|
|
101407
|
+
return {
|
|
101408
|
+
ok: false,
|
|
101409
|
+
reason
|
|
101410
|
+
};
|
|
101411
|
+
}
|
|
101412
|
+
//#endregion
|
|
101413
|
+
//#region src/composition/customize/event-decode.ts
|
|
101414
|
+
var ROSE_SOURCE = String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
101415
|
+
function decodePulseOverride(input) {
|
|
101416
|
+
if (input.feature.cap !== input.cap || input.feature.kind !== "fields") return null;
|
|
101417
|
+
if (input.feature.enabled === void 0) return null;
|
|
101418
|
+
const timestamp = input.feature.fields[input.timestampPath];
|
|
101419
|
+
const counter = input.feature.fields[input.counterPath];
|
|
101420
|
+
if (timestamp === void 0 || counter === void 0) return null;
|
|
101421
|
+
if (Object.keys(input.feature.fields).length !== 2) return null;
|
|
101422
|
+
const edges = readEdges(timestamp);
|
|
101423
|
+
if (edges === null) return null;
|
|
101424
|
+
if (readCount(counter, input) === null) return null;
|
|
101425
|
+
const draft = {
|
|
101426
|
+
kind: "pulse",
|
|
101427
|
+
cap: input.cap,
|
|
101428
|
+
targetId: input.targetId,
|
|
101429
|
+
enabled: input.feature.enabled,
|
|
101430
|
+
debounceMs: edges.debounceMs,
|
|
101431
|
+
sources: edges.sources
|
|
101432
|
+
};
|
|
101433
|
+
const decoded = {
|
|
101434
|
+
draft,
|
|
101435
|
+
changedAtFields: edges.changedAtFields
|
|
101436
|
+
};
|
|
101437
|
+
const compiled = compilePulseOverride({
|
|
101438
|
+
draft,
|
|
101439
|
+
device: input.device,
|
|
101440
|
+
changedAtFields: edges.changedAtFields
|
|
101441
|
+
});
|
|
101442
|
+
if (!compiled.ok) return null;
|
|
101443
|
+
return sameFeature$1(compiled.value, input.feature) ? decoded : null;
|
|
101444
|
+
}
|
|
101445
|
+
function readEdges(field) {
|
|
101446
|
+
if (field.kind !== "expression" || !field.expr.startsWith("latest(") || !field.expr.endsWith(")")) return null;
|
|
101447
|
+
const inner = field.expr.slice(7, -1);
|
|
101448
|
+
const found = [...inner.matchAll(new RegExp(ROSE_SOURCE, "g"))];
|
|
101449
|
+
if (found.length === 0 || found.map((match) => match[0]).join(", ") !== inner) return null;
|
|
101450
|
+
if (Object.keys(field.bindings).length !== found.length * 2) return null;
|
|
101451
|
+
const rows = found.map((match, index) => readRose(match, index, field.bindings));
|
|
101452
|
+
if (rows.some((row) => row === null)) return null;
|
|
101453
|
+
const edges = rows.filter((row) => row !== null);
|
|
101454
|
+
const debounceMs = edges[0]?.debounceMs;
|
|
101455
|
+
if (debounceMs === void 0 || edges.some((row) => row.debounceMs !== debounceMs)) return null;
|
|
101456
|
+
return {
|
|
101457
|
+
debounceMs,
|
|
101458
|
+
sources: edges.map((row) => row.source),
|
|
101459
|
+
changedAtFields: edges.map((row) => row.changedAtField)
|
|
101460
|
+
};
|
|
101461
|
+
}
|
|
101462
|
+
function readRose(match, index, bindings) {
|
|
101463
|
+
const activeIndex = Number(match[1]);
|
|
101464
|
+
const changedIndex = Number(match[2]);
|
|
101465
|
+
const debounceMs = Number(match[3]);
|
|
101466
|
+
if (activeIndex !== index || changedIndex !== index || !Number.isFinite(debounceMs)) return null;
|
|
101467
|
+
const active = fromBinding(bindings[`active${index}`]);
|
|
101468
|
+
const changed = fromBinding(bindings[`changed${index}`]);
|
|
101469
|
+
if (active === null || changed === null) return null;
|
|
101470
|
+
if (active.cap !== changed.cap) return null;
|
|
101471
|
+
if (active.source.addonId !== changed.source.addonId) return null;
|
|
101472
|
+
if (active.source.stableId !== changed.source.stableId) return null;
|
|
101473
|
+
return {
|
|
101474
|
+
debounceMs,
|
|
101475
|
+
changedAtField: changed.fieldPath,
|
|
101476
|
+
source: {
|
|
101477
|
+
addonId: active.source.addonId,
|
|
101478
|
+
stableId: active.source.stableId,
|
|
101479
|
+
cap: active.cap,
|
|
101480
|
+
fieldPath: active.fieldPath
|
|
101481
|
+
}
|
|
101482
|
+
};
|
|
101483
|
+
}
|
|
101484
|
+
function fromBinding(value) {
|
|
101485
|
+
if (value === void 0 || value.kind !== "from") return null;
|
|
101486
|
+
return value;
|
|
101487
|
+
}
|
|
101488
|
+
function readCount(field, input) {
|
|
101489
|
+
if (field.kind !== "expression" || field.expr !== `count(${input.timestampPath})`) return null;
|
|
101490
|
+
const binding = fromBinding(field.bindings[input.timestampPath]);
|
|
101491
|
+
if (binding === null) return null;
|
|
101492
|
+
if (Object.keys(field.bindings).length !== 1) return null;
|
|
101493
|
+
if (binding.cap !== input.cap || binding.fieldPath !== input.timestampPath) return null;
|
|
101494
|
+
if (binding.source.addonId !== input.device.addonId) return null;
|
|
101495
|
+
if (binding.source.stableId !== input.device.stableId) return null;
|
|
101496
|
+
return true;
|
|
101497
|
+
}
|
|
101498
|
+
function sameFeature$1(left, right) {
|
|
101499
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
101500
|
+
}
|
|
101501
|
+
//#endregion
|
|
101502
|
+
//#region src/composition/customize/event-eval.ts
|
|
101503
|
+
var INITIAL_PULSE = {
|
|
101504
|
+
priorActive: void 0,
|
|
101505
|
+
lastPressedAt: null,
|
|
101506
|
+
count: 0,
|
|
101507
|
+
acceptedAt: null
|
|
101508
|
+
};
|
|
101509
|
+
var INITIAL_SPAN = {
|
|
101510
|
+
open: false,
|
|
101511
|
+
startedAt: null,
|
|
101512
|
+
endedAt: null,
|
|
101513
|
+
quietUntil: null,
|
|
101514
|
+
priorActive: void 0
|
|
101515
|
+
};
|
|
101516
|
+
function stepPulse(state, sample, debounceMs) {
|
|
101517
|
+
if (sample.kind === "unread" || debounceMs < 0) return state;
|
|
101518
|
+
if (state.priorActive === void 0) return {
|
|
101519
|
+
...state,
|
|
101520
|
+
priorActive: sample.active
|
|
101521
|
+
};
|
|
101522
|
+
if (!sample.active) return {
|
|
101523
|
+
...state,
|
|
101524
|
+
priorActive: false
|
|
101525
|
+
};
|
|
101526
|
+
if (state.priorActive) return state;
|
|
101527
|
+
const at = finite(sample.changedAt);
|
|
101528
|
+
if (at === null) return {
|
|
101529
|
+
...state,
|
|
101530
|
+
priorActive: true
|
|
101531
|
+
};
|
|
101532
|
+
if (state.acceptedAt !== null && at - state.acceptedAt < debounceMs) return {
|
|
101533
|
+
...state,
|
|
101534
|
+
priorActive: true
|
|
101535
|
+
};
|
|
101536
|
+
return {
|
|
101537
|
+
priorActive: true,
|
|
101538
|
+
lastPressedAt: at,
|
|
101539
|
+
count: state.count + 1,
|
|
101540
|
+
acceptedAt: at
|
|
101541
|
+
};
|
|
101542
|
+
}
|
|
101543
|
+
function stepSpan(state, sample, timing) {
|
|
101544
|
+
const timed = expire(state, timing);
|
|
101545
|
+
if (sample.kind === "unread" || timing.timeoutMs < 0 || timing.cooldownMs < 0) return timed;
|
|
101546
|
+
if (timed.priorActive === void 0) return {
|
|
101547
|
+
...timed,
|
|
101548
|
+
priorActive: sample.active
|
|
101549
|
+
};
|
|
101550
|
+
if (timed.open && timed.priorActive && !sample.active) return finish(timed, finite(sample.changedAt) ?? timing.nowMs, timing.cooldownMs, false);
|
|
101551
|
+
if (!sample.active) return {
|
|
101552
|
+
...timed,
|
|
101553
|
+
priorActive: false
|
|
101554
|
+
};
|
|
101555
|
+
if (timed.priorActive || timed.open) return {
|
|
101556
|
+
...timed,
|
|
101557
|
+
priorActive: true
|
|
101558
|
+
};
|
|
101559
|
+
const at = finite(sample.changedAt) ?? timing.nowMs;
|
|
101560
|
+
if (timed.quietUntil !== null && at < timed.quietUntil) return {
|
|
101561
|
+
...timed,
|
|
101562
|
+
priorActive: true
|
|
101563
|
+
};
|
|
101564
|
+
return {
|
|
101565
|
+
open: true,
|
|
101566
|
+
startedAt: at,
|
|
101567
|
+
endedAt: null,
|
|
101568
|
+
quietUntil: null,
|
|
101569
|
+
priorActive: true
|
|
101570
|
+
};
|
|
101571
|
+
}
|
|
101572
|
+
function expire(state, timing) {
|
|
101573
|
+
if (!state.open || state.startedAt === null) return state;
|
|
101574
|
+
const deadline = state.startedAt + timing.timeoutMs;
|
|
101575
|
+
if (timing.nowMs < deadline) return state;
|
|
101576
|
+
return finish(state, deadline, timing.cooldownMs, state.priorActive === true);
|
|
101577
|
+
}
|
|
101578
|
+
function finish(state, endedAt, cooldownMs, priorActive) {
|
|
101579
|
+
return {
|
|
101580
|
+
open: false,
|
|
101581
|
+
startedAt: state.startedAt,
|
|
101582
|
+
endedAt,
|
|
101583
|
+
quietUntil: cooldownMs > 0 ? endedAt + cooldownMs : null,
|
|
101584
|
+
priorActive
|
|
101585
|
+
};
|
|
101586
|
+
}
|
|
101587
|
+
function finite(value) {
|
|
101588
|
+
return value !== null && Number.isFinite(value) ? value : null;
|
|
101589
|
+
}
|
|
101590
|
+
//#endregion
|
|
101591
|
+
//#region src/composition/customize/event-status.ts
|
|
101592
|
+
function projectPulseAssignment(input) {
|
|
101593
|
+
if (input.stored.kind === "pending") return held(input.targetId, "pending", null);
|
|
101594
|
+
if (input.stored.kind === "unknown") return held(input.targetId, "unknown", input.stored.reason ?? "unknown");
|
|
101595
|
+
if (input.stored.value === null) return native$1(input.targetId);
|
|
101596
|
+
const decoded = decodePulseOverride({
|
|
101597
|
+
feature: input.stored.value,
|
|
101598
|
+
device: input.device,
|
|
101599
|
+
cap: input.cap,
|
|
101600
|
+
targetId: input.targetId,
|
|
101601
|
+
timestampPath: input.timestampPath,
|
|
101602
|
+
counterPath: input.counterPath
|
|
101603
|
+
});
|
|
101604
|
+
if (decoded === null) return {
|
|
101605
|
+
text: "unknown",
|
|
101606
|
+
status: row(input.targetId, true, "assigned", "unavailable", "not-canonical")
|
|
101607
|
+
};
|
|
101608
|
+
if (input.sourcePresence === "pending") return {
|
|
101609
|
+
text: "pending",
|
|
101610
|
+
status: row(input.targetId, true, "assigned", "stale", null)
|
|
101611
|
+
};
|
|
101612
|
+
if (input.sourcePresence === "unknown") return {
|
|
101613
|
+
text: "unknown",
|
|
101614
|
+
status: row(input.targetId, true, "assigned", "stale", input.sourceUnknownReason ?? "unknown")
|
|
101615
|
+
};
|
|
101616
|
+
if (input.sourcePresence === "absent" && input.apply === "replace") return {
|
|
101617
|
+
text: "Native · source missing",
|
|
101618
|
+
status: row(input.targetId, true, "native", "released", "source-missing")
|
|
101619
|
+
};
|
|
101620
|
+
if (input.sourcePresence === "absent") return {
|
|
101621
|
+
text: "Assigned · source missing",
|
|
101622
|
+
status: row(input.targetId, true, "assigned", "unavailable", "source-missing")
|
|
101623
|
+
};
|
|
101624
|
+
const source = decoded.draft.sources[0];
|
|
101625
|
+
return {
|
|
101626
|
+
text: `Assigned · ${source === void 0 ? "assigned" : `${source.cap}.${source.fieldPath}`}`,
|
|
101627
|
+
status: row(input.targetId, true, "assigned", "active", null)
|
|
101628
|
+
};
|
|
101629
|
+
}
|
|
101630
|
+
function projectSpanAssignment(targetId, stored) {
|
|
101631
|
+
if (stored.kind === "pending") return {
|
|
101632
|
+
text: "pending",
|
|
101633
|
+
writable: false,
|
|
101634
|
+
rows: [],
|
|
101635
|
+
status: row(targetId, false, "native", "unavailable", null)
|
|
101636
|
+
};
|
|
101637
|
+
if (stored.kind === "unknown") return {
|
|
101638
|
+
text: "unknown",
|
|
101639
|
+
writable: false,
|
|
101640
|
+
rows: [],
|
|
101641
|
+
status: row(targetId, false, "native", "stale", stored.reason ?? "unknown")
|
|
101642
|
+
};
|
|
101643
|
+
if (stored.value.state === "unreadable") return {
|
|
101644
|
+
text: "unreadable",
|
|
101645
|
+
writable: false,
|
|
101646
|
+
rows: [],
|
|
101647
|
+
status: row(targetId, false, "assigned", "unavailable", stored.value.reason)
|
|
101648
|
+
};
|
|
101649
|
+
if (stored.value.state === "not-configured") return {
|
|
101650
|
+
text: "Native",
|
|
101651
|
+
writable: true,
|
|
101652
|
+
rows: [],
|
|
101653
|
+
status: row(targetId, false, "native", "active", null)
|
|
101654
|
+
};
|
|
101655
|
+
const rows = stored.value.sensors.map(sensorRow);
|
|
101656
|
+
const reason = spanReason(stored.value);
|
|
101657
|
+
return {
|
|
101658
|
+
text: rows.length === 0 ? "Native" : "Assigned",
|
|
101659
|
+
writable: true,
|
|
101660
|
+
rows,
|
|
101661
|
+
status: row(targetId, rows.length > 0, "assigned", "active", reason)
|
|
101662
|
+
};
|
|
101663
|
+
}
|
|
101664
|
+
function spanReason(status) {
|
|
101665
|
+
if (status.notForwarded !== void 0) return status.notForwarded;
|
|
101666
|
+
if (status.notEnforced !== void 0) return status.notEnforced;
|
|
101667
|
+
return status.sensors.map(attachmentReason).find((reason) => reason !== null) ?? null;
|
|
101668
|
+
}
|
|
101669
|
+
function sensorRow(sensor) {
|
|
101670
|
+
return {
|
|
101671
|
+
key: `${sensor.addonId}/${sensor.stableId}`,
|
|
101672
|
+
addonId: sensor.addonId,
|
|
101673
|
+
stableId: sensor.stableId,
|
|
101674
|
+
name: sensor.state === "missing" || sensor.state === "unreadable" ? sensor.stableId : sensor.name,
|
|
101675
|
+
mode: sensor.mode,
|
|
101676
|
+
state: sensor.state,
|
|
101677
|
+
reason: attachmentReason(sensor)
|
|
101678
|
+
};
|
|
101679
|
+
}
|
|
101680
|
+
function attachmentReason(sensor) {
|
|
101681
|
+
switch (sensor.state) {
|
|
101682
|
+
case "ready": return null;
|
|
101683
|
+
case "offline":
|
|
101684
|
+
case "missing":
|
|
101685
|
+
case "unsupported":
|
|
101686
|
+
case "unreadable": return sensor.reason;
|
|
101687
|
+
}
|
|
101688
|
+
}
|
|
101689
|
+
function native$1(targetId) {
|
|
101690
|
+
return {
|
|
101691
|
+
text: "Native",
|
|
101692
|
+
status: row(targetId, false, "native", "active", null)
|
|
101693
|
+
};
|
|
101694
|
+
}
|
|
101695
|
+
function held(targetId, text, reason) {
|
|
101696
|
+
return {
|
|
101697
|
+
text,
|
|
101698
|
+
status: row(targetId, false, "native", text === "pending" ? "unavailable" : "stale", reason)
|
|
101699
|
+
};
|
|
101700
|
+
}
|
|
101701
|
+
function row(targetId, configured, source, state, reason) {
|
|
101702
|
+
return {
|
|
101703
|
+
targetId,
|
|
101704
|
+
configured,
|
|
101705
|
+
source,
|
|
101706
|
+
state,
|
|
101707
|
+
reason
|
|
101708
|
+
};
|
|
101709
|
+
}
|
|
101710
|
+
//#endregion
|
|
101711
|
+
//#region src/composition/customize/keyed-array-expr.ts
|
|
101712
|
+
var STEP = /^x == ("(?:\\.|[^"\\])*") \? ("(?:\\.|[^"\\])*"|null) : ([\s\S]+)$/;
|
|
101713
|
+
function enumMapExpr(mapping) {
|
|
101714
|
+
const keys = Object.keys(mapping).toSorted();
|
|
101715
|
+
if (keys.length === 0) return null;
|
|
101716
|
+
return keys.reduceRight((rest, key) => {
|
|
101717
|
+
if (rest === null) return null;
|
|
101718
|
+
const value = mapping[key];
|
|
101719
|
+
if (value === void 0) return null;
|
|
101720
|
+
const rhs = value === null ? "null" : JSON.stringify(value);
|
|
101721
|
+
return `x == ${JSON.stringify(key)} ? ${rhs} : ${rest}`;
|
|
101722
|
+
}, "null");
|
|
101723
|
+
}
|
|
101724
|
+
function parseEnumMap(expr) {
|
|
101725
|
+
const mapping = {};
|
|
101726
|
+
let rest = expr;
|
|
101727
|
+
while (rest !== "null") {
|
|
101728
|
+
const match = STEP.exec(rest);
|
|
101729
|
+
if (match === null || match[1] === void 0 || match[2] === void 0 || match[3] === void 0) return null;
|
|
101730
|
+
const key = jsonString(match[1]);
|
|
101731
|
+
const value = match[2] === "null" ? null : jsonString(match[2]);
|
|
101732
|
+
if (key === null || match[2] !== "null" && value === null) return null;
|
|
101733
|
+
if (Object.prototype.hasOwnProperty.call(mapping, key)) return null;
|
|
101734
|
+
mapping[key] = value;
|
|
101735
|
+
rest = match[3];
|
|
101736
|
+
}
|
|
101737
|
+
return Object.keys(mapping).length === 0 ? null : mapping;
|
|
101738
|
+
}
|
|
101739
|
+
function enumMapDraft(mapping) {
|
|
101740
|
+
return {
|
|
101741
|
+
kind: "enum-map",
|
|
101742
|
+
mapping: { ...mapping }
|
|
101743
|
+
};
|
|
101744
|
+
}
|
|
101745
|
+
function jsonString(token) {
|
|
101746
|
+
try {
|
|
101747
|
+
const parsed = JSON.parse(token);
|
|
101748
|
+
return typeof parsed === "string" ? parsed : null;
|
|
101749
|
+
} catch {
|
|
101750
|
+
return null;
|
|
101751
|
+
}
|
|
101752
|
+
}
|
|
101753
|
+
//#endregion
|
|
101754
|
+
//#region src/composition/customize/keyed-array-compile.ts
|
|
101755
|
+
var catalog$1 = CAP_CUSTOMIZE_CATALOG;
|
|
101756
|
+
function compileKeyedArrayOverride(input) {
|
|
101757
|
+
const target = catalogTarget$1(input.cap, input.targetId);
|
|
101758
|
+
if (target === null || target.cardinality !== "keyedArray") return fail("target");
|
|
101759
|
+
if (input.items.length === 0) return fail("items");
|
|
101760
|
+
if (input.items.some((item) => item.draft.cap !== input.cap || item.draft.targetId !== input.targetId)) return fail("target");
|
|
101761
|
+
const keys = input.items.map((item) => item.draft.key);
|
|
101762
|
+
if (new Set(keys).size !== keys.length) return fail("key");
|
|
101763
|
+
const built = input.items.reduce((acc, item) => {
|
|
101764
|
+
if (!acc.ok) return acc;
|
|
101765
|
+
const entry = compileItem(target, item);
|
|
101766
|
+
if (!entry.ok) return entry;
|
|
101767
|
+
return {
|
|
101768
|
+
ok: true,
|
|
101769
|
+
value: {
|
|
101770
|
+
...acc.value,
|
|
101771
|
+
[item.draft.key]: entry.value
|
|
101772
|
+
}
|
|
101773
|
+
};
|
|
101774
|
+
}, {
|
|
101775
|
+
ok: true,
|
|
101776
|
+
value: {}
|
|
101777
|
+
});
|
|
101778
|
+
if (!built.ok) return built;
|
|
101779
|
+
const fields = compileCompanions(target, input.apply);
|
|
101780
|
+
if (!fields.ok) return fields;
|
|
101781
|
+
return {
|
|
101782
|
+
ok: true,
|
|
101783
|
+
value: {
|
|
101784
|
+
kind: "fields",
|
|
101785
|
+
cap: input.cap,
|
|
101786
|
+
fields: fields.value,
|
|
101787
|
+
items: { ...built.value }
|
|
101788
|
+
}
|
|
101789
|
+
};
|
|
101790
|
+
}
|
|
101791
|
+
/** Put one compiled item into an existing feature. Other items stay as stored. */
|
|
101792
|
+
function mergeKeyedArrayItem(current, compiled, key) {
|
|
101793
|
+
const item = compiled.items?.[key];
|
|
101794
|
+
if (item === void 0) return null;
|
|
101795
|
+
return {
|
|
101796
|
+
kind: "fields",
|
|
101797
|
+
cap: compiled.cap,
|
|
101798
|
+
...current?.enabled === void 0 ? {} : { enabled: current.enabled },
|
|
101799
|
+
fields: current === null ? compiled.fields : current.fields,
|
|
101800
|
+
items: {
|
|
101801
|
+
...current?.items,
|
|
101802
|
+
[key]: item
|
|
101803
|
+
}
|
|
101804
|
+
};
|
|
101805
|
+
}
|
|
101806
|
+
/** The feature without item `key`. Null when that item was the last one. */
|
|
101807
|
+
function withoutKeyedArrayItem(feature, key) {
|
|
101808
|
+
const rest = Object.fromEntries(Object.entries(feature.items ?? {}).filter(([name]) => name !== key));
|
|
101809
|
+
if (Object.keys(rest).length === 0) return null;
|
|
101810
|
+
return {
|
|
101811
|
+
...feature,
|
|
101812
|
+
items: rest
|
|
101813
|
+
};
|
|
101814
|
+
}
|
|
101815
|
+
function fail(reason) {
|
|
101816
|
+
return {
|
|
101817
|
+
ok: false,
|
|
101818
|
+
reason
|
|
101819
|
+
};
|
|
101820
|
+
}
|
|
101821
|
+
function catalogTarget$1(cap, targetId) {
|
|
101822
|
+
const entry = catalog$1[cap];
|
|
101823
|
+
if (entry === void 0) return null;
|
|
101824
|
+
return entry.targets.find((target) => target.id === targetId) ?? null;
|
|
101825
|
+
}
|
|
101826
|
+
function compileItem(target, item) {
|
|
101827
|
+
if (!require_composition.COMPOSITION_ITEM_KEY_RE.test(item.draft.key) || item.draft.label.trim() === "") return fail("key");
|
|
101828
|
+
const field = (target.fields ?? []).find((entry) => entry.path === item.draft.fieldPath);
|
|
101829
|
+
if (field === void 0) return fail("field");
|
|
101830
|
+
const source = sourceSpec(field, item);
|
|
101831
|
+
if (source === null) return fail("source-kind");
|
|
101832
|
+
if (source.requiredUnit !== void 0 && item.sourceUnit !== source.requiredUnit) return fail("unit");
|
|
101833
|
+
const allowed = item.draft.transform.kind;
|
|
101834
|
+
if (!source.transformKinds.includes(allowed)) return fail("transform");
|
|
101835
|
+
const value = compileValue(item, field);
|
|
101836
|
+
if (!value.ok) return value;
|
|
101837
|
+
const fields = compileLiterals(target, field, item, value.value);
|
|
101838
|
+
if (!fields.ok) return fields;
|
|
101839
|
+
return {
|
|
101840
|
+
ok: true,
|
|
101841
|
+
value: {
|
|
101842
|
+
label: item.draft.label.trim(),
|
|
101843
|
+
fields: fields.value
|
|
101844
|
+
}
|
|
101845
|
+
};
|
|
101846
|
+
}
|
|
101847
|
+
function sourceSpec(field, item) {
|
|
101848
|
+
if (item.sourceValueKind === "number") return field.sources.find((source) => source.kind === "numeric") ?? null;
|
|
101849
|
+
if (item.sourceValueKind === "enum" || item.sourceValueKind === "string") return field.sources.find((source) => source.kind === "enum") ?? null;
|
|
101850
|
+
return null;
|
|
101851
|
+
}
|
|
101852
|
+
function compileValue(item, field) {
|
|
101853
|
+
const read = fromRead(refOf(item.draft), item.draft.source.cap, item.draft.source.fieldPath);
|
|
101854
|
+
const transform = item.draft.transform;
|
|
101855
|
+
if (transform.kind === "identity") return {
|
|
101856
|
+
ok: true,
|
|
101857
|
+
value: read
|
|
101858
|
+
};
|
|
101859
|
+
if (transform.kind === "linear") return linearValue(transform, read);
|
|
101860
|
+
if (transform.kind === "enum-map") return enumValue(transform, read, field);
|
|
101861
|
+
return fail("transform");
|
|
101862
|
+
}
|
|
101863
|
+
function linearValue(transform, read) {
|
|
101864
|
+
const scale = signedToken(transform.scale);
|
|
101865
|
+
const offset = signedToken(transform.offset);
|
|
101866
|
+
if (scale === null || offset === null) return fail("scale");
|
|
101867
|
+
const clamps = clampTokens(transform.clampMin, transform.clampMax);
|
|
101868
|
+
if (!clamps.ok) return clamps;
|
|
101869
|
+
return {
|
|
101870
|
+
ok: true,
|
|
101871
|
+
value: expression(linearExpr("x", scale, offset, clamps.value.min, clamps.value.max), { x: read })
|
|
101872
|
+
};
|
|
101873
|
+
}
|
|
101874
|
+
function clampTokens(clampMin, clampMax) {
|
|
101875
|
+
if (clampMin === void 0 && clampMax === void 0) return {
|
|
101876
|
+
ok: true,
|
|
101877
|
+
value: {
|
|
101878
|
+
min: null,
|
|
101879
|
+
max: null
|
|
101880
|
+
}
|
|
101881
|
+
};
|
|
101882
|
+
if (clampMin === void 0 || clampMax === void 0) return fail("clamp");
|
|
101883
|
+
const min = signedToken(clampMin);
|
|
101884
|
+
const max = signedToken(clampMax);
|
|
101885
|
+
if (min === null || max === null || clampMin > clampMax) return fail("clamp");
|
|
101886
|
+
return {
|
|
101887
|
+
ok: true,
|
|
101888
|
+
value: {
|
|
101889
|
+
min,
|
|
101890
|
+
max
|
|
101891
|
+
}
|
|
101892
|
+
};
|
|
101893
|
+
}
|
|
101894
|
+
function enumValue(transform, read, field) {
|
|
101895
|
+
const allowed = new Set(field.enumValues ?? []);
|
|
101896
|
+
const entries = Object.entries(transform.mapping);
|
|
101897
|
+
if (entries.length === 0) return fail("enum");
|
|
101898
|
+
if (entries.some(([key, value]) => key.length === 0 || value !== null && !allowed.has(value))) return fail("enum");
|
|
101899
|
+
const expr = enumMapExpr(transform.mapping);
|
|
101900
|
+
if (expr === null) return fail("enum");
|
|
101901
|
+
return {
|
|
101902
|
+
ok: true,
|
|
101903
|
+
value: expression(expr, { x: read })
|
|
101904
|
+
};
|
|
101905
|
+
}
|
|
101906
|
+
function compileLiterals(target, field, item, value) {
|
|
101907
|
+
const required = new Set((field.literals ?? []).map((literalSpec) => literalSpec.path));
|
|
101908
|
+
const traits = new Map((target.traits ?? []).map((trait) => [trait.path, new Set(trait.values)]));
|
|
101909
|
+
if ([...required].filter((path) => !item.literals.some((literalSpec) => literalSpec.path === path)).length > 0) return fail("literal");
|
|
101910
|
+
return item.literals.reduce((acc, entry) => {
|
|
101911
|
+
if (!acc.ok) return acc;
|
|
101912
|
+
if (entry.path === field.path || acc.value[entry.path] !== void 0) return fail("literal");
|
|
101913
|
+
const allowed = allowedLiteral(field, traits, entry.path);
|
|
101914
|
+
if (allowed === null || !allowed.has(entry.value)) return fail("literal");
|
|
101915
|
+
const expr = constantExpr(entry.value);
|
|
101916
|
+
if (expr === null) return fail("literal");
|
|
101917
|
+
return {
|
|
101918
|
+
ok: true,
|
|
101919
|
+
value: {
|
|
101920
|
+
...acc.value,
|
|
101921
|
+
[entry.path]: literal(expr)
|
|
101922
|
+
}
|
|
101923
|
+
};
|
|
101924
|
+
}, {
|
|
101925
|
+
ok: true,
|
|
101926
|
+
value: { [field.path]: value }
|
|
101927
|
+
});
|
|
101928
|
+
}
|
|
101929
|
+
function allowedLiteral(field, traits, path) {
|
|
101930
|
+
const trait = traits.get(path);
|
|
101931
|
+
if (trait !== void 0) return trait;
|
|
101932
|
+
const required = (field.literals ?? []).find((entry) => entry.path === path);
|
|
101933
|
+
return required === void 0 ? null : new Set(required.values);
|
|
101934
|
+
}
|
|
101935
|
+
function compileCompanions(target, apply) {
|
|
101936
|
+
return (target.companions ?? []).filter((companion) => companionIncluded(companion, apply)).reduce((acc, companion) => {
|
|
101937
|
+
if (!acc.ok) return acc;
|
|
101938
|
+
if (companion.kind !== "clock") return fail("companion");
|
|
101939
|
+
return {
|
|
101940
|
+
ok: true,
|
|
101941
|
+
value: {
|
|
101942
|
+
...acc.value,
|
|
101943
|
+
[companion.path]: literal("now")
|
|
101944
|
+
}
|
|
101945
|
+
};
|
|
101946
|
+
}, {
|
|
101947
|
+
ok: true,
|
|
101948
|
+
value: {}
|
|
101949
|
+
});
|
|
101950
|
+
}
|
|
101951
|
+
function companionIncluded(companion, apply) {
|
|
101952
|
+
if (companion.kind === "transition-time") return false;
|
|
101953
|
+
return companion.when === "always" || apply === "add";
|
|
101954
|
+
}
|
|
101955
|
+
function refOf(draft) {
|
|
101956
|
+
return {
|
|
101957
|
+
addonId: draft.source.addonId,
|
|
101958
|
+
stableId: draft.source.stableId
|
|
101959
|
+
};
|
|
101960
|
+
}
|
|
101961
|
+
//#endregion
|
|
101962
|
+
//#region src/composition/customize/keyed-array-decode.ts
|
|
101963
|
+
var catalog = CAP_CUSTOMIZE_CATALOG;
|
|
101964
|
+
function readKeyedArrayItems(feature, cap, targetId) {
|
|
101965
|
+
const target = catalogTarget(cap, targetId);
|
|
101966
|
+
if (target === null || target.cardinality !== "keyedArray" || feature.cap !== cap) return null;
|
|
101967
|
+
const apply = inferApply(target, feature.fields);
|
|
101968
|
+
const canonical = apply !== null && companionsMatch(target, feature.fields, apply);
|
|
101969
|
+
const items = Object.entries(feature.items ?? {}).map(([key, item]) => viewOf(target, cap, targetId, key, item, canonical));
|
|
101970
|
+
return {
|
|
101971
|
+
canonical,
|
|
101972
|
+
apply: apply ?? "add",
|
|
101973
|
+
items
|
|
101974
|
+
};
|
|
101975
|
+
}
|
|
101976
|
+
function decodeKeyedArrayOverride(input) {
|
|
101977
|
+
const read = readKeyedArrayItems(input.feature, input.cap, input.targetId);
|
|
101978
|
+
if (read === null || !read.canonical) return null;
|
|
101979
|
+
if (read.items.some((item) => item.compile === null)) return null;
|
|
101980
|
+
const compiles = read.items.flatMap((item) => item.compile === null ? [] : [item.compile]);
|
|
101981
|
+
const compiled = compileKeyedArrayOverride({
|
|
101982
|
+
cap: input.cap,
|
|
101983
|
+
targetId: input.targetId,
|
|
101984
|
+
device: input.device,
|
|
101985
|
+
apply: read.apply,
|
|
101986
|
+
items: compiles
|
|
101987
|
+
});
|
|
101988
|
+
if (!compiled.ok) return null;
|
|
101989
|
+
return sameFeature(compiled.value, input.feature) ? read : null;
|
|
101990
|
+
}
|
|
101991
|
+
function viewOf(target, cap, targetId, key, item, canonical) {
|
|
101992
|
+
const blank = {
|
|
101993
|
+
key,
|
|
101994
|
+
label: item.label,
|
|
101995
|
+
recognized: false,
|
|
101996
|
+
compile: null
|
|
101997
|
+
};
|
|
101998
|
+
if (!canonical) return blank;
|
|
101999
|
+
const compile = compileOf(target, cap, targetId, key, item);
|
|
102000
|
+
if (compile === null) return blank;
|
|
102001
|
+
return {
|
|
102002
|
+
key,
|
|
102003
|
+
label: item.label,
|
|
102004
|
+
recognized: true,
|
|
102005
|
+
compile
|
|
102006
|
+
};
|
|
102007
|
+
}
|
|
102008
|
+
function compileOf(target, cap, targetId, key, item) {
|
|
102009
|
+
const assigned = assignedField(target, item);
|
|
102010
|
+
if (assigned === null) return null;
|
|
102011
|
+
const literals = literalFields(target, assigned.field, item, assigned.path);
|
|
102012
|
+
if (literals === null) return null;
|
|
102013
|
+
const draft = draftOf(cap, targetId, key, item.label, assigned);
|
|
102014
|
+
if (draft === null) return null;
|
|
102015
|
+
const compile = {
|
|
102016
|
+
draft,
|
|
102017
|
+
sourceValueKind: assigned.sourceValueKind,
|
|
102018
|
+
sourceUnit: null,
|
|
102019
|
+
literals
|
|
102020
|
+
};
|
|
102021
|
+
return reproduces(cap, targetId, key, compile, item) ? compile : null;
|
|
102022
|
+
}
|
|
102023
|
+
function assignedField(target, item) {
|
|
102024
|
+
const paths = Object.keys(item.fields).filter((path) => !isConstant(item.fields[path]));
|
|
102025
|
+
if (paths.length !== 1) return null;
|
|
102026
|
+
const path = paths[0];
|
|
102027
|
+
if (path === void 0) return null;
|
|
102028
|
+
const field = (target.fields ?? []).find((entry) => entry.path === path);
|
|
102029
|
+
const source = item.fields[path];
|
|
102030
|
+
if (field === void 0 || source === void 0) return null;
|
|
102031
|
+
const read = readTransform(source, field);
|
|
102032
|
+
if (read === null) return null;
|
|
102033
|
+
return {
|
|
102034
|
+
path,
|
|
102035
|
+
field,
|
|
102036
|
+
source,
|
|
102037
|
+
...read
|
|
102038
|
+
};
|
|
102039
|
+
}
|
|
102040
|
+
function readTransform(source, field) {
|
|
102041
|
+
if (source.kind === "from") return field.valueKind === "enum" ? {
|
|
102042
|
+
sourceValueKind: "enum",
|
|
102043
|
+
transform: { kind: "identity" }
|
|
102044
|
+
} : {
|
|
102045
|
+
sourceValueKind: "number",
|
|
102046
|
+
transform: { kind: "identity" }
|
|
102047
|
+
};
|
|
102048
|
+
if (source.kind !== "expression") return null;
|
|
102049
|
+
const mapped = parseEnumMap(source.expr);
|
|
102050
|
+
if (mapped !== null && field.valueKind === "enum") return {
|
|
102051
|
+
sourceValueKind: "enum",
|
|
102052
|
+
transform: enumMapDraft(mapped)
|
|
102053
|
+
};
|
|
102054
|
+
const linear = parseLinear(source.expr);
|
|
102055
|
+
if (linear === null || linear.inner !== "x" || field.valueKind !== "number") return null;
|
|
102056
|
+
return {
|
|
102057
|
+
sourceValueKind: "number",
|
|
102058
|
+
transform: {
|
|
102059
|
+
kind: "linear",
|
|
102060
|
+
scale: linear.scale,
|
|
102061
|
+
offset: linear.offset,
|
|
102062
|
+
...linear.clampMin === void 0 || linear.clampMax === void 0 ? {} : {
|
|
102063
|
+
clampMin: linear.clampMin,
|
|
102064
|
+
clampMax: linear.clampMax
|
|
102065
|
+
}
|
|
102066
|
+
}
|
|
102067
|
+
};
|
|
102068
|
+
}
|
|
102069
|
+
function literalFields(target, field, item, assignedPath) {
|
|
102070
|
+
const required = new Set((field.literals ?? []).map((entry) => entry.path));
|
|
102071
|
+
const traits = new Set((target.traits ?? []).map((trait) => trait.path));
|
|
102072
|
+
const found = Object.keys(item.fields).filter((path) => path !== assignedPath);
|
|
102073
|
+
if (found.some((path) => !required.has(path) && !traits.has(path))) return null;
|
|
102074
|
+
if ([...required].some((path) => !found.includes(path))) return null;
|
|
102075
|
+
const literals = found.map((path) => literalValue(item.fields[path], path));
|
|
102076
|
+
if (literals.some((entry) => entry === null)) return null;
|
|
102077
|
+
return literals.flatMap((entry) => entry === null ? [] : [entry]);
|
|
102078
|
+
}
|
|
102079
|
+
function literalValue(source, path) {
|
|
102080
|
+
if (source?.kind !== "expression" || Object.keys(source.bindings).length !== 0) return null;
|
|
102081
|
+
if (!(source.expr.startsWith("\"") && source.expr.endsWith("\""))) return null;
|
|
102082
|
+
try {
|
|
102083
|
+
const parsed = JSON.parse(source.expr);
|
|
102084
|
+
return typeof parsed === "string" ? {
|
|
102085
|
+
path,
|
|
102086
|
+
value: parsed
|
|
102087
|
+
} : null;
|
|
102088
|
+
} catch {
|
|
102089
|
+
return null;
|
|
102090
|
+
}
|
|
102091
|
+
}
|
|
102092
|
+
function draftOf(cap, targetId, key, label, assigned) {
|
|
102093
|
+
const bound = singleFrom(assigned.source);
|
|
102094
|
+
if (bound === null) return null;
|
|
102095
|
+
return {
|
|
102096
|
+
kind: "keyedArray",
|
|
102097
|
+
cap,
|
|
102098
|
+
targetId,
|
|
102099
|
+
key,
|
|
102100
|
+
label,
|
|
102101
|
+
fieldPath: assigned.path,
|
|
102102
|
+
source: {
|
|
102103
|
+
addonId: bound.addonId,
|
|
102104
|
+
stableId: bound.stableId,
|
|
102105
|
+
cap: bound.cap,
|
|
102106
|
+
fieldPath: bound.fieldPath
|
|
102107
|
+
},
|
|
102108
|
+
transform: assigned.transform
|
|
102109
|
+
};
|
|
102110
|
+
}
|
|
102111
|
+
function reproduces(cap, targetId, key, compile, item) {
|
|
102112
|
+
const compiled = compileKeyedArrayOverride({
|
|
102113
|
+
cap,
|
|
102114
|
+
targetId,
|
|
102115
|
+
device: {
|
|
102116
|
+
addonId: "t",
|
|
102117
|
+
stableId: "t"
|
|
102118
|
+
},
|
|
102119
|
+
apply: "add",
|
|
102120
|
+
items: [compile]
|
|
102121
|
+
});
|
|
102122
|
+
if (!compiled.ok) return false;
|
|
102123
|
+
const written = compiled.value.items?.[key];
|
|
102124
|
+
if (written === void 0) return false;
|
|
102125
|
+
return JSON.stringify(written) === JSON.stringify(item);
|
|
102126
|
+
}
|
|
102127
|
+
function isConstant(source) {
|
|
102128
|
+
return source?.kind === "expression" && Object.keys(source.bindings).length === 0;
|
|
102129
|
+
}
|
|
102130
|
+
function inferApply(target, fields) {
|
|
102131
|
+
const addPaths = (target.companions ?? []).flatMap((companion) => companion.kind !== "transition-time" && companion.when === "add" ? [companion.path] : []);
|
|
102132
|
+
if (addPaths.length === 0) return "replace";
|
|
102133
|
+
const present = addPaths.filter((path) => fields[path] !== void 0);
|
|
102134
|
+
if (present.length === addPaths.length) return "add";
|
|
102135
|
+
if (present.length === 0) return "replace";
|
|
102136
|
+
return null;
|
|
102137
|
+
}
|
|
102138
|
+
function companionsMatch(target, fields, apply) {
|
|
102139
|
+
const expected = (target.companions ?? []).flatMap((companion) => {
|
|
102140
|
+
if (companion.kind === "transition-time") return [];
|
|
102141
|
+
if (companion.when === "always" || apply === "add") return [companion.path];
|
|
102142
|
+
return [];
|
|
102143
|
+
});
|
|
102144
|
+
if (Object.keys(fields).toSorted().join(",") !== [...expected].toSorted().join(",")) return false;
|
|
102145
|
+
return expected.every((path) => isLiteral(fields[path], "now"));
|
|
102146
|
+
}
|
|
102147
|
+
function catalogTarget(cap, targetId) {
|
|
102148
|
+
const entry = catalog[cap];
|
|
102149
|
+
if (entry === void 0) return null;
|
|
102150
|
+
return entry.targets.find((target) => target.id === targetId) ?? null;
|
|
102151
|
+
}
|
|
102152
|
+
function sameFeature(compiled, stored) {
|
|
102153
|
+
return sameStored(wrap(stripEnabled(compiled)), wrap(stripEnabled(stored)));
|
|
102154
|
+
}
|
|
102155
|
+
function stripEnabled(feature) {
|
|
102156
|
+
const { enabled: _enabled, ...rest } = feature;
|
|
102157
|
+
return rest;
|
|
102158
|
+
}
|
|
102159
|
+
function wrap(feature) {
|
|
102160
|
+
return {
|
|
102161
|
+
family: "composition",
|
|
102162
|
+
target: {
|
|
102163
|
+
addonId: "t",
|
|
102164
|
+
stableId: "t"
|
|
102165
|
+
},
|
|
102166
|
+
feature
|
|
102167
|
+
};
|
|
102168
|
+
}
|
|
102169
|
+
//#endregion
|
|
102170
|
+
//#region src/composition/customize/keyed-array-status.ts
|
|
102171
|
+
function projectKeyedArrayAssignment(input) {
|
|
102172
|
+
if (input.stored.kind === "pending") return unanswered(input.targetId, "pending", null);
|
|
102173
|
+
if (input.stored.kind === "unknown") return unanswered(input.targetId, "unknown", input.stored.reason ?? "unknown");
|
|
102174
|
+
if (input.stored.value === null) return native(input.targetId);
|
|
102175
|
+
const read = readKeyedArrayItems(input.stored.value, input.cap, input.targetId);
|
|
102176
|
+
const count = read?.items.filter((item) => item.recognized).length ?? 0;
|
|
102177
|
+
if (read === null || !read.canonical || count === 0) return {
|
|
102178
|
+
text: "unknown",
|
|
102179
|
+
assignedCount: 0,
|
|
102180
|
+
status: status(input.targetId, true, "assigned", "unavailable", "not-canonical")
|
|
102181
|
+
};
|
|
102182
|
+
return projectDecoded(input, count);
|
|
102183
|
+
}
|
|
102184
|
+
function projectDecoded(input, count) {
|
|
102185
|
+
const text = `${count} assigned`;
|
|
102186
|
+
if (input.sourcePresence === "pending") return {
|
|
102187
|
+
text: "pending",
|
|
102188
|
+
assignedCount: count,
|
|
102189
|
+
status: status(input.targetId, true, "assigned", "stale", null)
|
|
102190
|
+
};
|
|
102191
|
+
if (input.sourcePresence === "unknown") return {
|
|
102192
|
+
text: "unknown",
|
|
102193
|
+
assignedCount: count,
|
|
102194
|
+
status: status(input.targetId, true, "assigned", "stale", input.sourceUnknownReason ?? "unknown")
|
|
102195
|
+
};
|
|
102196
|
+
if (input.sourcePresence === "absent") return {
|
|
102197
|
+
text,
|
|
102198
|
+
assignedCount: count,
|
|
102199
|
+
status: status(input.targetId, true, "assigned", "unavailable", "source-missing")
|
|
102200
|
+
};
|
|
102201
|
+
return {
|
|
102202
|
+
text,
|
|
102203
|
+
assignedCount: count,
|
|
102204
|
+
status: status(input.targetId, true, "assigned", "active", null)
|
|
102205
|
+
};
|
|
102206
|
+
}
|
|
102207
|
+
function native(targetId) {
|
|
102208
|
+
return {
|
|
102209
|
+
text: "Native",
|
|
102210
|
+
assignedCount: 0,
|
|
102211
|
+
status: status(targetId, false, "native", "active", null)
|
|
102212
|
+
};
|
|
102213
|
+
}
|
|
102214
|
+
function unanswered(targetId, text, reason) {
|
|
102215
|
+
return {
|
|
102216
|
+
text,
|
|
102217
|
+
assignedCount: 0,
|
|
102218
|
+
status: status(targetId, false, "native", text === "pending" ? "unavailable" : "stale", reason)
|
|
102219
|
+
};
|
|
102220
|
+
}
|
|
102221
|
+
function status(targetId, configured, source, state, reason) {
|
|
102222
|
+
return {
|
|
102223
|
+
targetId,
|
|
102224
|
+
configured,
|
|
102225
|
+
source,
|
|
102226
|
+
state,
|
|
102227
|
+
reason
|
|
102228
|
+
};
|
|
102229
|
+
}
|
|
102230
|
+
//#endregion
|
|
100294
102231
|
//#region src/generated/scope-presets.ts
|
|
100295
102232
|
var SCOPE_PRESETS = [
|
|
100296
102233
|
{
|
|
@@ -111026,6 +112963,7 @@ exports.CAMSTACK_EVENT_PREFIX = CAMSTACK_EVENT_PREFIX;
|
|
|
111026
112963
|
exports.CAM_PROFILE_ORDER = require_sleep.CAM_PROFILE_ORDER;
|
|
111027
112964
|
exports.CAPABILITY_NAMES = CAPABILITY_NAMES;
|
|
111028
112965
|
exports.CAPABILITY_ROUTER_KEYS = CAPABILITY_ROUTER_KEYS;
|
|
112966
|
+
exports.CAP_CUSTOMIZE_CATALOG = CAP_CUSTOMIZE_CATALOG;
|
|
111029
112967
|
exports.CAP_NAMES_WITH_STATUS = CAP_NAMES_WITH_STATUS;
|
|
111030
112968
|
exports.CAP_NODE_PIN_CONTEXT_KEY = require_sleep.CAP_NODE_PIN_CONTEXT_KEY;
|
|
111031
112969
|
exports.CAP_PROVIDER_KIND_MAP = CAP_PROVIDER_KIND_MAP;
|
|
@@ -111254,6 +113192,7 @@ exports.CredentialScopeSchema = CredentialScopeSchema;
|
|
|
111254
113192
|
exports.CredentialTokenClaimsSchema = CredentialTokenClaimsSchema;
|
|
111255
113193
|
exports.CustomActionInputSchema = CustomActionInputSchema;
|
|
111256
113194
|
exports.CustomModelDescriptorSchema = CustomModelDescriptorSchema;
|
|
113195
|
+
exports.CustomizeAssignmentStatusSchema = CustomizeAssignmentStatusSchema;
|
|
111257
113196
|
exports.DATABASE_SNAPSHOT_PARTIAL_SUFFIX = DATABASE_SNAPSHOT_PARTIAL_SUFFIX;
|
|
111258
113197
|
exports.DATABASE_SNAPSHOT_SUFFIX = DATABASE_SNAPSHOT_SUFFIX;
|
|
111259
113198
|
exports.DATABASE_SNAPSHOT_TIMEOUT_MS = DATABASE_SNAPSHOT_TIMEOUT_MS;
|
|
@@ -111595,6 +113534,8 @@ exports.ICON_ENTRIES = ICON_ENTRIES;
|
|
|
111595
113534
|
exports.ICON_KEYS = ICON_KEYS;
|
|
111596
113535
|
exports.ICON_VIEWER_MODULES = ICON_VIEWER_MODULES;
|
|
111597
113536
|
exports.INFERENCE_DEVICE_EXCLUSION_REASONS = INFERENCE_DEVICE_EXCLUSION_REASONS;
|
|
113537
|
+
exports.INITIAL_PULSE = INITIAL_PULSE;
|
|
113538
|
+
exports.INITIAL_SPAN = INITIAL_SPAN;
|
|
111598
113539
|
exports.INVERTIBLE_CAPS = INVERTIBLE_CAPS;
|
|
111599
113540
|
exports.IconKeySchema = IconKeySchema;
|
|
111600
113541
|
exports.ImageContractSchema = ImageContractSchema;
|
|
@@ -111776,6 +113717,7 @@ exports.MOTION_CROP_MAX_REGIONS = MOTION_CROP_MAX_REGIONS;
|
|
|
111776
113717
|
exports.MOTION_CROP_MOTION_PAD = MOTION_CROP_MOTION_PAD;
|
|
111777
113718
|
exports.MOTION_CROP_TRACKED_PAD = MOTION_CROP_TRACKED_PAD;
|
|
111778
113719
|
exports.MOTION_SOURCE_LABELS = MOTION_SOURCE_LABELS;
|
|
113720
|
+
exports.MOTION_SPAN_TIMEOUT_MS = MOTION_SPAN_TIMEOUT_MS;
|
|
111779
113721
|
exports.MOTION_TRIGGER_FEATURE = MOTION_TRIGGER_FEATURE;
|
|
111780
113722
|
exports.ManagedModelCatalogEntrySchema = ManagedModelCatalogEntrySchema;
|
|
111781
113723
|
exports.ManagedModelExtraFileSchema = ManagedModelExtraFileSchema;
|
|
@@ -112151,6 +114093,7 @@ exports.OsdTemplateBindingSchema = OsdTemplateBindingSchema;
|
|
|
112151
114093
|
exports.OsdTemplateFormatSchema = OsdTemplateFormatSchema;
|
|
112152
114094
|
exports.OsdTemplatePickSchema = OsdTemplatePickSchema;
|
|
112153
114095
|
exports.OsdTemplateTokenKindSchema = OsdTemplateTokenKindSchema;
|
|
114096
|
+
exports.OverrideDraftSchema = OverrideDraftSchema;
|
|
112154
114097
|
exports.PEER_BYTES_CHUNK_BYTES = require_sleep.PEER_BYTES_CHUNK_BYTES;
|
|
112155
114098
|
exports.PEER_BYTES_MAX_OUTSTANDING = require_sleep.PEER_BYTES_MAX_OUTSTANDING;
|
|
112156
114099
|
exports.PEER_BYTES_STALL_MS = require_sleep.PEER_BYTES_STALL_MS;
|
|
@@ -112314,6 +114257,7 @@ exports.ROOT_SUPPLIABLE_STEP_IDS = ROOT_SUPPLIABLE_STEP_IDS;
|
|
|
112314
114257
|
exports.RUNNING_POWER_START_DELAY_MS = RUNNING_POWER_START_DELAY_MS;
|
|
112315
114258
|
exports.RUNNING_POWER_STOP_DELAY_MS = RUNNING_POWER_STOP_DELAY_MS;
|
|
112316
114259
|
exports.RUNNING_POWER_THRESHOLD_WATTS = RUNNING_POWER_THRESHOLD_WATTS;
|
|
114260
|
+
exports.RUNNING_STATE_COLD = RUNNING_STATE_COLD;
|
|
112317
114261
|
exports.RUNTIME_DEFAULTS = require_sleep.RUNTIME_DEFAULTS;
|
|
112318
114262
|
exports.RUNTIME_STATE_POLICY = RUNTIME_STATE_POLICY;
|
|
112319
114263
|
exports.RUNTIME_STATE_REFRESH_MISS_COOLDOWN_MS = RUNTIME_STATE_REFRESH_MISS_COOLDOWN_MS;
|
|
@@ -112906,7 +114850,6 @@ exports.buildCapabilityLookup = buildCapabilityLookup;
|
|
|
112906
114850
|
exports.buildDeviceAdminUrl = buildDeviceAdminUrl;
|
|
112907
114851
|
exports.buildDeviceEnrollmentLink = buildDeviceEnrollmentLink;
|
|
112908
114852
|
exports.buildDeviceSignatureMessage = buildDeviceSignatureMessage;
|
|
112909
|
-
exports.buildDoorbellCompositionFeature = buildDoorbellCompositionFeature;
|
|
112910
114853
|
exports.buildEventKindDescriptor = buildEventKindDescriptor;
|
|
112911
114854
|
exports.buildFfmpegArgs = require_composition.buildFfmpegArgs;
|
|
112912
114855
|
exports.buildFrigateClassMap = buildFrigateClassMap;
|
|
@@ -112980,6 +114923,10 @@ exports.commitWatchdogRestart = commitWatchdogRestart;
|
|
|
112980
114923
|
exports.compareToTarget = compareToTarget;
|
|
112981
114924
|
exports.compileExpression = require_composition.compileExpression;
|
|
112982
114925
|
exports.compileExpressionSafe = require_composition.compileExpressionSafe;
|
|
114926
|
+
exports.compileKeyedArrayOverride = compileKeyedArrayOverride;
|
|
114927
|
+
exports.compilePulseOverride = compilePulseOverride;
|
|
114928
|
+
exports.compileScalarOverride = compileScalarOverride;
|
|
114929
|
+
exports.compileSpanOverride = compileSpanOverride;
|
|
112983
114930
|
exports.composeSwitchedOff = composeSwitchedOff;
|
|
112984
114931
|
exports.composedDeviceRef = require_composition.composedDeviceRef;
|
|
112985
114932
|
exports.composedDeviceStableId = require_composition.composedDeviceStableId;
|
|
@@ -113044,6 +114991,9 @@ exports.dayOfWeekToIndex = dayOfWeekToIndex;
|
|
|
113044
114991
|
exports.declarationOwnerNodeId = declarationOwnerNodeId;
|
|
113045
114992
|
exports.declarationsOf = require_sleep.declarationsOf;
|
|
113046
114993
|
exports.declareLogChannel = declareLogChannel;
|
|
114994
|
+
exports.decodeKeyedArrayOverride = decodeKeyedArrayOverride;
|
|
114995
|
+
exports.decodePulseOverride = decodePulseOverride;
|
|
114996
|
+
exports.decodeScalarOverride = decodeScalarOverride;
|
|
113047
114997
|
exports.decodeVectorBase64 = decodeVectorBase64;
|
|
113048
114998
|
exports.decoderCapability = decoderCapability;
|
|
113049
114999
|
exports.defaultDeliveryForSection = defaultDeliveryForSection;
|
|
@@ -113102,7 +115052,6 @@ exports.dishwasherCapability = dishwasherCapability;
|
|
|
113102
115052
|
exports.doActionSelectValue = doActionSelectValue;
|
|
113103
115053
|
exports.dominantClipLabels = dominantClipLabels;
|
|
113104
115054
|
exports.doorbellCapability = doorbellCapability;
|
|
113105
|
-
exports.doorbellFeatureSources = doorbellFeatureSources;
|
|
113106
115055
|
exports.droppedConditionsForKind = droppedConditionsForKind;
|
|
113107
115056
|
exports.edgetpuDelegateDevice = edgetpuDelegateDevice;
|
|
113108
115057
|
exports.effectiveStepSettings = effectiveStepSettings;
|
|
@@ -113280,7 +115229,6 @@ exports.isRemovedModelId = isRemovedModelId;
|
|
|
113280
115229
|
exports.isRestoredCap = isRestoredCap;
|
|
113281
115230
|
exports.isRetiredClearKey = isRetiredClearKey;
|
|
113282
115231
|
exports.isRootSuppliableStepId = isRootSuppliableStepId;
|
|
113283
|
-
exports.isRunningAssignmentFeature = isRunningAssignmentFeature;
|
|
113284
115232
|
exports.isSameAddonId = isSameAddonId;
|
|
113285
115233
|
exports.isScheduleActive = isScheduleActive;
|
|
113286
115234
|
exports.isSecretClear = require_sleep.isSecretClear;
|
|
@@ -113355,6 +115303,7 @@ exports.measuredDetectorCells = measuredDetectorCells;
|
|
|
113355
115303
|
exports.mediaPlayerCapability = mediaPlayerCapability;
|
|
113356
115304
|
exports.memoizePinnedFfmpeg = memoizePinnedFfmpeg;
|
|
113357
115305
|
exports.mergeClipLabels = mergeClipLabels;
|
|
115306
|
+
exports.mergeKeyedArrayItem = mergeKeyedArrayItem;
|
|
113358
115307
|
exports.mergeSecretStatePaths = require_sleep.mergeSecretStatePaths;
|
|
113359
115308
|
exports.mergeSettingsBags = mergeSettingsBags;
|
|
113360
115309
|
exports.mergeSourceInfo = mergeSourceInfo;
|
|
@@ -113481,6 +115430,10 @@ exports.pressureSensorCapability = pressureSensorCapability;
|
|
|
113481
115430
|
exports.principalMayReachAddon = principalMayReachAddon;
|
|
113482
115431
|
exports.privacyMaskCapability = privacyMaskCapability;
|
|
113483
115432
|
exports.procedureAuthKey = procedureAuthKey;
|
|
115433
|
+
exports.projectKeyedArrayAssignment = projectKeyedArrayAssignment;
|
|
115434
|
+
exports.projectPulseAssignment = projectPulseAssignment;
|
|
115435
|
+
exports.projectScalarAssignment = projectScalarAssignment;
|
|
115436
|
+
exports.projectSpanAssignment = projectSpanAssignment;
|
|
113484
115437
|
exports.projectSubjectPath = projectSubjectPath;
|
|
113485
115438
|
exports.providerMotionEvent = providerMotionEvent;
|
|
113486
115439
|
exports.ptzAutotrackCapability = ptzAutotrackCapability;
|
|
@@ -113496,6 +115449,7 @@ exports.readErrorI18n = require_sleep.readErrorI18n;
|
|
|
113496
115449
|
exports.readFaceRescoreIntervalMinutes = readFaceRescoreIntervalMinutes;
|
|
113497
115450
|
exports.readHubMotionDetected = readHubMotionDetected;
|
|
113498
115451
|
exports.readHubMotionStatus = readHubMotionStatus;
|
|
115452
|
+
exports.readKeyedArrayItems = readKeyedArrayItems;
|
|
113499
115453
|
exports.readMotionTriggeredBy = readMotionTriggeredBy;
|
|
113500
115454
|
exports.readNativeLeaseOverride = readNativeLeaseOverride;
|
|
113501
115455
|
exports.readNodePin = require_sleep.readNodePin;
|
|
@@ -113598,8 +115552,6 @@ exports.ruleSectionOf = ruleSectionOf;
|
|
|
113598
115552
|
exports.ruleSeedForSection = ruleSeedForSection;
|
|
113599
115553
|
exports.ruleTriggerZoneIds = ruleTriggerZoneIds;
|
|
113600
115554
|
exports.runInferenceStep = runInferenceStep;
|
|
113601
|
-
exports.runningAssignmentFeature = runningAssignmentFeature;
|
|
113602
|
-
exports.runningAssignmentRecovered = runningAssignmentRecovered;
|
|
113603
115555
|
exports.runningFromDishwasherOperation = runningFromDishwasherOperation;
|
|
113604
115556
|
exports.runningFromLawnMower = runningFromLawnMower;
|
|
113605
115557
|
exports.runningFromMediaPlayer = runningFromMediaPlayer;
|
|
@@ -113662,7 +115614,9 @@ exports.startReachabilityPoll = startReachabilityPoll;
|
|
|
113662
115614
|
exports.stateLabel = stateLabel;
|
|
113663
115615
|
exports.stateVocabularyFor = stateVocabularyFor;
|
|
113664
115616
|
exports.stepModelRunsOnFormat = stepModelRunsOnFormat;
|
|
115617
|
+
exports.stepPulse = stepPulse;
|
|
113665
115618
|
exports.stepSettingSource = stepSettingSource;
|
|
115619
|
+
exports.stepSpan = stepSpan;
|
|
113666
115620
|
exports.storageAdminCapability = storageAdminCapability;
|
|
113667
115621
|
exports.storageCapability = storageCapability;
|
|
113668
115622
|
exports.storageEvictableCapability = storageEvictableCapability;
|
|
@@ -113780,6 +115734,7 @@ exports.withLocationMode = withLocationMode;
|
|
|
113780
115734
|
exports.withSystemEventClasses = withSystemEventClasses;
|
|
113781
115735
|
exports.withoutCallerStamp = require_sleep.withoutCallerStamp;
|
|
113782
115736
|
exports.withoutField = withoutField;
|
|
115737
|
+
exports.withoutKeyedArrayItem = withoutKeyedArrayItem;
|
|
113783
115738
|
exports.writeModelBoundSetting = writeModelBoundSetting;
|
|
113784
115739
|
exports.zodEntriesToConfigUI = zodEntriesToConfigUI;
|
|
113785
115740
|
exports.zoneAnalyticsCapability = zoneAnalyticsCapability;
|