@camstack/types 1.2.266 → 1.2.268
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/addon.js +4 -4
- package/dist/addon.mjs +3 -3
- package/dist/capabilities/battery.cap.d.ts +17 -2
- package/dist/capabilities/capability-definition.d.ts +22 -0
- package/dist/capabilities/composer.cap.d.ts +99 -0
- package/dist/capabilities/consumables.cap.d.ts +79 -0
- package/dist/capabilities/core-blocks.cap.d.ts +1149 -91
- package/dist/capabilities/device-extension.cap.d.ts +12 -13
- package/dist/capabilities/device-state.cap.d.ts +186 -2
- package/dist/capabilities/index.d.ts +3 -3
- package/dist/capabilities/pipeline-analytics.cap.d.ts +14 -0
- package/dist/composition/composition-graph.d.ts +42 -9
- package/dist/composition/composition-items.d.ts +25 -0
- package/dist/composition/composition-report.d.ts +93 -2
- package/dist/composition/composition.d.ts +154 -3
- package/dist/composition/customization-name.d.ts +6 -0
- package/dist/composition/evaluate-field.d.ts +12 -0
- package/dist/composition/examples.d.ts +33 -0
- package/dist/composition/field-kinds.d.ts +42 -0
- package/dist/composition/index.d.ts +1 -0
- package/dist/composition/plan-result.d.ts +16 -0
- package/dist/composition/state-fields.d.ts +6 -0
- package/dist/composition/validate-composition.d.ts +44 -9
- package/dist/composition-CPFIlFfw.mjs +1759 -0
- package/dist/composition-QlOB7QTG.js +2184 -0
- package/dist/device/device-context.d.ts +9 -0
- package/dist/device/device-runtime-state.d.ts +15 -1
- package/dist/device/index.d.ts +1 -1
- package/dist/device-extension/slot-descriptor.d.ts +8 -11
- package/dist/device-extension/slot-provider.d.ts +0 -2
- package/dist/enums/event-category.d.ts +25 -0
- package/dist/enums.js +1 -1
- package/dist/enums.mjs +1 -1
- package/dist/err-msg-DX6i_MY4.mjs +339 -0
- package/dist/err-msg-Dx2Kor0g.js +368 -0
- package/dist/{event-category-BVDXG4tB.mjs → event-category-C5xZWqz6.mjs} +31 -1
- package/dist/{event-category-BVfsrBYA.js → event-category-MbnB-6AN.js} +48 -0
- package/dist/generated/addon-api.d.ts +42 -0
- package/dist/generated/device-proxy.d.ts +1 -1
- package/dist/generated/method-access-map.d.ts +1 -1
- package/dist/generated/method-device-selectors.d.ts +2 -2
- package/dist/generated/system-proxy.d.ts +2 -2
- package/dist/index.d.ts +4 -3
- package/dist/index.js +1548 -1660
- package/dist/index.mjs +1243 -1388
- package/dist/interfaces/kernel-abstractions.d.ts +16 -0
- package/dist/interfaces/status-overlay.d.ts +42 -0
- package/dist/node.d.ts +1 -0
- package/dist/node.js +29 -8
- package/dist/node.mjs +23 -3
- package/dist/{sleep-8K9gue-H.js → sleep-BSzia-xT.js} +6 -352
- package/dist/{sleep-DC-wdyeS.mjs → sleep-jkRQgtSc.mjs} +7 -329
- package/package.json +1 -1
- package/dist/canonical-hash-CPK2Dy60.mjs +0 -715
- package/dist/canonical-hash-CSE4ioRi.js +0 -792
- package/dist/err-msg-COpsHMw2.js +0 -18
- package/dist/err-msg-IQTHeDzc.mjs +0 -13
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_sleep = require("./sleep-
|
|
3
|
-
const require_event_category = require("./event-category-
|
|
4
|
-
const
|
|
2
|
+
const require_sleep = require("./sleep-BSzia-xT.js");
|
|
3
|
+
const require_event_category = require("./event-category-MbnB-6AN.js");
|
|
4
|
+
const require_composition = require("./composition-QlOB7QTG.js");
|
|
5
|
+
const require_err_msg = require("./err-msg-Dx2Kor0g.js");
|
|
5
6
|
const require_enums = require("./enums.js");
|
|
6
|
-
const require_err_msg = require("./err-msg-COpsHMw2.js");
|
|
7
7
|
let zod = require("zod");
|
|
8
8
|
//#region src/media/media-owner-key.ts
|
|
9
9
|
/**
|
|
@@ -741,7 +741,7 @@ function canonicalEgressPlan(request, delivery = egressTransportFromRequest(requ
|
|
|
741
741
|
* every other consumer to 360p.
|
|
742
742
|
*/
|
|
743
743
|
function egressTranscodeSharingKey(request, delivery = egressTransportFromRequest(request)) {
|
|
744
|
-
return `egress:${
|
|
744
|
+
return `egress:${require_composition.canonicalHash(canonicalEgressPlan(request, delivery))}`;
|
|
745
745
|
}
|
|
746
746
|
//#endregion
|
|
747
747
|
//#region src/health/wiring-health.ts
|
|
@@ -5531,809 +5531,6 @@ function principalMayReachAddon(input) {
|
|
|
5531
5531
|
};
|
|
5532
5532
|
}
|
|
5533
5533
|
//#endregion
|
|
5534
|
-
//#region src/expression/errors.ts
|
|
5535
|
-
/**
|
|
5536
|
-
* Error types for the safe expression engine. Two distinct classes so callers
|
|
5537
|
-
* can tell a compile-time (grammar) failure from a runtime (evaluation)
|
|
5538
|
-
* failure — both are non-fatal to the host: read paths degrade to "skip link".
|
|
5539
|
-
*/
|
|
5540
|
-
/** Thrown by the tokenizer / parser. Carries a 0-based source `position` when
|
|
5541
|
-
* the failure is anchored to a character (author-facing inline feedback). */
|
|
5542
|
-
var ExpressionParseError = class extends Error {
|
|
5543
|
-
position;
|
|
5544
|
-
constructor(message, position) {
|
|
5545
|
-
super(message);
|
|
5546
|
-
this.name = "ExpressionParseError";
|
|
5547
|
-
this.position = position;
|
|
5548
|
-
}
|
|
5549
|
-
};
|
|
5550
|
-
/** Thrown by the evaluator (unknown identifier, type mismatch, non-finite
|
|
5551
|
-
* result, unknown builtin, step-budget exceeded). */
|
|
5552
|
-
var ExpressionEvalError = class extends Error {
|
|
5553
|
-
constructor(message) {
|
|
5554
|
-
super(message);
|
|
5555
|
-
this.name = "ExpressionEvalError";
|
|
5556
|
-
}
|
|
5557
|
-
};
|
|
5558
|
-
//#endregion
|
|
5559
|
-
//#region src/expression/builtins.ts
|
|
5560
|
-
function asFiniteNumber(value, name, index) {
|
|
5561
|
-
if (typeof value !== "number" || !Number.isFinite(value)) throw new ExpressionEvalError(`${name}: argument ${index + 1} must be a finite number`);
|
|
5562
|
-
return value;
|
|
5563
|
-
}
|
|
5564
|
-
function asString$1(value, name, index) {
|
|
5565
|
-
if (typeof value !== "string") throw new ExpressionEvalError(`${name}: argument ${index + 1} must be a string`);
|
|
5566
|
-
return value;
|
|
5567
|
-
}
|
|
5568
|
-
function finiteResult(value, name) {
|
|
5569
|
-
if (!Number.isFinite(value)) throw new ExpressionEvalError(`${name}: produced a non-finite result`);
|
|
5570
|
-
return value;
|
|
5571
|
-
}
|
|
5572
|
-
function allFiniteNumbers(args, name) {
|
|
5573
|
-
return args.map((a, idx) => asFiniteNumber(a, name, idx));
|
|
5574
|
-
}
|
|
5575
|
-
function asBoolean$1(value, name, index) {
|
|
5576
|
-
if (typeof value !== "boolean") throw new ExpressionEvalError(`${name}: argument ${index + 1} must be a boolean`);
|
|
5577
|
-
return value;
|
|
5578
|
-
}
|
|
5579
|
-
var INF = Number.POSITIVE_INFINITY;
|
|
5580
|
-
var table = {
|
|
5581
|
-
min: {
|
|
5582
|
-
minArgs: 1,
|
|
5583
|
-
maxArgs: INF,
|
|
5584
|
-
apply: (args) => finiteResult(Math.min(...allFiniteNumbers(args, "min")), "min")
|
|
5585
|
-
},
|
|
5586
|
-
max: {
|
|
5587
|
-
minArgs: 1,
|
|
5588
|
-
maxArgs: INF,
|
|
5589
|
-
apply: (args) => finiteResult(Math.max(...allFiniteNumbers(args, "max")), "max")
|
|
5590
|
-
},
|
|
5591
|
-
abs: {
|
|
5592
|
-
minArgs: 1,
|
|
5593
|
-
maxArgs: 1,
|
|
5594
|
-
apply: (args) => finiteResult(Math.abs(asFiniteNumber(args[0], "abs", 0)), "abs")
|
|
5595
|
-
},
|
|
5596
|
-
floor: {
|
|
5597
|
-
minArgs: 1,
|
|
5598
|
-
maxArgs: 1,
|
|
5599
|
-
apply: (args) => finiteResult(Math.floor(asFiniteNumber(args[0], "floor", 0)), "floor")
|
|
5600
|
-
},
|
|
5601
|
-
ceil: {
|
|
5602
|
-
minArgs: 1,
|
|
5603
|
-
maxArgs: 1,
|
|
5604
|
-
apply: (args) => finiteResult(Math.ceil(asFiniteNumber(args[0], "ceil", 0)), "ceil")
|
|
5605
|
-
},
|
|
5606
|
-
sqrt: {
|
|
5607
|
-
minArgs: 1,
|
|
5608
|
-
maxArgs: 1,
|
|
5609
|
-
apply: (args) => finiteResult(Math.sqrt(asFiniteNumber(args[0], "sqrt", 0)), "sqrt")
|
|
5610
|
-
},
|
|
5611
|
-
round: {
|
|
5612
|
-
minArgs: 1,
|
|
5613
|
-
maxArgs: 2,
|
|
5614
|
-
apply: (args) => {
|
|
5615
|
-
const x = asFiniteNumber(args[0], "round", 0);
|
|
5616
|
-
const digits = args.length > 1 ? Math.trunc(asFiniteNumber(args[1], "round", 1)) : 0;
|
|
5617
|
-
if (digits < 0 || digits > 100) throw new ExpressionEvalError("round: digits must be between 0 and 100");
|
|
5618
|
-
const factor = 10 ** digits;
|
|
5619
|
-
return finiteResult(Math.round(x * factor) / factor, "round");
|
|
5620
|
-
}
|
|
5621
|
-
},
|
|
5622
|
-
pow: {
|
|
5623
|
-
minArgs: 2,
|
|
5624
|
-
maxArgs: 2,
|
|
5625
|
-
apply: (args) => finiteResult(asFiniteNumber(args[0], "pow", 0) ** asFiniteNumber(args[1], "pow", 1), "pow")
|
|
5626
|
-
},
|
|
5627
|
-
clamp: {
|
|
5628
|
-
minArgs: 3,
|
|
5629
|
-
maxArgs: 3,
|
|
5630
|
-
apply: (args) => {
|
|
5631
|
-
const x = asFiniteNumber(args[0], "clamp", 0);
|
|
5632
|
-
const lo = asFiniteNumber(args[1], "clamp", 1);
|
|
5633
|
-
const hi = asFiniteNumber(args[2], "clamp", 2);
|
|
5634
|
-
if (lo > hi) throw new ExpressionEvalError("clamp: lower bound is greater than upper bound");
|
|
5635
|
-
return finiteResult(Math.min(hi, Math.max(lo, x)), "clamp");
|
|
5636
|
-
}
|
|
5637
|
-
},
|
|
5638
|
-
avg: {
|
|
5639
|
-
minArgs: 1,
|
|
5640
|
-
maxArgs: INF,
|
|
5641
|
-
apply: (args) => {
|
|
5642
|
-
const nums = allFiniteNumbers(args, "avg");
|
|
5643
|
-
return finiteResult(nums.reduce((acc, v) => acc + v, 0) / nums.length, "avg");
|
|
5644
|
-
}
|
|
5645
|
-
},
|
|
5646
|
-
sum: {
|
|
5647
|
-
minArgs: 1,
|
|
5648
|
-
maxArgs: INF,
|
|
5649
|
-
apply: (args) => finiteResult(allFiniteNumbers(args, "sum").reduce((acc, v) => acc + v, 0), "sum")
|
|
5650
|
-
},
|
|
5651
|
-
coalesce: {
|
|
5652
|
-
minArgs: 1,
|
|
5653
|
-
maxArgs: INF,
|
|
5654
|
-
apply: (args) => {
|
|
5655
|
-
for (const a of args) if (a !== null) return a;
|
|
5656
|
-
return null;
|
|
5657
|
-
}
|
|
5658
|
-
},
|
|
5659
|
-
age: {
|
|
5660
|
-
minArgs: 2,
|
|
5661
|
-
maxArgs: 2,
|
|
5662
|
-
apply: (args) => finiteResult(asFiniteNumber(args[0], "age", 0) - asFiniteNumber(args[1], "age", 1), "age")
|
|
5663
|
-
},
|
|
5664
|
-
convert: {
|
|
5665
|
-
minArgs: 3,
|
|
5666
|
-
maxArgs: 3,
|
|
5667
|
-
apply: (args, hooks) => {
|
|
5668
|
-
const x = asFiniteNumber(args[0], "convert", 0);
|
|
5669
|
-
const from = asString$1(args[1], "convert", 1).trim();
|
|
5670
|
-
const to = asString$1(args[2], "convert", 2).trim();
|
|
5671
|
-
if (hooks.convert) {
|
|
5672
|
-
const out = hooks.convert(x, from, to);
|
|
5673
|
-
if (out === null) throw new ExpressionEvalError(`convert: cannot convert '${from}' to '${to}'`);
|
|
5674
|
-
return finiteResult(out, "convert");
|
|
5675
|
-
}
|
|
5676
|
-
if (from === to) return x;
|
|
5677
|
-
throw new ExpressionEvalError("convert: unit conversion table not installed");
|
|
5678
|
-
}
|
|
5679
|
-
},
|
|
5680
|
-
any: {
|
|
5681
|
-
minArgs: 1,
|
|
5682
|
-
maxArgs: INF,
|
|
5683
|
-
apply: (args) => args.map((a, i) => asBoolean$1(a, "any", i)).some((b) => b)
|
|
5684
|
-
},
|
|
5685
|
-
all: {
|
|
5686
|
-
minArgs: 1,
|
|
5687
|
-
maxArgs: INF,
|
|
5688
|
-
apply: (args) => args.map((a, i) => asBoolean$1(a, "all", i)).every((b) => b)
|
|
5689
|
-
},
|
|
5690
|
-
within: {
|
|
5691
|
-
minArgs: 2,
|
|
5692
|
-
maxArgs: 2,
|
|
5693
|
-
apply: (args, hooks) => {
|
|
5694
|
-
const windowMs = asFiniteNumber(args[1], "within", 1);
|
|
5695
|
-
if (windowMs < 0) throw new ExpressionEvalError("within: the window must not be negative");
|
|
5696
|
-
const at = args[0];
|
|
5697
|
-
if (at === null) return false;
|
|
5698
|
-
const ts = asFiniteNumber(at, "within", 0);
|
|
5699
|
-
const now = hooks.now;
|
|
5700
|
-
if (now === void 0 || !Number.isFinite(now)) throw new ExpressionEvalError("within: no clock was supplied to this evaluation");
|
|
5701
|
-
const inside = now - ts <= windowMs;
|
|
5702
|
-
if (inside) hooks.noteDeadline?.(ts + windowMs + 1);
|
|
5703
|
-
return inside;
|
|
5704
|
-
}
|
|
5705
|
-
},
|
|
5706
|
-
latest: {
|
|
5707
|
-
minArgs: 1,
|
|
5708
|
-
maxArgs: INF,
|
|
5709
|
-
apply: (args) => {
|
|
5710
|
-
const present = args.flatMap((a, i) => a === null ? [] : [asFiniteNumber(a, "latest", i)]);
|
|
5711
|
-
return present.length === 0 ? null : finiteResult(Math.max(...present), "latest");
|
|
5712
|
-
}
|
|
5713
|
-
}
|
|
5714
|
-
};
|
|
5715
|
-
/** Frozen, null-prototype builtin table. */
|
|
5716
|
-
var EXPRESSION_BUILTINS = Object.freeze(Object.assign(Object.create(null), table));
|
|
5717
|
-
/** The set of valid builtin names — used by the parser to reject unknown
|
|
5718
|
-
* callees at parse time (immediate author feedback). */
|
|
5719
|
-
var EXPRESSION_BUILTIN_NAMES = new Set(Object.keys(table));
|
|
5720
|
-
//#endregion
|
|
5721
|
-
//#region src/expression/limits.ts
|
|
5722
|
-
/**
|
|
5723
|
-
* Resource-bound constants for the safe expression engine.
|
|
5724
|
-
*
|
|
5725
|
-
* Every bound is defense-in-depth: the grammar is non-Turing-complete (no
|
|
5726
|
-
* loops, recursion, lambdas or member access — see `ast.ts`), so evaluation is
|
|
5727
|
-
* O(nodeCount) by construction. These caps merely put a hard ceiling on the
|
|
5728
|
-
* work a single author-supplied expression can request, so a hostile or
|
|
5729
|
-
* accidental pathological string can never spend unbounded CPU/memory.
|
|
5730
|
-
*/
|
|
5731
|
-
/** Max source length (chars) — checked BEFORE tokenizing so a huge string is
|
|
5732
|
-
* rejected without allocation. */
|
|
5733
|
-
var MAX_EXPRESSION_SOURCE_LENGTH = 2048;
|
|
5734
|
-
/** Max AST nodes — checked during parse; a deeply nested grouping that exceeds
|
|
5735
|
-
* this is rejected as "expression too complex". */
|
|
5736
|
-
var MAX_EXPRESSION_AST_NODES = 256;
|
|
5737
|
-
/** Defense-in-depth walker step budget — one increment per node visit during
|
|
5738
|
-
* evaluation. The grammar guarantees O(nodeCount) walks, so this can only trip
|
|
5739
|
-
* on a crafted maximum-size AST. */
|
|
5740
|
-
var MAX_EXPRESSION_EVAL_STEPS = 4096;
|
|
5741
|
-
/** Max named bindings on one {@link ExpressionSource}. */
|
|
5742
|
-
var MAX_EXPRESSION_BINDINGS = 32;
|
|
5743
|
-
/** Max positional arguments to any builtin call. */
|
|
5744
|
-
var MAX_EXPRESSION_CALL_ARGS = 16;
|
|
5745
|
-
/** LRU compile-cache capacity (parsed ASTs keyed by raw source string). */
|
|
5746
|
-
var EXPRESSION_COMPILE_CACHE_CAPACITY = 256;
|
|
5747
|
-
/** A legal binding / identifier name. */
|
|
5748
|
-
var EXPRESSION_IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
5749
|
-
/** Binding names an author may NOT use: `now` is auto-injected; the literal
|
|
5750
|
-
* keywords lex as values, not identifiers, so binding to them is meaningless. */
|
|
5751
|
-
var RESERVED_BINDING_NAMES = new Set([
|
|
5752
|
-
"now",
|
|
5753
|
-
"true",
|
|
5754
|
-
"false",
|
|
5755
|
-
"null"
|
|
5756
|
-
]);
|
|
5757
|
-
//#endregion
|
|
5758
|
-
//#region src/expression/tokenizer.ts
|
|
5759
|
-
/**
|
|
5760
|
-
* Tokenizer for the safe expression mini-language. Hand-rolled, single-pass,
|
|
5761
|
-
* zero-dependency. The grammar is deliberately boring: decimal numbers,
|
|
5762
|
-
* single/double-quoted strings with a tiny escape set, identifiers, the three
|
|
5763
|
-
* value keywords (`true`/`false`/`null`) and a fixed punctuator set. Anything
|
|
5764
|
-
* outside that — a bare `.`, `=`, `[`, `]`, `{`, `}`, `;`, backtick, `&`, `|` —
|
|
5765
|
-
* is a parse error with a source position, so member access / assignment /
|
|
5766
|
-
* template literals are lexically impossible.
|
|
5767
|
-
*/
|
|
5768
|
-
var KEYWORDS = new Set([
|
|
5769
|
-
"true",
|
|
5770
|
-
"false",
|
|
5771
|
-
"null"
|
|
5772
|
-
]);
|
|
5773
|
-
function isDigit(ch) {
|
|
5774
|
-
return ch >= "0" && ch <= "9";
|
|
5775
|
-
}
|
|
5776
|
-
function isIdentStart(ch) {
|
|
5777
|
-
return ch >= "A" && ch <= "Z" || ch >= "a" && ch <= "z" || ch === "_";
|
|
5778
|
-
}
|
|
5779
|
-
function isIdentPart(ch) {
|
|
5780
|
-
return isIdentStart(ch) || isDigit(ch);
|
|
5781
|
-
}
|
|
5782
|
-
function isWhitespace(ch) {
|
|
5783
|
-
return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f" || ch === "\v";
|
|
5784
|
-
}
|
|
5785
|
-
/** Tokenize `source` into a flat token list ending with a single `eof` token.
|
|
5786
|
-
* Throws `ExpressionParseError` on any illegal character or unterminated
|
|
5787
|
-
* string. */
|
|
5788
|
-
function tokenize(source) {
|
|
5789
|
-
if (source.length > 2048) throw new ExpressionParseError(`expression too long (${source.length} > ${MAX_EXPRESSION_SOURCE_LENGTH} chars)`, 0);
|
|
5790
|
-
const tokens = [];
|
|
5791
|
-
let i = 0;
|
|
5792
|
-
const n = source.length;
|
|
5793
|
-
while (i < n) {
|
|
5794
|
-
const ch = source[i];
|
|
5795
|
-
if (isWhitespace(ch)) {
|
|
5796
|
-
i += 1;
|
|
5797
|
-
continue;
|
|
5798
|
-
}
|
|
5799
|
-
if (isDigit(ch)) {
|
|
5800
|
-
const start = i;
|
|
5801
|
-
while (i < n && isDigit(source[i])) i += 1;
|
|
5802
|
-
if (i < n && source[i] === ".") {
|
|
5803
|
-
if (i + 1 >= n || !isDigit(source[i + 1])) throw new ExpressionParseError("malformed number: decimal point needs a digit", i);
|
|
5804
|
-
i += 1;
|
|
5805
|
-
while (i < n && isDigit(source[i])) i += 1;
|
|
5806
|
-
}
|
|
5807
|
-
const text = source.slice(start, i);
|
|
5808
|
-
const value = Number(text);
|
|
5809
|
-
if (!Number.isFinite(value)) throw new ExpressionParseError(`malformed number: '${text}'`, start);
|
|
5810
|
-
tokens.push({
|
|
5811
|
-
type: "number",
|
|
5812
|
-
value,
|
|
5813
|
-
pos: start
|
|
5814
|
-
});
|
|
5815
|
-
continue;
|
|
5816
|
-
}
|
|
5817
|
-
if (ch === "'" || ch === "\"") {
|
|
5818
|
-
const quote = ch;
|
|
5819
|
-
const start = i;
|
|
5820
|
-
i += 1;
|
|
5821
|
-
let out = "";
|
|
5822
|
-
let closed = false;
|
|
5823
|
-
while (i < n) {
|
|
5824
|
-
const c = source[i];
|
|
5825
|
-
if (c === "\\") {
|
|
5826
|
-
const next = i + 1 < n ? source[i + 1] : "";
|
|
5827
|
-
if (next === "\\" || next === "'" || next === "\"") {
|
|
5828
|
-
out += next;
|
|
5829
|
-
i += 2;
|
|
5830
|
-
continue;
|
|
5831
|
-
}
|
|
5832
|
-
throw new ExpressionParseError(`invalid string escape: '\\${next}'`, i);
|
|
5833
|
-
}
|
|
5834
|
-
if (c === quote) {
|
|
5835
|
-
closed = true;
|
|
5836
|
-
i += 1;
|
|
5837
|
-
break;
|
|
5838
|
-
}
|
|
5839
|
-
out += c;
|
|
5840
|
-
i += 1;
|
|
5841
|
-
}
|
|
5842
|
-
if (!closed) throw new ExpressionParseError("unterminated string literal", start);
|
|
5843
|
-
tokens.push({
|
|
5844
|
-
type: "string",
|
|
5845
|
-
value: out,
|
|
5846
|
-
pos: start
|
|
5847
|
-
});
|
|
5848
|
-
continue;
|
|
5849
|
-
}
|
|
5850
|
-
if (isIdentStart(ch)) {
|
|
5851
|
-
const start = i;
|
|
5852
|
-
while (i < n && isIdentPart(source[i])) i += 1;
|
|
5853
|
-
const text = source.slice(start, i);
|
|
5854
|
-
if (KEYWORDS.has(text)) tokens.push({
|
|
5855
|
-
type: "keyword",
|
|
5856
|
-
keyword: keywordOf(text),
|
|
5857
|
-
pos: start
|
|
5858
|
-
});
|
|
5859
|
-
else tokens.push({
|
|
5860
|
-
type: "identifier",
|
|
5861
|
-
name: text,
|
|
5862
|
-
pos: start
|
|
5863
|
-
});
|
|
5864
|
-
continue;
|
|
5865
|
-
}
|
|
5866
|
-
const two = i + 1 < n ? source.slice(i, i + 2) : "";
|
|
5867
|
-
if (two === "<=" || two === ">=" || two === "==" || two === "!=" || two === "&&" || two === "||") {
|
|
5868
|
-
tokens.push({
|
|
5869
|
-
type: "punct",
|
|
5870
|
-
punct: two,
|
|
5871
|
-
pos: i
|
|
5872
|
-
});
|
|
5873
|
-
i += 2;
|
|
5874
|
-
continue;
|
|
5875
|
-
}
|
|
5876
|
-
if (isSinglePunct(ch)) {
|
|
5877
|
-
tokens.push({
|
|
5878
|
-
type: "punct",
|
|
5879
|
-
punct: ch,
|
|
5880
|
-
pos: i
|
|
5881
|
-
});
|
|
5882
|
-
i += 1;
|
|
5883
|
-
continue;
|
|
5884
|
-
}
|
|
5885
|
-
throw new ExpressionParseError(`unexpected character '${ch}'`, i);
|
|
5886
|
-
}
|
|
5887
|
-
tokens.push({
|
|
5888
|
-
type: "eof",
|
|
5889
|
-
pos: n
|
|
5890
|
-
});
|
|
5891
|
-
return tokens;
|
|
5892
|
-
}
|
|
5893
|
-
function keywordOf(text) {
|
|
5894
|
-
if (text === "true") return "true";
|
|
5895
|
-
if (text === "false") return "false";
|
|
5896
|
-
return "null";
|
|
5897
|
-
}
|
|
5898
|
-
function isSinglePunct(ch) {
|
|
5899
|
-
return ch === "(" || ch === ")" || ch === "," || ch === "?" || ch === ":" || ch === "+" || ch === "-" || ch === "*" || ch === "/" || ch === "%" || ch === "!" || ch === "<" || ch === ">";
|
|
5900
|
-
}
|
|
5901
|
-
//#endregion
|
|
5902
|
-
//#region src/expression/parser.ts
|
|
5903
|
-
/**
|
|
5904
|
-
* Pratt (precedence-climbing) parser for the safe expression mini-language.
|
|
5905
|
-
*
|
|
5906
|
-
* Precedence (low → high): ternary `?:` (right-assoc) → `||` → `&&` → equality
|
|
5907
|
-
* → relational → additive → multiplicative → unary `! -` → call / primary.
|
|
5908
|
-
* Calls are ONLY `IDENT '(' args? ')'` at primary position — the callee is a
|
|
5909
|
-
* string validated against the builtin table at parse time, so an unknown
|
|
5910
|
-
* function is rejected immediately (author feedback) and a persisted expression
|
|
5911
|
-
* that references a since-removed builtin degrades at read.
|
|
5912
|
-
*
|
|
5913
|
-
* A node counter caps total AST size (`MAX_EXPRESSION_AST_NODES`) and call
|
|
5914
|
-
* arity is capped (`MAX_EXPRESSION_CALL_ARGS`) — both raise `ExpressionParseError`.
|
|
5915
|
-
*/
|
|
5916
|
-
/** Binary/logical operator precedence (higher binds tighter). */
|
|
5917
|
-
var BINARY_PRECEDENCE = {
|
|
5918
|
-
"||": 1,
|
|
5919
|
-
"&&": 2,
|
|
5920
|
-
"==": 3,
|
|
5921
|
-
"!=": 3,
|
|
5922
|
-
"<": 4,
|
|
5923
|
-
"<=": 4,
|
|
5924
|
-
">": 4,
|
|
5925
|
-
">=": 4,
|
|
5926
|
-
"+": 5,
|
|
5927
|
-
"-": 5,
|
|
5928
|
-
"*": 6,
|
|
5929
|
-
"/": 6,
|
|
5930
|
-
"%": 6
|
|
5931
|
-
};
|
|
5932
|
-
function isLogicalOp(op) {
|
|
5933
|
-
return op === "&&" || op === "||";
|
|
5934
|
-
}
|
|
5935
|
-
function isBinaryOp(op) {
|
|
5936
|
-
return op === "+" || op === "-" || op === "*" || op === "/" || op === "%" || op === "==" || op === "!=" || op === "<" || op === "<=" || op === ">" || op === ">=";
|
|
5937
|
-
}
|
|
5938
|
-
var Parser = class {
|
|
5939
|
-
tokens;
|
|
5940
|
-
pos = 0;
|
|
5941
|
-
nodeCount = 0;
|
|
5942
|
-
identifiers = /* @__PURE__ */ new Set();
|
|
5943
|
-
callees = /* @__PURE__ */ new Set();
|
|
5944
|
-
constructor(tokens) {
|
|
5945
|
-
this.tokens = tokens;
|
|
5946
|
-
}
|
|
5947
|
-
parse() {
|
|
5948
|
-
const ast = this.parseTernary();
|
|
5949
|
-
const tok = this.peek();
|
|
5950
|
-
if (tok.type !== "eof") throw new ExpressionParseError("unexpected trailing input", tok.pos);
|
|
5951
|
-
return {
|
|
5952
|
-
ast,
|
|
5953
|
-
identifiers: this.identifiers,
|
|
5954
|
-
callees: this.callees,
|
|
5955
|
-
nodeCount: this.nodeCount
|
|
5956
|
-
};
|
|
5957
|
-
}
|
|
5958
|
-
peek() {
|
|
5959
|
-
return this.tokens[this.pos];
|
|
5960
|
-
}
|
|
5961
|
-
next() {
|
|
5962
|
-
return this.tokens[this.pos++];
|
|
5963
|
-
}
|
|
5964
|
-
/** Consume a punctuator token, erroring if the next token isn't it. */
|
|
5965
|
-
expectPunct(punct) {
|
|
5966
|
-
const tok = this.peek();
|
|
5967
|
-
if (tok.type !== "punct" || tok.punct !== punct) throw new ExpressionParseError(`expected '${punct}'`, tok.pos);
|
|
5968
|
-
this.pos += 1;
|
|
5969
|
-
}
|
|
5970
|
-
matchPunct(punct) {
|
|
5971
|
-
const tok = this.peek();
|
|
5972
|
-
if (tok.type === "punct" && tok.punct === punct) {
|
|
5973
|
-
this.pos += 1;
|
|
5974
|
-
return true;
|
|
5975
|
-
}
|
|
5976
|
-
return false;
|
|
5977
|
-
}
|
|
5978
|
-
countNode() {
|
|
5979
|
-
this.nodeCount += 1;
|
|
5980
|
-
if (this.nodeCount > 256) throw new ExpressionParseError("expression too complex", this.peek().pos);
|
|
5981
|
-
}
|
|
5982
|
-
parseTernary() {
|
|
5983
|
-
const test = this.parseBinary(1);
|
|
5984
|
-
if (this.matchPunct("?")) {
|
|
5985
|
-
const consequent = this.parseTernary();
|
|
5986
|
-
this.expectPunct(":");
|
|
5987
|
-
const alternate = this.parseTernary();
|
|
5988
|
-
this.countNode();
|
|
5989
|
-
return {
|
|
5990
|
-
kind: "conditional",
|
|
5991
|
-
test,
|
|
5992
|
-
consequent,
|
|
5993
|
-
alternate
|
|
5994
|
-
};
|
|
5995
|
-
}
|
|
5996
|
-
return test;
|
|
5997
|
-
}
|
|
5998
|
-
parseBinary(minPrec) {
|
|
5999
|
-
let left = this.parseUnary();
|
|
6000
|
-
for (;;) {
|
|
6001
|
-
const tok = this.peek();
|
|
6002
|
-
if (tok.type !== "punct") break;
|
|
6003
|
-
const prec = BINARY_PRECEDENCE[tok.punct];
|
|
6004
|
-
if (prec === void 0 || prec < minPrec) break;
|
|
6005
|
-
const op = tok.punct;
|
|
6006
|
-
this.pos += 1;
|
|
6007
|
-
const right = this.parseBinary(prec + 1);
|
|
6008
|
-
this.countNode();
|
|
6009
|
-
if (isLogicalOp(op)) left = {
|
|
6010
|
-
kind: "logical",
|
|
6011
|
-
op,
|
|
6012
|
-
left,
|
|
6013
|
-
right
|
|
6014
|
-
};
|
|
6015
|
-
else if (isBinaryOp(op)) left = {
|
|
6016
|
-
kind: "binary",
|
|
6017
|
-
op,
|
|
6018
|
-
left,
|
|
6019
|
-
right
|
|
6020
|
-
};
|
|
6021
|
-
else throw new ExpressionParseError(`unexpected operator '${op}'`, tok.pos);
|
|
6022
|
-
}
|
|
6023
|
-
return left;
|
|
6024
|
-
}
|
|
6025
|
-
parseUnary() {
|
|
6026
|
-
const tok = this.peek();
|
|
6027
|
-
if (tok.type === "punct" && (tok.punct === "!" || tok.punct === "-")) {
|
|
6028
|
-
const op = tok.punct;
|
|
6029
|
-
this.pos += 1;
|
|
6030
|
-
const operand = this.parseUnary();
|
|
6031
|
-
this.countNode();
|
|
6032
|
-
return {
|
|
6033
|
-
kind: "unary",
|
|
6034
|
-
op,
|
|
6035
|
-
operand
|
|
6036
|
-
};
|
|
6037
|
-
}
|
|
6038
|
-
return this.parsePrimary();
|
|
6039
|
-
}
|
|
6040
|
-
parsePrimary() {
|
|
6041
|
-
const tok = this.next();
|
|
6042
|
-
switch (tok.type) {
|
|
6043
|
-
case "number":
|
|
6044
|
-
this.countNode();
|
|
6045
|
-
return {
|
|
6046
|
-
kind: "literal",
|
|
6047
|
-
value: tok.value
|
|
6048
|
-
};
|
|
6049
|
-
case "string":
|
|
6050
|
-
this.countNode();
|
|
6051
|
-
return {
|
|
6052
|
-
kind: "literal",
|
|
6053
|
-
value: tok.value
|
|
6054
|
-
};
|
|
6055
|
-
case "keyword":
|
|
6056
|
-
this.countNode();
|
|
6057
|
-
return {
|
|
6058
|
-
kind: "literal",
|
|
6059
|
-
value: tok.keyword === "null" ? null : tok.keyword === "true"
|
|
6060
|
-
};
|
|
6061
|
-
case "identifier": {
|
|
6062
|
-
const nextTok = this.peek();
|
|
6063
|
-
if (nextTok.type === "punct" && nextTok.punct === "(") return this.parseCall(tok.name, tok.pos);
|
|
6064
|
-
this.identifiers.add(tok.name);
|
|
6065
|
-
this.countNode();
|
|
6066
|
-
return {
|
|
6067
|
-
kind: "identifier",
|
|
6068
|
-
name: tok.name
|
|
6069
|
-
};
|
|
6070
|
-
}
|
|
6071
|
-
case "punct":
|
|
6072
|
-
if (tok.punct === "(") {
|
|
6073
|
-
const inner = this.parseTernary();
|
|
6074
|
-
this.expectPunct(")");
|
|
6075
|
-
return inner;
|
|
6076
|
-
}
|
|
6077
|
-
throw new ExpressionParseError(`unexpected token '${tok.punct}'`, tok.pos);
|
|
6078
|
-
case "eof": throw new ExpressionParseError("unexpected end of expression", tok.pos);
|
|
6079
|
-
}
|
|
6080
|
-
}
|
|
6081
|
-
parseCall(callee, pos) {
|
|
6082
|
-
if (!EXPRESSION_BUILTIN_NAMES.has(callee)) throw new ExpressionParseError(`unknown function '${callee}'`, pos);
|
|
6083
|
-
this.expectPunct("(");
|
|
6084
|
-
const args = [];
|
|
6085
|
-
if (!this.matchPunct(")")) for (;;) {
|
|
6086
|
-
args.push(this.parseTernary());
|
|
6087
|
-
if (args.length > 16) throw new ExpressionParseError(`too many arguments to '${callee}'`, pos);
|
|
6088
|
-
if (this.matchPunct(",")) continue;
|
|
6089
|
-
this.expectPunct(")");
|
|
6090
|
-
break;
|
|
6091
|
-
}
|
|
6092
|
-
this.callees.add(callee);
|
|
6093
|
-
this.countNode();
|
|
6094
|
-
return {
|
|
6095
|
-
kind: "call",
|
|
6096
|
-
callee,
|
|
6097
|
-
args
|
|
6098
|
-
};
|
|
6099
|
-
}
|
|
6100
|
-
};
|
|
6101
|
-
/** Tokenize + parse `source` into a validated `ParsedExpression`. Throws
|
|
6102
|
-
* `ExpressionParseError` on any lexical or grammatical failure. */
|
|
6103
|
-
function parseExpression(source) {
|
|
6104
|
-
return new Parser(tokenize(source)).parse();
|
|
6105
|
-
}
|
|
6106
|
-
//#endregion
|
|
6107
|
-
//#region src/expression/compile.ts
|
|
6108
|
-
/**
|
|
6109
|
-
* LRU compile cache for parsed expressions (spec §2.4 "parse once … LRU keyed
|
|
6110
|
-
* by expr"). The cache stores BOTH successes and failures (negative caching),
|
|
6111
|
-
* so a corrupt persisted string costs exactly one tokenize+parse total — not
|
|
6112
|
-
* one per read on a hot resolve path.
|
|
6113
|
-
*
|
|
6114
|
-
* The cache is a module-level singleton: entries are pure, content-addressed
|
|
6115
|
-
* ASTs keyed by the raw source string, so sharing one instance across all
|
|
6116
|
-
* callers is safe and maximises hit rate.
|
|
6117
|
-
*/
|
|
6118
|
-
var cache = /* @__PURE__ */ new Map();
|
|
6119
|
-
function getCached(source) {
|
|
6120
|
-
const hit = cache.get(source);
|
|
6121
|
-
if (hit !== void 0) {
|
|
6122
|
-
cache.delete(source);
|
|
6123
|
-
cache.set(source, hit);
|
|
6124
|
-
return hit;
|
|
6125
|
-
}
|
|
6126
|
-
let result;
|
|
6127
|
-
try {
|
|
6128
|
-
result = {
|
|
6129
|
-
ok: true,
|
|
6130
|
-
parsed: parseExpression(source)
|
|
6131
|
-
};
|
|
6132
|
-
} catch (err) {
|
|
6133
|
-
result = {
|
|
6134
|
-
ok: false,
|
|
6135
|
-
error: err instanceof ExpressionParseError ? err.message : String(err)
|
|
6136
|
-
};
|
|
6137
|
-
}
|
|
6138
|
-
cache.set(source, result);
|
|
6139
|
-
if (cache.size > 256) {
|
|
6140
|
-
const oldest = cache.keys().next().value;
|
|
6141
|
-
if (oldest !== void 0) cache.delete(oldest);
|
|
6142
|
-
}
|
|
6143
|
-
return result;
|
|
6144
|
-
}
|
|
6145
|
-
/** Compile `source` to a `ParsedExpression`, throwing `ExpressionParseError`
|
|
6146
|
-
* on failure. LRU/negative-cached. */
|
|
6147
|
-
function compileExpression(source) {
|
|
6148
|
-
const result = getCached(source);
|
|
6149
|
-
if (result.ok) return result.parsed;
|
|
6150
|
-
throw new ExpressionParseError(result.error);
|
|
6151
|
-
}
|
|
6152
|
-
/** Compile `source`, returning a discriminated result instead of throwing.
|
|
6153
|
-
* Used by read paths that must degrade rather than raise. LRU/negative-cached. */
|
|
6154
|
-
function compileExpressionSafe(source) {
|
|
6155
|
-
return getCached(source);
|
|
6156
|
-
}
|
|
6157
|
-
//#endregion
|
|
6158
|
-
//#region src/expression/evaluator.ts
|
|
6159
|
-
/**
|
|
6160
|
-
* Tree-walking evaluator for the safe expression mini-language.
|
|
6161
|
-
*
|
|
6162
|
-
* SECURITY (spec §4 rule 2/5):
|
|
6163
|
-
* - The scope is an `Object.create(null)` copy of ONLY the caller's own
|
|
6164
|
-
* enumerable binding entries, so `name in scope` is a pure own-key check and
|
|
6165
|
-
* `constructor` / `__proto__` / `toString` are plain unknown identifiers.
|
|
6166
|
-
* - Performs ZERO I/O and never touches `globalThis` / `Date` / `Math`
|
|
6167
|
-
* directly — the only external calls are into the frozen builtin table.
|
|
6168
|
-
* - The grammar has no loops/recursion/lambdas, so a walk is O(nodeCount) by
|
|
6169
|
-
* construction; the step counter is defense-in-depth for a crafted max-size
|
|
6170
|
-
* AST. Nothing blocks: there are no timers, awaits or unbounded loops.
|
|
6171
|
-
*/
|
|
6172
|
-
var EMPTY_HOOKS = Object.freeze({});
|
|
6173
|
-
/** Build a null-prototype scope from own-enumerable binding entries. Inherited
|
|
6174
|
-
* keys of the input (e.g. from a `{__proto__: {...}}` payload) are NOT copied,
|
|
6175
|
-
* so nothing smuggles in via the prototype chain. */
|
|
6176
|
-
function createExpressionScope(bindings) {
|
|
6177
|
-
const scope = Object.create(null);
|
|
6178
|
-
for (const key of Object.keys(bindings)) if (Object.prototype.hasOwnProperty.call(bindings, key)) scope[key] = bindings[key];
|
|
6179
|
-
return scope;
|
|
6180
|
-
}
|
|
6181
|
-
function isFiniteNumber(value) {
|
|
6182
|
-
return typeof value === "number" && Number.isFinite(value);
|
|
6183
|
-
}
|
|
6184
|
-
/** JS truthiness of a primitive value. */
|
|
6185
|
-
function truthy(value) {
|
|
6186
|
-
return Boolean(value);
|
|
6187
|
-
}
|
|
6188
|
-
function requireFinite(value, context) {
|
|
6189
|
-
if (!Number.isFinite(value)) throw new ExpressionEvalError(`${context} produced a non-finite result`);
|
|
6190
|
-
return value;
|
|
6191
|
-
}
|
|
6192
|
-
function step(ctx) {
|
|
6193
|
-
ctx.steps += 1;
|
|
6194
|
-
if (ctx.steps > ctx.maxSteps) throw new ExpressionEvalError("expression evaluation step budget exceeded");
|
|
6195
|
-
}
|
|
6196
|
-
function evalNode(node, ctx) {
|
|
6197
|
-
step(ctx);
|
|
6198
|
-
switch (node.kind) {
|
|
6199
|
-
case "literal": return node.value;
|
|
6200
|
-
case "identifier":
|
|
6201
|
-
if (!(node.name in ctx.scope)) throw new ExpressionEvalError(`unknown identifier: ${node.name}`);
|
|
6202
|
-
return ctx.scope[node.name];
|
|
6203
|
-
case "unary": return evalUnary(node.op, evalNode(node.operand, ctx));
|
|
6204
|
-
case "binary": return evalBinary(node.op, evalNode(node.left, ctx), evalNode(node.right, ctx));
|
|
6205
|
-
case "logical": {
|
|
6206
|
-
const left = evalNode(node.left, ctx);
|
|
6207
|
-
if (node.op === "&&") return truthy(left) ? evalNode(node.right, ctx) : left;
|
|
6208
|
-
return truthy(left) ? left : evalNode(node.right, ctx);
|
|
6209
|
-
}
|
|
6210
|
-
case "conditional": return truthy(evalNode(node.test, ctx)) ? evalNode(node.consequent, ctx) : evalNode(node.alternate, ctx);
|
|
6211
|
-
case "call": return evalCall(node.callee, node.args.map((a) => evalNode(a, ctx)), ctx.hooks);
|
|
6212
|
-
}
|
|
6213
|
-
}
|
|
6214
|
-
function evalUnary(op, operand) {
|
|
6215
|
-
if (op === "!") return !truthy(operand);
|
|
6216
|
-
if (!isFiniteNumber(operand)) throw new ExpressionEvalError("unary \"-\" requires a finite number");
|
|
6217
|
-
return requireFinite(-operand, "unary \"-\"");
|
|
6218
|
-
}
|
|
6219
|
-
function evalBinary(op, left, right) {
|
|
6220
|
-
switch (op) {
|
|
6221
|
-
case "==": return left === right;
|
|
6222
|
-
case "!=": return left !== right;
|
|
6223
|
-
case "+":
|
|
6224
|
-
if (typeof left === "string" && typeof right === "string") return left + right;
|
|
6225
|
-
if (isFiniteNumber(left) && isFiniteNumber(right)) return requireFinite(left + right, "\"+\"");
|
|
6226
|
-
throw new ExpressionEvalError("\"+\" requires two numbers or two strings");
|
|
6227
|
-
case "-":
|
|
6228
|
-
case "*":
|
|
6229
|
-
case "/":
|
|
6230
|
-
case "%":
|
|
6231
|
-
if (!isFiniteNumber(left) || !isFiniteNumber(right)) throw new ExpressionEvalError(`"${op}" requires two finite numbers`);
|
|
6232
|
-
return requireFinite(op === "-" ? left - right : op === "*" ? left * right : op === "/" ? left / right : left % right, `"${op}"`);
|
|
6233
|
-
case "<":
|
|
6234
|
-
case "<=":
|
|
6235
|
-
case ">":
|
|
6236
|
-
case ">=":
|
|
6237
|
-
if (isFiniteNumber(left) && isFiniteNumber(right)) return op === "<" ? left < right : op === "<=" ? left <= right : op === ">" ? left > right : left >= right;
|
|
6238
|
-
if (typeof left === "string" && typeof right === "string") return op === "<" ? left < right : op === "<=" ? left <= right : op === ">" ? left > right : left >= right;
|
|
6239
|
-
throw new ExpressionEvalError(`"${op}" requires two numbers or two strings`);
|
|
6240
|
-
}
|
|
6241
|
-
}
|
|
6242
|
-
function evalCall(callee, args, hooks) {
|
|
6243
|
-
if (!Object.prototype.hasOwnProperty.call(EXPRESSION_BUILTINS, callee)) throw new ExpressionEvalError(`unknown function: ${callee}`);
|
|
6244
|
-
const builtin = EXPRESSION_BUILTINS[callee];
|
|
6245
|
-
if (args.length < builtin.minArgs || args.length > builtin.maxArgs) throw new ExpressionEvalError(`${callee}: wrong number of arguments (${args.length})`);
|
|
6246
|
-
return builtin.apply(args, hooks);
|
|
6247
|
-
}
|
|
6248
|
-
/** Evaluate an AST node against a scope. Throws `ExpressionEvalError` on any
|
|
6249
|
-
* runtime failure (unknown identifier, type mismatch, non-finite result,
|
|
6250
|
-
* step-budget exhaustion). */
|
|
6251
|
-
function evaluateAst(node, scope, opts) {
|
|
6252
|
-
return evalNode(node, {
|
|
6253
|
-
scope,
|
|
6254
|
-
hooks: opts?.hooks ?? EMPTY_HOOKS,
|
|
6255
|
-
maxSteps: opts?.maxSteps ?? 4096,
|
|
6256
|
-
steps: 0
|
|
6257
|
-
});
|
|
6258
|
-
}
|
|
6259
|
-
//#endregion
|
|
6260
|
-
//#region src/expression/expression-source.ts
|
|
6261
|
-
/** The `now` epoch-ms binding is auto-injected into every evaluation and is a
|
|
6262
|
-
* reserved binding name (authors may not rebind it). */
|
|
6263
|
-
var EXPRESSION_INJECTED_NOW = "now";
|
|
6264
|
-
/**
|
|
6265
|
-
* Coerce an untrusted `getByPath` / mirror read to an `ExpressionValue`.
|
|
6266
|
-
* Non-primitive values (objects, arrays, `undefined`, functions, bigint,
|
|
6267
|
-
* symbol) and non-finite numbers become `undefined` so the caller can apply
|
|
6268
|
-
* its binding-miss policy (→ `null`). `null` itself is a valid value.
|
|
6269
|
-
*/
|
|
6270
|
-
function toExpressionValue(raw) {
|
|
6271
|
-
if (raw === null) return null;
|
|
6272
|
-
if (typeof raw === "string") return raw;
|
|
6273
|
-
if (typeof raw === "boolean") return raw;
|
|
6274
|
-
if (typeof raw === "number") return Number.isFinite(raw) ? raw : void 0;
|
|
6275
|
-
}
|
|
6276
|
-
/**
|
|
6277
|
-
* Author-time validation. Returns `null` when the source is valid, else a
|
|
6278
|
-
* human-readable error message. Checks: the expression compiles; binding count
|
|
6279
|
-
* is within `MAX_EXPRESSION_BINDINGS`; every binding name is a legal identifier,
|
|
6280
|
-
* is not reserved (`now`/keywords) and does not shadow a builtin; and every
|
|
6281
|
-
* FREE identifier of the AST is covered by a binding or the injected `now`.
|
|
6282
|
-
*/
|
|
6283
|
-
function validateExpressionSource(src) {
|
|
6284
|
-
const names = Object.keys(src.bindings);
|
|
6285
|
-
if (names.length > 32) return `too many bindings (${names.length} > 32)`;
|
|
6286
|
-
for (const name of names) {
|
|
6287
|
-
if (!EXPRESSION_IDENTIFIER_RE.test(name)) return `invalid binding name '${name}'`;
|
|
6288
|
-
if (RESERVED_BINDING_NAMES.has(name)) return `binding name '${name}' is reserved`;
|
|
6289
|
-
if (EXPRESSION_BUILTIN_NAMES.has(name)) return `binding name '${name}' shadows a builtin function`;
|
|
6290
|
-
}
|
|
6291
|
-
const compiled = compileExpressionSafe(src.expr);
|
|
6292
|
-
if (!compiled.ok) return compiled.error;
|
|
6293
|
-
const bound = new Set(names);
|
|
6294
|
-
for (const id of compiled.parsed.identifiers) {
|
|
6295
|
-
if (id === "now") continue;
|
|
6296
|
-
if (!bound.has(id)) return `expression references unbound identifier '${id}'`;
|
|
6297
|
-
}
|
|
6298
|
-
return null;
|
|
6299
|
-
}
|
|
6300
|
-
/**
|
|
6301
|
-
* Shared read-path evaluation. Builds a null-proto scope from `bindingValues`
|
|
6302
|
-
* plus the injected `now` (supplied by the caller for determinism and
|
|
6303
|
-
* testability), compiles via the LRU, and evaluates. Any failure (parse or
|
|
6304
|
-
* eval) returns `{ ok: false }` — the caller treats that as "skip this
|
|
6305
|
-
* derivation", never as a throw that takes the pass down.
|
|
6306
|
-
*/
|
|
6307
|
-
function evaluateExpressionSource(expr, bindingValues, now, opts) {
|
|
6308
|
-
const compiled = compileExpressionSafe(expr);
|
|
6309
|
-
if (!compiled.ok) return {
|
|
6310
|
-
ok: false,
|
|
6311
|
-
error: compiled.error
|
|
6312
|
-
};
|
|
6313
|
-
const scope = createExpressionScope({
|
|
6314
|
-
...bindingValues,
|
|
6315
|
-
["now"]: now
|
|
6316
|
-
});
|
|
6317
|
-
const hooks = {
|
|
6318
|
-
...opts?.hooks,
|
|
6319
|
-
now
|
|
6320
|
-
};
|
|
6321
|
-
try {
|
|
6322
|
-
return {
|
|
6323
|
-
ok: true,
|
|
6324
|
-
value: evaluateAst(compiled.parsed.ast, scope, {
|
|
6325
|
-
...opts,
|
|
6326
|
-
hooks
|
|
6327
|
-
})
|
|
6328
|
-
};
|
|
6329
|
-
} catch (err) {
|
|
6330
|
-
return {
|
|
6331
|
-
ok: false,
|
|
6332
|
-
error: err instanceof ExpressionEvalError ? err.message : String(err)
|
|
6333
|
-
};
|
|
6334
|
-
}
|
|
6335
|
-
}
|
|
6336
|
-
//#endregion
|
|
6337
5534
|
//#region src/expression/binding-source.ts
|
|
6338
5535
|
/**
|
|
6339
5536
|
* What an expression's named bindings READ from.
|
|
@@ -6394,10 +5591,10 @@ var ExpressionBindingSourceSchema = zod.z.union([
|
|
|
6394
5591
|
* Compiles are LRU-cached, so repeated validation of the same string is a hit.
|
|
6395
5592
|
*/
|
|
6396
5593
|
var ExpressionSourceSchema = zod.z.object({
|
|
6397
|
-
expr: zod.z.string().min(1).max(MAX_EXPRESSION_SOURCE_LENGTH),
|
|
6398
|
-
bindings: zod.z.record(zod.z.string().regex(EXPRESSION_IDENTIFIER_RE), ExpressionBindingSourceSchema)
|
|
5594
|
+
expr: zod.z.string().min(1).max(require_composition.MAX_EXPRESSION_SOURCE_LENGTH),
|
|
5595
|
+
bindings: zod.z.record(zod.z.string().regex(require_composition.EXPRESSION_IDENTIFIER_RE), ExpressionBindingSourceSchema)
|
|
6399
5596
|
}).superRefine((src, ctx) => {
|
|
6400
|
-
const err = validateExpressionSource(src);
|
|
5597
|
+
const err = require_composition.validateExpressionSource(src);
|
|
6401
5598
|
if (err !== null) ctx.addIssue({
|
|
6402
5599
|
code: "custom",
|
|
6403
5600
|
message: err,
|
|
@@ -6478,10 +5675,10 @@ var AutomationConditionLeafSchema = zod.z.object({
|
|
|
6478
5675
|
*/
|
|
6479
5676
|
var AutomationConditionExpressionSchema = zod.z.object({
|
|
6480
5677
|
kind: zod.z.literal("expression"),
|
|
6481
|
-
expr: zod.z.string().min(1).max(MAX_EXPRESSION_SOURCE_LENGTH),
|
|
6482
|
-
bindings: zod.z.record(zod.z.string().regex(EXPRESSION_IDENTIFIER_RE), ExpressionBindingSourceSchema)
|
|
5678
|
+
expr: zod.z.string().min(1).max(require_composition.MAX_EXPRESSION_SOURCE_LENGTH),
|
|
5679
|
+
bindings: zod.z.record(zod.z.string().regex(require_composition.EXPRESSION_IDENTIFIER_RE), ExpressionBindingSourceSchema)
|
|
6483
5680
|
}).superRefine((src, ctx) => {
|
|
6484
|
-
const err = validateExpressionSource(src);
|
|
5681
|
+
const err = require_composition.validateExpressionSource(src);
|
|
6485
5682
|
if (err !== null) ctx.addIssue({
|
|
6486
5683
|
code: "custom",
|
|
6487
5684
|
message: err,
|
|
@@ -7555,7 +6752,7 @@ var audioAnalysisCapability = {
|
|
|
7555
6752
|
mode: "singleton",
|
|
7556
6753
|
kind: "wrapper",
|
|
7557
6754
|
defaultActive: true,
|
|
7558
|
-
deviceTypes: [
|
|
6755
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
7559
6756
|
exposesDeviceSettings: true,
|
|
7560
6757
|
methods: {
|
|
7561
6758
|
/**
|
|
@@ -8702,7 +7899,7 @@ var cameraPipelineConfigCapability = {
|
|
|
8702
7899
|
mode: "singleton",
|
|
8703
7900
|
kind: "wrapper",
|
|
8704
7901
|
defaultActive: true,
|
|
8705
|
-
deviceTypes: [
|
|
7902
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
8706
7903
|
exposesDeviceSettings: true,
|
|
8707
7904
|
methods: {}
|
|
8708
7905
|
};
|
|
@@ -9812,7 +9009,7 @@ var cameraStreamsCapability = {
|
|
|
9812
9009
|
mode: "singleton",
|
|
9813
9010
|
kind: "wrapper",
|
|
9814
9011
|
defaultActive: true,
|
|
9815
|
-
deviceTypes: [
|
|
9012
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
9816
9013
|
methods: {
|
|
9817
9014
|
getCameraStreams: require_sleep.method(zod.z.object({ deviceId: zod.z.number().int().nonnegative() }), zod.z.array(require_sleep.CameraStreamSchema).readonly()),
|
|
9818
9015
|
getBrokerStreams: require_sleep.method(zod.z.object({ deviceId: zod.z.number().int().nonnegative() }), zod.z.array(require_sleep.ProfileSlotSchema).readonly()),
|
|
@@ -10136,177 +9333,6 @@ function kebabToCamel(s) {
|
|
|
10136
9333
|
return s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
10137
9334
|
}
|
|
10138
9335
|
//#endregion
|
|
10139
|
-
//#region src/composition/composition.ts
|
|
10140
|
-
/**
|
|
10141
|
-
* A COMPOSITION: a device assembled from other devices' state (D659).
|
|
10142
|
-
*
|
|
10143
|
-
* The data half of the composed-devices spec §1. A composition is stored inside
|
|
10144
|
-
* a core block (`CoreBlock.source.kind === 'composition'`) and run by the shared
|
|
10145
|
-
* `composer` runner. It names a TARGET and, for each capability of the target, a
|
|
10146
|
-
* FIELD MAP: every state field has exactly one source.
|
|
10147
|
-
*
|
|
10148
|
-
* Sources are keyed by `(addonId, stableId)`, NEVER by numeric device id. A
|
|
10149
|
-
* resync reissues numeric ids, and a composition that stored them would be
|
|
10150
|
-
* orphaned by the first re-adoption (the linked-devices lesson). A `stableId` is
|
|
10151
|
-
* unique only within its owning addon, so the owner travels with it.
|
|
10152
|
-
*
|
|
10153
|
-
* Later slices EXTEND these unions and do not reshape them. The variants a later
|
|
10154
|
-
* slice implements are already in the wire shape, and `validateComposition`
|
|
10155
|
-
* refuses them BY NAME until then:
|
|
10156
|
-
* target `existing` → slice 2 · feature `passthrough` → slice 3 ·
|
|
10157
|
-
* `commands` (`forward`) → slice 3 · source `code` → slice 4.
|
|
10158
|
-
*/
|
|
10159
|
-
/** The owner of every composed device: the `composer` builtin. */
|
|
10160
|
-
var COMPOSER_ADDON_ID = "composer";
|
|
10161
|
-
/** A composed device's stableId is this prefix plus the block id. */
|
|
10162
|
-
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
10163
|
-
/** A device with more capabilities than this is two devices. */
|
|
10164
|
-
var MAX_COMPOSITION_FEATURES = 16;
|
|
10165
|
-
var MAX_COMPOSITION_FIELDS_PER_FEATURE = 32;
|
|
10166
|
-
/** Longest snippet a `code` source may carry (slice 4). */
|
|
10167
|
-
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
10168
|
-
var CompositionSourceRefSchema = zod.z.object({
|
|
10169
|
-
/** The owning addon; `stableId` is unique only within it. */
|
|
10170
|
-
addonId: zod.z.string().min(1),
|
|
10171
|
-
stableId: zod.z.string().min(1)
|
|
10172
|
-
});
|
|
10173
|
-
/** One field of one capability of one source device. */
|
|
10174
|
-
var CompositionFieldReadSchema = zod.z.object({
|
|
10175
|
-
source: CompositionSourceRefSchema,
|
|
10176
|
-
cap: zod.z.string().min(1),
|
|
10177
|
-
/** Dotted path into the source cap's runtime-state slice. */
|
|
10178
|
-
fieldPath: zod.z.string().min(1)
|
|
10179
|
-
});
|
|
10180
|
-
/** `from`: copy one source field verbatim. It is also an expression's `from` binding. */
|
|
10181
|
-
var CompositionFromSourceSchema = CompositionFieldReadSchema.extend({ kind: zod.z.literal("from") });
|
|
10182
|
-
/** A constant binding. No device is read. */
|
|
10183
|
-
var CompositionLiteralBindingSchema = zod.z.object({
|
|
10184
|
-
kind: zod.z.literal("literal"),
|
|
10185
|
-
value: zod.z.union([
|
|
10186
|
-
zod.z.string(),
|
|
10187
|
-
zod.z.number(),
|
|
10188
|
-
zod.z.boolean(),
|
|
10189
|
-
zod.z.null()
|
|
10190
|
-
])
|
|
10191
|
-
});
|
|
10192
|
-
var CompositionBindingSchema = zod.z.discriminatedUnion("kind", [CompositionFromSourceSchema, CompositionLiteralBindingSchema]);
|
|
10193
|
-
/**
|
|
10194
|
-
* `expression`: a formula over named bindings, in the salvaged expression
|
|
10195
|
-
* engine. Validated at parse by the SAME function every other consumer runs,
|
|
10196
|
-
* so the editor and the store cannot disagree.
|
|
10197
|
-
*/
|
|
10198
|
-
var CompositionExpressionSourceSchema = zod.z.object({
|
|
10199
|
-
kind: zod.z.literal("expression"),
|
|
10200
|
-
expr: zod.z.string().min(1).max(MAX_EXPRESSION_SOURCE_LENGTH),
|
|
10201
|
-
bindings: zod.z.record(zod.z.string().regex(EXPRESSION_IDENTIFIER_RE), CompositionBindingSchema)
|
|
10202
|
-
}).superRefine((src, ctx) => {
|
|
10203
|
-
const err = validateExpressionSource(src);
|
|
10204
|
-
if (err !== null) ctx.addIssue({
|
|
10205
|
-
code: "custom",
|
|
10206
|
-
message: err,
|
|
10207
|
-
path: ["expr"]
|
|
10208
|
-
});
|
|
10209
|
-
});
|
|
10210
|
-
/** `code`: RESERVED for slice 4 (own runner, one-way eject). */
|
|
10211
|
-
var CompositionCodeSourceSchema = zod.z.object({
|
|
10212
|
-
kind: zod.z.literal("code"),
|
|
10213
|
-
code: zod.z.string().min(1).max(MAX_COMPOSITION_CODE_LENGTH)
|
|
10214
|
-
});
|
|
10215
|
-
var CompositionFieldSourceSchema = zod.z.discriminatedUnion("kind", [
|
|
10216
|
-
CompositionFromSourceSchema,
|
|
10217
|
-
CompositionExpressionSourceSchema,
|
|
10218
|
-
CompositionCodeSourceSchema
|
|
10219
|
-
]);
|
|
10220
|
-
/** `forward`: RESERVED for slice 3. Argument mapping arrives there as an additive optional `args`. */
|
|
10221
|
-
var CompositionForwardCommandSchema = zod.z.object({
|
|
10222
|
-
kind: zod.z.literal("forward"),
|
|
10223
|
-
source: CompositionSourceRefSchema,
|
|
10224
|
-
cap: zod.z.string().min(1),
|
|
10225
|
-
method: zod.z.string().min(1)
|
|
10226
|
-
});
|
|
10227
|
-
var CompositionCommandTargetSchema = zod.z.discriminatedUnion("kind", [CompositionForwardCommandSchema, CompositionCodeSourceSchema]);
|
|
10228
|
-
var CompositionFieldsFeatureSchema = zod.z.object({
|
|
10229
|
-
kind: zod.z.literal("fields"),
|
|
10230
|
-
cap: zod.z.string().min(1),
|
|
10231
|
-
fields: zod.z.record(zod.z.string().min(1), CompositionFieldSourceSchema).refine((fields) => Object.keys(fields).length <= 32, { message: `at most 32 fields per capability` }),
|
|
10232
|
-
/** RESERVED for slice 3; refused by the validator when non-empty. */
|
|
10233
|
-
commands: zod.z.record(zod.z.string().min(1), CompositionCommandTargetSchema).optional()
|
|
10234
|
-
});
|
|
10235
|
-
/** RESERVED for slice 3: a media / data-plane cap, whole, from one source. */
|
|
10236
|
-
var CompositionPassthroughFeatureSchema = zod.z.object({
|
|
10237
|
-
kind: zod.z.literal("passthrough"),
|
|
10238
|
-
cap: zod.z.string().min(1),
|
|
10239
|
-
source: CompositionSourceRefSchema
|
|
10240
|
-
});
|
|
10241
|
-
var CompositionFeatureSchema = zod.z.discriminatedUnion("kind", [CompositionFieldsFeatureSchema, CompositionPassthroughFeatureSchema]);
|
|
10242
|
-
/**
|
|
10243
|
-
* A NEW device. It has no `name` of its own: the block's name IS the device's
|
|
10244
|
-
* name (2026-08-08). A second copy here would be a second writer of one string (D62).
|
|
10245
|
-
*/
|
|
10246
|
-
var CompositionNewTargetSchema = zod.z.object({
|
|
10247
|
-
kind: zod.z.literal("new"),
|
|
10248
|
-
type: zod.z.enum(require_sleep.DeviceType),
|
|
10249
|
-
role: zod.z.enum(require_sleep.DeviceRole).optional()
|
|
10250
|
-
});
|
|
10251
|
-
/** RESERVED for slice 2: customize an existing device. */
|
|
10252
|
-
var CompositionExistingTargetSchema = zod.z.object({
|
|
10253
|
-
kind: zod.z.literal("existing"),
|
|
10254
|
-
device: CompositionSourceRefSchema
|
|
10255
|
-
});
|
|
10256
|
-
var CompositionTargetSchema = zod.z.discriminatedUnion("kind", [CompositionNewTargetSchema, CompositionExistingTargetSchema]);
|
|
10257
|
-
var CompositionSchema = zod.z.object({
|
|
10258
|
-
target: CompositionTargetSchema,
|
|
10259
|
-
features: zod.z.array(CompositionFeatureSchema).min(1).max(16)
|
|
10260
|
-
}).superRefine((composition, ctx) => {
|
|
10261
|
-
const seen = /* @__PURE__ */ new Set();
|
|
10262
|
-
composition.features.forEach((feature, index) => {
|
|
10263
|
-
if (seen.has(feature.cap)) ctx.addIssue({
|
|
10264
|
-
code: "custom",
|
|
10265
|
-
message: `capability \`${feature.cap}\` is composed twice — one feature per capability`,
|
|
10266
|
-
path: [
|
|
10267
|
-
"features",
|
|
10268
|
-
index,
|
|
10269
|
-
"cap"
|
|
10270
|
-
]
|
|
10271
|
-
});
|
|
10272
|
-
seen.add(feature.cap);
|
|
10273
|
-
});
|
|
10274
|
-
});
|
|
10275
|
-
function compositionSourceKey(ref) {
|
|
10276
|
-
return `${ref.addonId}/${ref.stableId}`;
|
|
10277
|
-
}
|
|
10278
|
-
function compositionSliceKey(ref, cap) {
|
|
10279
|
-
return `${compositionSourceKey(ref)}#${cap}`;
|
|
10280
|
-
}
|
|
10281
|
-
function compositionReadKey(read) {
|
|
10282
|
-
return `${compositionSliceKey(read.source, read.cap)}.${read.fieldPath}`;
|
|
10283
|
-
}
|
|
10284
|
-
function composedDeviceStableId(blockId) {
|
|
10285
|
-
return `${COMPOSED_DEVICE_STABLE_ID_PREFIX}${blockId}`;
|
|
10286
|
-
}
|
|
10287
|
-
function composedDeviceRef(blockId) {
|
|
10288
|
-
return {
|
|
10289
|
-
addonId: COMPOSER_ADDON_ID,
|
|
10290
|
-
stableId: composedDeviceStableId(blockId)
|
|
10291
|
-
};
|
|
10292
|
-
}
|
|
10293
|
-
/** Every device field a source reads: `from` is one read, an expression is its `from` bindings. */
|
|
10294
|
-
function fieldReads(source) {
|
|
10295
|
-
switch (source.kind) {
|
|
10296
|
-
case "from": return [{
|
|
10297
|
-
source: source.source,
|
|
10298
|
-
cap: source.cap,
|
|
10299
|
-
fieldPath: source.fieldPath
|
|
10300
|
-
}];
|
|
10301
|
-
case "expression": return Object.values(source.bindings).flatMap((binding) => binding.kind === "from" ? [{
|
|
10302
|
-
source: binding.source,
|
|
10303
|
-
cap: binding.cap,
|
|
10304
|
-
fieldPath: binding.fieldPath
|
|
10305
|
-
}] : []);
|
|
10306
|
-
case "code": return [];
|
|
10307
|
-
}
|
|
10308
|
-
}
|
|
10309
|
-
//#endregion
|
|
10310
9336
|
//#region src/composition/composition-report.ts
|
|
10311
9337
|
/**
|
|
10312
9338
|
* What the validator says about a composition and what the composer says about
|
|
@@ -10329,7 +9355,12 @@ var CompositionProblemCodeSchema = zod.z.enum([
|
|
|
10329
9355
|
"source-field-unknown",
|
|
10330
9356
|
"expression-invalid",
|
|
10331
9357
|
"cycle",
|
|
10332
|
-
"duplicate-target"
|
|
9358
|
+
"duplicate-target",
|
|
9359
|
+
"not-item-array",
|
|
9360
|
+
"item-field-reserved",
|
|
9361
|
+
"target-missing",
|
|
9362
|
+
"target-unreadable",
|
|
9363
|
+
"not-replaceable"
|
|
10333
9364
|
]);
|
|
10334
9365
|
/** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.celsius`. */
|
|
10335
9366
|
var CompositionProblemSchema = zod.z.object({
|
|
@@ -10343,8 +9374,18 @@ var CompositionFieldKindSchema = zod.z.enum([
|
|
|
10343
9374
|
"boolean",
|
|
10344
9375
|
"enum"
|
|
10345
9376
|
]);
|
|
10346
|
-
/**
|
|
10347
|
-
|
|
9377
|
+
/**
|
|
9378
|
+
* How a field says "unavailable" (D393, D663): `null` when its schema allows it;
|
|
9379
|
+
* `unknown` — the enum's own word — for an ADDED field that has one; `release`
|
|
9380
|
+
* for a REPLACED field of an existing device, whose claim is released so the
|
|
9381
|
+
* native provider's reading shows again; else the (composed) device goes offline.
|
|
9382
|
+
*/
|
|
9383
|
+
var CompositionUnavailableModeSchema = zod.z.enum([
|
|
9384
|
+
"null",
|
|
9385
|
+
"offline",
|
|
9386
|
+
"unknown",
|
|
9387
|
+
"release"
|
|
9388
|
+
]);
|
|
10348
9389
|
/**
|
|
10349
9390
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
10350
9391
|
* field of its cap changes value · `constant` reads nothing, computed once.
|
|
@@ -10354,9 +9395,17 @@ var CompositionFieldRoleSchema = zod.z.enum([
|
|
|
10354
9395
|
"clock",
|
|
10355
9396
|
"constant"
|
|
10356
9397
|
]);
|
|
9398
|
+
/** The item a planned field belongs to; its `path` is then the dotted path INSIDE the item. */
|
|
9399
|
+
var CompositionFieldItemSchema = zod.z.object({
|
|
9400
|
+
arrayPath: zod.z.string(),
|
|
9401
|
+
key: zod.z.string(),
|
|
9402
|
+
label: zod.z.string()
|
|
9403
|
+
});
|
|
10357
9404
|
var CompositionFieldPlanSchema = zod.z.object({
|
|
10358
9405
|
cap: zod.z.string(),
|
|
9406
|
+
/** Top-level field, or — when `item` is set — the dotted path inside that item. */
|
|
10359
9407
|
path: zod.z.string(),
|
|
9408
|
+
item: CompositionFieldItemSchema.optional(),
|
|
10360
9409
|
/** Index into `composition.features` this field's capability came from —
|
|
10361
9410
|
* lets a source/cycle problem name its path as `features[N].fields.<path>`
|
|
10362
9411
|
* (the same convention `planComposition`'s own problems already use). */
|
|
@@ -10366,19 +9415,45 @@ var CompositionFieldPlanSchema = zod.z.object({
|
|
|
10366
9415
|
required: zod.z.boolean(),
|
|
10367
9416
|
unavailable: CompositionUnavailableModeSchema,
|
|
10368
9417
|
role: CompositionFieldRoleSchema,
|
|
10369
|
-
source: CompositionFieldSourceSchema,
|
|
10370
|
-
reads: zod.z.array(CompositionFieldReadSchema)
|
|
9418
|
+
source: require_composition.CompositionFieldSourceSchema,
|
|
9419
|
+
reads: zod.z.array(require_composition.CompositionFieldReadSchema)
|
|
9420
|
+
});
|
|
9421
|
+
/** The key every record map, log line and graph node uses for a planned field. Two items' `status` are two keys. */
|
|
9422
|
+
function compositionFieldKey(plan) {
|
|
9423
|
+
const path = plan.item === void 0 ? plan.path : require_composition.compositionItemFieldPath(plan.item.arrayPath, plan.item.key, plan.path);
|
|
9424
|
+
return `${plan.cap}.${path}`;
|
|
9425
|
+
}
|
|
9426
|
+
/**
|
|
9427
|
+
* What a feature does to its target (D663): `new` builds a capability on a new
|
|
9428
|
+
* device; on an existing device it `add`s a capability the device lacks, or
|
|
9429
|
+
* `replace`s named fields of one it has natively.
|
|
9430
|
+
*/
|
|
9431
|
+
var CompositionFeatureModeSchema = zod.z.enum([
|
|
9432
|
+
"new",
|
|
9433
|
+
"add",
|
|
9434
|
+
"replace"
|
|
9435
|
+
]);
|
|
9436
|
+
var CompositionFeaturePlanSchema = zod.z.object({
|
|
9437
|
+
featureIndex: zod.z.number().int().nonnegative(),
|
|
9438
|
+
cap: zod.z.string(),
|
|
9439
|
+
mode: CompositionFeatureModeSchema
|
|
10371
9440
|
});
|
|
10372
9441
|
var CompositionValidationSchema = zod.z.object({
|
|
10373
9442
|
ok: zod.z.boolean(),
|
|
10374
9443
|
problems: zod.z.array(CompositionProblemSchema),
|
|
10375
|
-
fields: zod.z.array(CompositionFieldPlanSchema)
|
|
9444
|
+
fields: zod.z.array(CompositionFieldPlanSchema),
|
|
9445
|
+
features: zod.z.array(CompositionFeaturePlanSchema)
|
|
10376
9446
|
});
|
|
10377
|
-
/**
|
|
9447
|
+
/**
|
|
9448
|
+
* Mirrors `CoreBlockStatus`, pinned by `core-blocks-source.spec.ts`. `degraded`:
|
|
9449
|
+
* running, but a replaced field is released to the native provider while its
|
|
9450
|
+
* source is unavailable (ruling S1b, D663) — the reason names each such field.
|
|
9451
|
+
*/
|
|
10378
9452
|
var CompositionRunStatusSchema = zod.z.enum([
|
|
10379
9453
|
"stopped",
|
|
10380
9454
|
"starting",
|
|
10381
9455
|
"running",
|
|
9456
|
+
"degraded",
|
|
10382
9457
|
"failed"
|
|
10383
9458
|
]);
|
|
10384
9459
|
var CompositionFieldStateKindSchema = zod.z.enum([
|
|
@@ -10389,6 +9464,8 @@ var CompositionFieldStateKindSchema = zod.z.enum([
|
|
|
10389
9464
|
var CompositionFieldStateSchema = zod.z.object({
|
|
10390
9465
|
cap: zod.z.string(),
|
|
10391
9466
|
path: zod.z.string(),
|
|
9467
|
+
/** Same as the plan's: two items' `status` are told apart by it. */
|
|
9468
|
+
item: CompositionFieldItemSchema.optional(),
|
|
10392
9469
|
state: CompositionFieldStateKindSchema,
|
|
10393
9470
|
/** `null` whenever `state === 'unavailable'`; never a plausible stand-in (D393). */
|
|
10394
9471
|
value: zod.z.union([
|
|
@@ -10470,11 +9547,14 @@ function coreBlockIdFromAddonId(addonId) {
|
|
|
10470
9547
|
* agent is the reason placement is not fixed to the hub. */
|
|
10471
9548
|
var CoreBlockPlacementSchema = zod.z.union([zod.z.literal("hub"), zod.z.string().min(1)]);
|
|
10472
9549
|
/** What a block's process is doing. Mirrors the addon runner's own lifecycle so
|
|
10473
|
-
* a failing block reads the same way a failing addon does.
|
|
9550
|
+
* a failing block reads the same way a failing addon does. `degraded` is a
|
|
9551
|
+
* composition on an existing device with a field handed back to the native
|
|
9552
|
+
* provider while its source is unavailable (S1b, D663); the error names it. */
|
|
10474
9553
|
var CoreBlockStatusSchema = zod.z.enum([
|
|
10475
9554
|
"stopped",
|
|
10476
9555
|
"starting",
|
|
10477
9556
|
"running",
|
|
9557
|
+
"degraded",
|
|
10478
9558
|
"failed"
|
|
10479
9559
|
]);
|
|
10480
9560
|
/** Client-authored fields. */
|
|
@@ -10507,14 +9587,21 @@ var CoreBlockSourceSchema = zod.z.discriminatedUnion("kind", [
|
|
|
10507
9587
|
}),
|
|
10508
9588
|
zod.z.object({
|
|
10509
9589
|
kind: zod.z.literal("composition"),
|
|
10510
|
-
composition: CompositionSchema
|
|
9590
|
+
composition: require_composition.CompositionSchema
|
|
10511
9591
|
})
|
|
10512
9592
|
]);
|
|
10513
|
-
/**
|
|
9593
|
+
/**
|
|
9594
|
+
* The client-authored half of a composition block. No `code`, no placement (hub-only; Phase 7).
|
|
9595
|
+
*
|
|
9596
|
+
* `name`: REQUIRED for a `new` target — the block's name IS the device's name
|
|
9597
|
+
* (D659). ABSENT for an `existing` target — a customization has no name of its
|
|
9598
|
+
* own; the server derives one (`customizationBlockName`, D663) and refuses a
|
|
9599
|
+
* client-sent name by name.
|
|
9600
|
+
*/
|
|
10514
9601
|
var CompositionBlockInputSchema = zod.z.object({
|
|
10515
|
-
name: zod.z.string().min(1).max(120),
|
|
9602
|
+
name: zod.z.string().min(1).max(120).optional(),
|
|
10516
9603
|
enabled: zod.z.boolean(),
|
|
10517
|
-
composition: CompositionSchema
|
|
9604
|
+
composition: require_composition.CompositionSchema
|
|
10518
9605
|
});
|
|
10519
9606
|
/** A stored block. */
|
|
10520
9607
|
var CoreBlockSchema = CoreBlockInputSchema.extend({
|
|
@@ -10571,6 +9658,11 @@ var CompositionGetReadSchema = zod.z.discriminatedUnion("state", [zod.z.object({
|
|
|
10571
9658
|
state: zod.z.literal("loaded"),
|
|
10572
9659
|
view: CompositionViewSchema.nullable()
|
|
10573
9660
|
}), CompositionsNotLoadedSchema]);
|
|
9661
|
+
/** The customization of one existing device, found by its TARGET, or `not-loaded` (D315). */
|
|
9662
|
+
var CompositionCustomizationReadSchema = zod.z.discriminatedUnion("state", [zod.z.object({
|
|
9663
|
+
state: zod.z.literal("loaded"),
|
|
9664
|
+
view: CompositionViewSchema.nullable()
|
|
9665
|
+
}), CompositionsNotLoadedSchema]);
|
|
10574
9666
|
/** What a compile attempt produced. */
|
|
10575
9667
|
var CoreBlockCompileResultSchema = zod.z.object({
|
|
10576
9668
|
ok: zod.z.boolean(),
|
|
@@ -10681,11 +9773,19 @@ var coreBlocksCapability = {
|
|
|
10681
9773
|
getComposition: require_sleep.method(zod.z.object({ blockId: zod.z.string() }), CompositionGetReadSchema, { auth: "admin" }),
|
|
10682
9774
|
listCompositions: require_sleep.method(zod.z.object({}), CompositionListReadSchema, { auth: "admin" }),
|
|
10683
9775
|
/**
|
|
9776
|
+
* The composition that customizes an existing device (D663), found by its
|
|
9777
|
+
* TARGET — never by the block's derived name. One per device at most.
|
|
9778
|
+
*/
|
|
9779
|
+
getCustomization: require_sleep.method(zod.z.object({
|
|
9780
|
+
addonId: zod.z.string().min(1),
|
|
9781
|
+
stableId: zod.z.string().min(1)
|
|
9782
|
+
}), CompositionCustomizationReadSchema, { auth: "admin" }),
|
|
9783
|
+
/**
|
|
10684
9784
|
* Validate without saving — the same verdict the save reaches. A mutation
|
|
10685
9785
|
* for its body size; it writes nothing, so its access is `view`.
|
|
10686
9786
|
*/
|
|
10687
9787
|
validateComposition: require_sleep.method(zod.z.object({
|
|
10688
|
-
composition: CompositionSchema,
|
|
9788
|
+
composition: require_composition.CompositionSchema,
|
|
10689
9789
|
blockId: zod.z.string().optional()
|
|
10690
9790
|
}), CompositionValidationSchema, {
|
|
10691
9791
|
kind: "mutation",
|
|
@@ -10704,13 +9804,13 @@ var coreBlocksCapability = {
|
|
|
10704
9804
|
* and reads their state for the API. Nothing else talks to it.
|
|
10705
9805
|
*/
|
|
10706
9806
|
/** The composer's runner id, `resolveRunnerId(decl, 'composer')`; pinned by `composer-manifest.spec.ts`. */
|
|
10707
|
-
var COMPOSER_RUNNER_ID = COMPOSER_ADDON_ID;
|
|
9807
|
+
var COMPOSER_RUNNER_ID = require_composition.COMPOSER_ADDON_ID;
|
|
10708
9808
|
var ComposerBlockSchema = zod.z.object({
|
|
10709
9809
|
id: zod.z.string().min(1),
|
|
10710
9810
|
name: zod.z.string().min(1).max(120),
|
|
10711
9811
|
enabled: zod.z.boolean(),
|
|
10712
9812
|
updatedAt: zod.z.number(),
|
|
10713
|
-
composition: CompositionSchema
|
|
9813
|
+
composition: require_composition.CompositionSchema
|
|
10714
9814
|
});
|
|
10715
9815
|
/**
|
|
10716
9816
|
* A stored composition row that no longer PARSES — a schema a release
|
|
@@ -11660,7 +10760,7 @@ var detectionPipelineCapability = {
|
|
|
11660
10760
|
mode: "singleton",
|
|
11661
10761
|
kind: "wrapper",
|
|
11662
10762
|
defaultActive: true,
|
|
11663
|
-
deviceTypes: [
|
|
10763
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
11664
10764
|
exposesDeviceSettings: true,
|
|
11665
10765
|
methods: {}
|
|
11666
10766
|
};
|
|
@@ -12093,7 +11193,7 @@ var DiscoveredChildDeviceSchema = zod.z.lazy(() => zod.z.object({
|
|
|
12093
11193
|
/** Friendly name as reported by the source (Reolink camera name, ONVIF profile, ...). */
|
|
12094
11194
|
name: zod.z.string(),
|
|
12095
11195
|
/** DeviceType the child should be created with on adopt. */
|
|
12096
|
-
type: zod.z.enum(
|
|
11196
|
+
type: zod.z.enum(require_err_msg.DeviceType),
|
|
12097
11197
|
status: DiscoveredChildStatusSchema,
|
|
12098
11198
|
/** Free-form integration-specific metadata surfaced in the panel. */
|
|
12099
11199
|
metadata: zod.z.object({
|
|
@@ -12149,7 +11249,7 @@ var deviceDiscoveryCapability = {
|
|
|
12149
11249
|
scope: "device",
|
|
12150
11250
|
deviceNative: true,
|
|
12151
11251
|
mode: "singleton",
|
|
12152
|
-
deviceTypes: [
|
|
11252
|
+
deviceTypes: [require_err_msg.DeviceType.Hub],
|
|
12153
11253
|
status: {
|
|
12154
11254
|
schema: DeviceDiscoveryStatusSchema,
|
|
12155
11255
|
kind: "poll"
|
|
@@ -12751,7 +11851,7 @@ var DiscoveredDeviceSchema = zod.z.object({
|
|
|
12751
11851
|
*/
|
|
12752
11852
|
var DiscoveryCandidateSchema = zod.z.object({
|
|
12753
11853
|
stableId: zod.z.string(),
|
|
12754
|
-
type: zod.z.enum(
|
|
11854
|
+
type: zod.z.enum(require_err_msg.DeviceType),
|
|
12755
11855
|
suggestedName: zod.z.string(),
|
|
12756
11856
|
prefilledConfig: zod.z.record(zod.z.string(), zod.z.unknown()),
|
|
12757
11857
|
/**
|
|
@@ -12888,7 +11988,7 @@ var deviceProviderCapability = {
|
|
|
12888
11988
|
* provider does not support manual creation. Lets the Add-Device dialog
|
|
12889
11989
|
* pick the right type instead of assuming Camera.
|
|
12890
11990
|
*/
|
|
12891
|
-
getManualCreationType: require_sleep.method(zod.z.object({}), zod.z.object({ deviceType: zod.z.enum(
|
|
11991
|
+
getManualCreationType: require_sleep.method(zod.z.object({}), zod.z.object({ deviceType: zod.z.enum(require_err_msg.DeviceType).nullable() })),
|
|
12892
11992
|
adoptDiscoveredDevice: require_sleep.method(zod.z.object({ candidate: DiscoveryCandidateSchema }), DeviceSummarySchema, {
|
|
12893
11993
|
kind: "mutation",
|
|
12894
11994
|
auth: "admin"
|
|
@@ -12900,9 +12000,9 @@ var deviceProviderCapability = {
|
|
|
12900
12000
|
* devices of that type. The output is a `ConfigUISchema` — the
|
|
12901
12001
|
* router type-asserts it at the boundary.
|
|
12902
12002
|
*/
|
|
12903
|
-
getChildCreationSchema: require_sleep.method(zod.z.object({ type: zod.z.enum(
|
|
12003
|
+
getChildCreationSchema: require_sleep.method(zod.z.object({ type: zod.z.enum(require_err_msg.DeviceType) }), CreationSchemaOutputSchema),
|
|
12904
12004
|
createDevice: require_sleep.method(zod.z.object({
|
|
12905
|
-
type: zod.z.enum(
|
|
12005
|
+
type: zod.z.enum(require_err_msg.DeviceType),
|
|
12906
12006
|
config: zod.z.record(zod.z.string(), zod.z.unknown())
|
|
12907
12007
|
}), DeviceSummarySchema, {
|
|
12908
12008
|
kind: "mutation",
|
|
@@ -12921,7 +12021,7 @@ var deviceProviderCapability = {
|
|
|
12921
12021
|
* for backwards compatibility; providers free to ignore it.
|
|
12922
12022
|
*/
|
|
12923
12023
|
testCreationField: require_sleep.method(zod.z.object({
|
|
12924
|
-
type: zod.z.enum(
|
|
12024
|
+
type: zod.z.enum(require_err_msg.DeviceType),
|
|
12925
12025
|
key: zod.z.string(),
|
|
12926
12026
|
value: zod.z.unknown(),
|
|
12927
12027
|
formValues: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
|
|
@@ -13001,7 +12101,7 @@ var DeviceInfoSchema = zod.z.object({
|
|
|
13001
12101
|
id: zod.z.number(),
|
|
13002
12102
|
stableId: zod.z.string(),
|
|
13003
12103
|
addonId: zod.z.string(),
|
|
13004
|
-
type: zod.z.enum(
|
|
12104
|
+
type: zod.z.enum(require_err_msg.DeviceType),
|
|
13005
12105
|
name: zod.z.string(),
|
|
13006
12106
|
/** Operator-organisational location label. `null` when unset. */
|
|
13007
12107
|
location: zod.z.string().nullable(),
|
|
@@ -13094,7 +12194,7 @@ var LINKED_DEVICES_SLOT = {
|
|
|
13094
12194
|
label: "Linked devices",
|
|
13095
12195
|
description: "Companion devices of this camera: their controls appear with it, and the ones you opt in produce tracked events on it.",
|
|
13096
12196
|
shape: "association",
|
|
13097
|
-
hostDeviceTypes: [
|
|
12197
|
+
hostDeviceTypes: [require_err_msg.DeviceType.Camera],
|
|
13098
12198
|
sourceCaps: "any",
|
|
13099
12199
|
cardinality: "many",
|
|
13100
12200
|
value: LinkedDevicesSlotValueSchema
|
|
@@ -13336,7 +12436,7 @@ var deviceManagerCapability = {
|
|
|
13336
12436
|
* placeholder `'generic'`. */
|
|
13337
12437
|
setType: require_sleep.method(zod.z.object({
|
|
13338
12438
|
deviceId: zod.z.number(),
|
|
13339
|
-
type: zod.z.enum(
|
|
12439
|
+
type: zod.z.enum(require_err_msg.DeviceType)
|
|
13340
12440
|
}), zod.z.void(), {
|
|
13341
12441
|
kind: "mutation",
|
|
13342
12442
|
auth: "admin"
|
|
@@ -13464,7 +12564,7 @@ var deviceManagerCapability = {
|
|
|
13464
12564
|
deviceId: zod.z.number(),
|
|
13465
12565
|
name: zod.z.string().optional(),
|
|
13466
12566
|
location: zod.z.string().nullable().optional(),
|
|
13467
|
-
type: zod.z.enum(
|
|
12567
|
+
type: zod.z.enum(require_err_msg.DeviceType).optional(),
|
|
13468
12568
|
integrationId: zod.z.string().optional(),
|
|
13469
12569
|
linkDeviceId: zod.z.number().nullable().optional(),
|
|
13470
12570
|
role: zod.z.string().nullable().optional()
|
|
@@ -14015,12 +13115,12 @@ var deviceManagerCapability = {
|
|
|
14015
13115
|
*/
|
|
14016
13116
|
getCreationSchema: require_sleep.method(zod.z.object({
|
|
14017
13117
|
addonId: zod.z.string(),
|
|
14018
|
-
type: zod.z.enum(
|
|
13118
|
+
type: zod.z.enum(require_err_msg.DeviceType)
|
|
14019
13119
|
}), zod.z.unknown().nullable()),
|
|
14020
13120
|
/** Create a new device via the device-provider capability. */
|
|
14021
13121
|
createDevice: require_sleep.method(zod.z.object({
|
|
14022
13122
|
addonId: zod.z.string(),
|
|
14023
|
-
type: zod.z.enum(
|
|
13123
|
+
type: zod.z.enum(require_err_msg.DeviceType),
|
|
14024
13124
|
config: zod.z.record(zod.z.string(), zod.z.unknown()),
|
|
14025
13125
|
/** Owning integration id, stamped onto the new device's meta by the
|
|
14026
13126
|
* device-manager forwarder so `removeByIntegration` can cascade it.
|
|
@@ -14040,7 +13140,7 @@ var deviceManagerCapability = {
|
|
|
14040
13140
|
*/
|
|
14041
13141
|
testCreationField: require_sleep.method(zod.z.object({
|
|
14042
13142
|
addonId: zod.z.string(),
|
|
14043
|
-
type: zod.z.enum(
|
|
13143
|
+
type: zod.z.enum(require_err_msg.DeviceType),
|
|
14044
13144
|
key: zod.z.string(),
|
|
14045
13145
|
value: zod.z.unknown(),
|
|
14046
13146
|
formValues: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
|
|
@@ -14135,7 +13235,7 @@ var deviceManagerCapability = {
|
|
|
14135
13235
|
}),
|
|
14136
13236
|
/** The device type a provider creates via manual add (Camera/Container/Hub),
|
|
14137
13237
|
* so the Add-Device dialog uses the right type instead of assuming Camera. */
|
|
14138
|
-
providerCreationType: require_sleep.method(zod.z.object({ addonId: zod.z.string() }), zod.z.object({ deviceType: zod.z.enum(
|
|
13238
|
+
providerCreationType: require_sleep.method(zod.z.object({ addonId: zod.z.string() }), zod.z.object({ deviceType: zod.z.enum(require_err_msg.DeviceType).nullable() }), { auth: "admin" }),
|
|
14139
13239
|
/** A provider's extra per-scan param form (ConfigUISchema) for the
|
|
14140
13240
|
* per-integration scan, or null when it takes none. */
|
|
14141
13241
|
providerDiscoveryParamsSchema: require_sleep.method(zod.z.object({ addonId: zod.z.string() }), zod.z.unknown(), { auth: "admin" }),
|
|
@@ -14201,6 +13301,52 @@ var deviceManagerCapability = {
|
|
|
14201
13301
|
//#endregion
|
|
14202
13302
|
//#region src/capabilities/device-state.cap.ts
|
|
14203
13303
|
/**
|
|
13304
|
+
* Per-field ownership (D663). A composition may CLAIM fields of a native
|
|
13305
|
+
* cap's runtime-state slice on an existing device: `replace` overlays the
|
|
13306
|
+
* claimed fields on the native slice, `add` builds a slice the device does
|
|
13307
|
+
* not natively have. Declared here — once — so the hub mirror (Task 5) and
|
|
13308
|
+
* the claim methods (Task 6) share one union.
|
|
13309
|
+
*/
|
|
13310
|
+
var FieldClaimModeSchema = zod.z.enum(["replace", "add"]);
|
|
13311
|
+
/** What a claim, patch or release answers. A refusal always names its reason. */
|
|
13312
|
+
var ClaimOutcomeSchema = zod.z.discriminatedUnion("ok", [zod.z.object({
|
|
13313
|
+
ok: zod.z.literal(true),
|
|
13314
|
+
changed: zod.z.boolean()
|
|
13315
|
+
}), zod.z.object({
|
|
13316
|
+
ok: zod.z.literal(false),
|
|
13317
|
+
code: zod.z.enum([
|
|
13318
|
+
"owned-by-other",
|
|
13319
|
+
"not-claimed",
|
|
13320
|
+
"field-not-claimed",
|
|
13321
|
+
"invalid-slice",
|
|
13322
|
+
"unknown-device",
|
|
13323
|
+
"row-unreadable",
|
|
13324
|
+
"migration-in-flight"
|
|
13325
|
+
]),
|
|
13326
|
+
message: zod.z.string()
|
|
13327
|
+
})]);
|
|
13328
|
+
/** One claim as `listClaims` reports it. `fields` is the PLANNED set, explicit (ruling S5). */
|
|
13329
|
+
var FieldClaimSchema = zod.z.object({
|
|
13330
|
+
deviceId: zod.z.number(),
|
|
13331
|
+
capName: zod.z.string(),
|
|
13332
|
+
owner: zod.z.string().min(1),
|
|
13333
|
+
mode: FieldClaimModeSchema,
|
|
13334
|
+
fields: zod.z.array(zod.z.string().min(1)).min(1)
|
|
13335
|
+
});
|
|
13336
|
+
/**
|
|
13337
|
+
* What `listClaims` answers. The claims INDEX is a listing projection loaded
|
|
13338
|
+
* from the settings store at boot; until a load has succeeded it is
|
|
13339
|
+
* `not-loaded`, never `[]` — an unanswered question must not look like an
|
|
13340
|
+
* empty answer (D315).
|
|
13341
|
+
*/
|
|
13342
|
+
var ClaimsListingSchema = zod.z.discriminatedUnion("state", [zod.z.object({
|
|
13343
|
+
state: zod.z.literal("loaded"),
|
|
13344
|
+
claims: zod.z.array(FieldClaimSchema)
|
|
13345
|
+
}), zod.z.object({
|
|
13346
|
+
state: zod.z.literal("not-loaded"),
|
|
13347
|
+
reason: zod.z.string()
|
|
13348
|
+
})]);
|
|
13349
|
+
/**
|
|
14204
13350
|
* `deviceState` — generic, cap-agnostic surface for cross-process
|
|
14205
13351
|
* access to per-device runtime state. Read pendant for every cap's
|
|
14206
13352
|
* runtime-state slice + the canonical write entrypoint. Mirrors the
|
|
@@ -14231,8 +13377,12 @@ var deviceStateCapability = {
|
|
|
14231
13377
|
/** Full state snapshot for one device. Empty object if no
|
|
14232
13378
|
* cap-keyed slice has been written yet. */
|
|
14233
13379
|
getSnapshot: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), zod.z.record(zod.z.string(), zod.z.record(zod.z.string(), zod.z.unknown()))),
|
|
14234
|
-
/**
|
|
14235
|
-
*
|
|
13380
|
+
/**
|
|
13381
|
+
* Single cap slice — the EFFECTIVE one: the merge every consumer sees, null
|
|
13382
|
+
* when the slice hasn't been written, the device isn't registered, or a
|
|
13383
|
+
* claim HOLDS the cap (D663). Never the native shadow — that is
|
|
13384
|
+
* `getNativeCapSlice`, admin-only.
|
|
13385
|
+
*/
|
|
14236
13386
|
getCapSlice: require_sleep.method(zod.z.object({
|
|
14237
13387
|
deviceId: zod.z.number(),
|
|
14238
13388
|
capName: zod.z.string()
|
|
@@ -14277,7 +13427,66 @@ var deviceStateCapability = {
|
|
|
14277
13427
|
deviceId: zod.z.number(),
|
|
14278
13428
|
capName: zod.z.string(),
|
|
14279
13429
|
slice: zod.z.record(zod.z.string(), zod.z.unknown())
|
|
14280
|
-
}), zod.z.void(), { kind: "mutation" })
|
|
13430
|
+
}), zod.z.void(), { kind: "mutation" }),
|
|
13431
|
+
/**
|
|
13432
|
+
* Claim `fields` of `capName` on a device for `owner`. The PLANNED field set
|
|
13433
|
+
* is explicit (ruling S5): `values` may be partial and MUST be a subset of
|
|
13434
|
+
* `fields` (else `field-not-claimed`); a claimed field with no value is HELD,
|
|
13435
|
+
* never answered from the native. A re-claim by the same owner REPLACES
|
|
13436
|
+
* `fields` and MERGES `values` — a field dropped from `fields` loses its
|
|
13437
|
+
* value. Another owner's claim → `owned-by-other`.
|
|
13438
|
+
*/
|
|
13439
|
+
claimFields: require_sleep.method(zod.z.object({
|
|
13440
|
+
deviceId: zod.z.number(),
|
|
13441
|
+
capName: zod.z.string(),
|
|
13442
|
+
owner: zod.z.string().min(1),
|
|
13443
|
+
mode: FieldClaimModeSchema,
|
|
13444
|
+
fields: zod.z.array(zod.z.string().min(1)).min(1),
|
|
13445
|
+
values: zod.z.record(zod.z.string(), zod.z.unknown())
|
|
13446
|
+
}), ClaimOutcomeSchema, {
|
|
13447
|
+
kind: "mutation",
|
|
13448
|
+
auth: "admin"
|
|
13449
|
+
}),
|
|
13450
|
+
/**
|
|
13451
|
+
* Write owned values. Every key of `values` must be in the claim's `fields`
|
|
13452
|
+
* (`field-not-claimed`); no claim → `not-claimed`; another owner's →
|
|
13453
|
+
* `owned-by-other`. Partial patches merge (S5); debounced like a native slice.
|
|
13454
|
+
*/
|
|
13455
|
+
patchOwnedFields: require_sleep.method(zod.z.object({
|
|
13456
|
+
deviceId: zod.z.number(),
|
|
13457
|
+
capName: zod.z.string(),
|
|
13458
|
+
owner: zod.z.string().min(1),
|
|
13459
|
+
values: zod.z.record(zod.z.string(), zod.z.unknown())
|
|
13460
|
+
}), ClaimOutcomeSchema, {
|
|
13461
|
+
kind: "mutation",
|
|
13462
|
+
auth: "admin"
|
|
13463
|
+
}),
|
|
13464
|
+
/**
|
|
13465
|
+
* Hand the cap back. A `replace` re-emits the native slice exactly as last
|
|
13466
|
+
* written; an `add` leaves the mirror. `not-claimed` also removes a stale
|
|
13467
|
+
* index entry — the index self-heals through this method.
|
|
13468
|
+
*/
|
|
13469
|
+
releaseClaim: require_sleep.method(zod.z.object({
|
|
13470
|
+
deviceId: zod.z.number(),
|
|
13471
|
+
capName: zod.z.string(),
|
|
13472
|
+
owner: zod.z.string().min(1)
|
|
13473
|
+
}), ClaimOutcomeSchema, {
|
|
13474
|
+
kind: "mutation",
|
|
13475
|
+
auth: "admin"
|
|
13476
|
+
}),
|
|
13477
|
+
/** Every claim the index lists, optionally those whose owner starts with `ownerPrefix`. */
|
|
13478
|
+
listClaims: require_sleep.method(zod.z.object({ ownerPrefix: zod.z.string().optional() }), ClaimsListingSchema, { auth: "admin" }),
|
|
13479
|
+
/**
|
|
13480
|
+
* The NATIVE slice — what the provider wrote, the shadow under a `replace`
|
|
13481
|
+
* claim — for the owner's derived reads. Admin-only (D224, ruled in the
|
|
13482
|
+
* Task 6 review): the shadow is a second truth beside the merge, and the
|
|
13483
|
+
* event channel already refuses it to everyone but the composer; a
|
|
13484
|
+
* protected read of it would hand out what the events withhold.
|
|
13485
|
+
*/
|
|
13486
|
+
getNativeCapSlice: require_sleep.method(zod.z.object({
|
|
13487
|
+
deviceId: zod.z.number(),
|
|
13488
|
+
capName: zod.z.string()
|
|
13489
|
+
}), zod.z.record(zod.z.string(), zod.z.unknown()).nullable(), { auth: "admin" })
|
|
14281
13490
|
},
|
|
14282
13491
|
events: {
|
|
14283
13492
|
/**
|
|
@@ -16269,7 +15478,7 @@ var motionDetectionCapability = {
|
|
|
16269
15478
|
/** Frame-differencing motion analysis over a video stream — only a camera
|
|
16270
15479
|
* produces the frames. Read by the `defaultActive` auto-bind in
|
|
16271
15480
|
* `device-manager.getBindings` to decide which devices it may claim. */
|
|
16272
|
-
deviceTypes: [
|
|
15481
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
16273
15482
|
exposesDeviceSettings: true,
|
|
16274
15483
|
methods: {
|
|
16275
15484
|
analyze: require_sleep.method(zod.z.object({
|
|
@@ -17854,7 +17063,7 @@ var alarmPanelCapability = {
|
|
|
17854
17063
|
scope: "device",
|
|
17855
17064
|
deviceNative: true,
|
|
17856
17065
|
mode: "singleton",
|
|
17857
|
-
deviceTypes: [
|
|
17066
|
+
deviceTypes: [require_err_msg.DeviceType.AlarmPanel],
|
|
17858
17067
|
methods: {
|
|
17859
17068
|
arm: require_sleep.method(zod.z.object({
|
|
17860
17069
|
deviceId: zod.z.number().int().nonnegative(),
|
|
@@ -20814,7 +20023,7 @@ var DeviceSelectorSchema = zod.z.discriminatedUnion("kind", [
|
|
|
20814
20023
|
}),
|
|
20815
20024
|
zod.z.object({
|
|
20816
20025
|
kind: zod.z.literal("types"),
|
|
20817
|
-
types: zod.z.array(zod.z.enum(
|
|
20026
|
+
types: zod.z.array(zod.z.enum(require_err_msg.DeviceType)).min(1)
|
|
20818
20027
|
}),
|
|
20819
20028
|
zod.z.object({
|
|
20820
20029
|
kind: zod.z.literal("locations"),
|
|
@@ -22936,7 +22145,15 @@ var RebuildObjectEmbeddingsInput = zod.z.object({
|
|
|
22936
22145
|
* force is logged at start and finish so a deliberately slow pass reads
|
|
22937
22146
|
* differently from a stalled one.
|
|
22938
22147
|
*/
|
|
22939
|
-
pacingMs: zod.z.number().int().nonnegative().optional()
|
|
22148
|
+
pacingMs: zod.z.number().int().nonnegative().optional(),
|
|
22149
|
+
/**
|
|
22150
|
+
* Re-embed ONLY the tracks whose vector is ALREADY in the pinned model's
|
|
22151
|
+
* space (D664) — the in-space skip inverted. It exists to redo vectors
|
|
22152
|
+
* written from the wrong box, which a normal pass would skip as done
|
|
22153
|
+
* forever. Requires `maxTracks`: a forced pass without a bound is refused
|
|
22154
|
+
* (`force-requires-max-tracks`).
|
|
22155
|
+
*/
|
|
22156
|
+
force: zod.z.boolean().optional()
|
|
22940
22157
|
});
|
|
22941
22158
|
/**
|
|
22942
22159
|
* Result of emptying the CLIP index.
|
|
@@ -22972,6 +22189,7 @@ var WipeObjectEmbeddingsResultSchema = zod.z.object({
|
|
|
22972
22189
|
* - `reads-disagree` — the two reads named different choices.
|
|
22973
22190
|
* - `not-a-clip-model` — the CONFIRMED id has no CLIP metadata, so there is no
|
|
22974
22191
|
* index to fill and no dimension to check against (D649).
|
|
22192
|
+
* - `force-requires-max-tracks` — `force: true` with no `maxTracks` (D664).
|
|
22975
22193
|
*/
|
|
22976
22194
|
var RebuildObjectEmbeddingsRefusalSchema = zod.z.enum([
|
|
22977
22195
|
"stores-unavailable",
|
|
@@ -22979,7 +22197,8 @@ var RebuildObjectEmbeddingsRefusalSchema = zod.z.enum([
|
|
|
22979
22197
|
"method-unavailable",
|
|
22980
22198
|
"read-failed",
|
|
22981
22199
|
"reads-disagree",
|
|
22982
|
-
"not-a-clip-model"
|
|
22200
|
+
"not-a-clip-model",
|
|
22201
|
+
"force-requires-max-tracks"
|
|
22983
22202
|
]);
|
|
22984
22203
|
/**
|
|
22985
22204
|
* Acknowledgement that a rebuild STARTED.
|
|
@@ -23004,11 +22223,32 @@ var RebuildStatusSchema = zod.z.object({
|
|
|
23004
22223
|
running: zod.z.boolean(),
|
|
23005
22224
|
scanned: zod.z.number(),
|
|
23006
22225
|
rebuilt: zod.z.number(),
|
|
23007
|
-
/** Tracks whose key frame is gone — nothing to re-embed from.
|
|
22226
|
+
/** Tracks whose key frame is gone — nothing to re-embed from. Pixels ONLY:
|
|
22227
|
+
* `missingEvent` is its own field since D664, never summed in. */
|
|
23008
22228
|
missingKeyFrame: zod.z.number(),
|
|
23009
|
-
/** Tracks with no
|
|
22229
|
+
/** Tracks with no object event at all (D664). */
|
|
22230
|
+
missingEvent: zod.z.number(),
|
|
22231
|
+
/** Tracks with no box measured on the pixels to cut — see `boxSource.refused`. */
|
|
23010
22232
|
missingBbox: zod.z.number(),
|
|
23011
22233
|
/**
|
|
22234
|
+
* Which rule placed each judged track's box (D664): the key frame row's own
|
|
22235
|
+
* `subjectBox`, `track.positions` at exactly its instant (older key frames),
|
|
22236
|
+
* the event box (a key frame recovered from the recording, at the event's
|
|
22237
|
+
* instant), or `refused` by name — the reasons are in the tagged log lines.
|
|
22238
|
+
*/
|
|
22239
|
+
boxSource: zod.z.object({
|
|
22240
|
+
subjectBox: zod.z.number(),
|
|
22241
|
+
positions: zod.z.number(),
|
|
22242
|
+
event: zod.z.number(),
|
|
22243
|
+
refused: zod.z.number()
|
|
22244
|
+
}),
|
|
22245
|
+
/** Tracks skipped because their vector is already in the pinned space. */
|
|
22246
|
+
alreadyInSpace: zod.z.number(),
|
|
22247
|
+
/** Whether the current / last pass was a `force` pass; `null` before any (D664). */
|
|
22248
|
+
force: zod.z.boolean().nullable(),
|
|
22249
|
+
/** In-space tracks a `force` pass selected for re-embedding. */
|
|
22250
|
+
forcedInSpace: zod.z.number(),
|
|
22251
|
+
/**
|
|
23012
22252
|
* Tracks an executing node REFUSED rather than broke on — an unreadable key
|
|
23013
22253
|
* frame, a step that threw. Separate from `failed` because the remedy is
|
|
23014
22254
|
* different, and because a whole camera silently contributing zero vectors
|
|
@@ -23146,7 +22386,7 @@ var pipelineAnalyticsCapability = {
|
|
|
23146
22386
|
mode: "singleton",
|
|
23147
22387
|
kind: "wrapper",
|
|
23148
22388
|
defaultActive: true,
|
|
23149
|
-
deviceTypes: [
|
|
22389
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
23150
22390
|
exposesDeviceSettings: true,
|
|
23151
22391
|
methods: {
|
|
23152
22392
|
getActiveTracks: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), zod.z.array(TrackSchema).readonly()),
|
|
@@ -24829,7 +24069,7 @@ var zonesCapability = {
|
|
|
24829
24069
|
name: "zones",
|
|
24830
24070
|
scope: "device",
|
|
24831
24071
|
mode: "singleton",
|
|
24832
|
-
deviceTypes: [
|
|
24072
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
24833
24073
|
methods: {
|
|
24834
24074
|
listZones: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), zod.z.array(ZoneSchema).readonly()),
|
|
24835
24075
|
addZone: require_sleep.method(zod.z.object({
|
|
@@ -27811,7 +27051,7 @@ var snapshotCapability = {
|
|
|
27811
27051
|
mode: "singleton",
|
|
27812
27052
|
kind: "wrapper",
|
|
27813
27053
|
defaultActive: true,
|
|
27814
|
-
deviceTypes: [
|
|
27054
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
27815
27055
|
exposesDeviceSettings: true,
|
|
27816
27056
|
methods: {
|
|
27817
27057
|
getSnapshot: require_sleep.method(zod.z.object({
|
|
@@ -28667,7 +27907,7 @@ var streamSignalsCapability = {
|
|
|
28667
27907
|
scope: "device",
|
|
28668
27908
|
deviceNative: true,
|
|
28669
27909
|
mode: "singleton",
|
|
28670
|
-
deviceTypes: Object.values(
|
|
27910
|
+
deviceTypes: Object.values(require_err_msg.DeviceType),
|
|
28671
27911
|
runtimeState: StreamSignalsStatusSchema,
|
|
28672
27912
|
/**
|
|
28673
27913
|
* Runtime-state durability: **session** — mirrored in RAM, never written.
|
|
@@ -30166,7 +29406,7 @@ var videoclipsCapability = {
|
|
|
30166
29406
|
/** A clip is a window over a camera's footage — the cap is meaningless on a
|
|
30167
29407
|
* sensor, a button or an event emitter, and the `defaultActive` auto-bind
|
|
30168
29408
|
* reads this to decide which devices it may claim. */
|
|
30169
|
-
deviceTypes: [
|
|
29409
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
30170
29410
|
/**
|
|
30171
29411
|
* The Clips section of a camera's device details is FRAMEWORK-DERIVED (D14):
|
|
30172
29412
|
* the aggregator turns this declaration into the `type:'widget'` section and
|
|
@@ -30760,7 +30000,7 @@ var DOORBELL_SOURCE_SLOT = {
|
|
|
30760
30000
|
label: "Doorbell trigger devices",
|
|
30761
30001
|
description: "Any of these becoming active rings this camera's virtual doorbell: a binary sensor when it goes active, a switch when it turns on.",
|
|
30762
30002
|
shape: "association",
|
|
30763
|
-
hostDeviceTypes: [
|
|
30003
|
+
hostDeviceTypes: [require_err_msg.DeviceType.Camera],
|
|
30764
30004
|
sourceCaps: SOURCE_CAPS,
|
|
30765
30005
|
cardinality: "many",
|
|
30766
30006
|
value: DoorbellSourceSlotValueSchema
|
|
@@ -30772,7 +30012,7 @@ var doorbellCapability = {
|
|
|
30772
30012
|
mode: "singleton",
|
|
30773
30013
|
kind: "wrapper",
|
|
30774
30014
|
defaultActive: false,
|
|
30775
|
-
deviceTypes: [
|
|
30015
|
+
deviceTypes: [require_err_msg.DeviceType.Button, require_err_msg.DeviceType.Camera],
|
|
30776
30016
|
extensionSlots: [DOORBELL_SOURCE_SLOT],
|
|
30777
30017
|
methods: {},
|
|
30778
30018
|
events: {
|
|
@@ -30820,29 +30060,28 @@ var EXTENSION_SLOTS = {
|
|
|
30820
30060
|
"doorbell-source": {
|
|
30821
30061
|
descriptor: DOORBELL_SOURCE_SLOT,
|
|
30822
30062
|
declaringCap: "doorbell",
|
|
30823
|
-
hostDeviceTypes: [
|
|
30063
|
+
hostDeviceTypes: [require_err_msg.DeviceType.Camera]
|
|
30824
30064
|
},
|
|
30825
30065
|
"linked-devices": {
|
|
30826
30066
|
descriptor: LINKED_DEVICES_SLOT,
|
|
30827
30067
|
declaringCap: "device-manager",
|
|
30828
|
-
hostDeviceTypes: [
|
|
30068
|
+
hostDeviceTypes: [require_err_msg.DeviceType.Camera]
|
|
30829
30069
|
}
|
|
30830
30070
|
};
|
|
30831
30071
|
/** A slot's editable value, discriminated on `slot`. */
|
|
30832
30072
|
var ExtensionSlotValueSchema = zod.z.discriminatedUnion("slot", [DoorbellSourceSlotValueSchema.extend({ slot: zod.z.literal("doorbell-source") }), LinkedDevicesSlotValueSchema.extend({ slot: zod.z.literal("linked-devices") })]);
|
|
30833
30073
|
/** Every device type at least one slot is offered on — `device-extension`'s `deviceTypes`. */
|
|
30834
|
-
var EXTENSION_HOST_DEVICE_TYPES = [
|
|
30074
|
+
var EXTENSION_HOST_DEVICE_TYPES = [require_err_msg.DeviceType.Camera];
|
|
30835
30075
|
//#endregion
|
|
30836
30076
|
//#region src/capabilities/device-extension.cap.ts
|
|
30837
30077
|
/**
|
|
30838
30078
|
* `device-extension` — ONE place to see and author what a device is extended
|
|
30839
30079
|
* with by OTHER devices (D648).
|
|
30840
30080
|
*
|
|
30841
|
-
* **A contract, not a store.** Every slot (`linked-devices`,
|
|
30842
|
-
*
|
|
30843
|
-
*
|
|
30844
|
-
*
|
|
30845
|
-
* path. This cap persists nothing and has no config method (guarded by
|
|
30081
|
+
* **A contract, not a store.** Every slot (`linked-devices`, `doorbell-source`)
|
|
30082
|
+
* is declared by the cap that owns the function (`extensionSlots` in its
|
|
30083
|
+
* `*.cap.ts`, D4) and SERVED by the addon that already owns its store, over
|
|
30084
|
+
* that store and its existing write path. This cap persists nothing and has no config method (guarded by
|
|
30846
30085
|
* `scripts/check-extension-slots.ts`): D62 applied to the whole feature, and
|
|
30847
30086
|
* D3 — no shadow registry.
|
|
30848
30087
|
*
|
|
@@ -30863,6 +30102,11 @@ var EXTENSION_HOST_DEVICE_TYPES = [require_sleep.DeviceType.Camera];
|
|
|
30863
30102
|
* The slot's value travels as the generated discriminated union
|
|
30864
30103
|
* (`ExtensionSlotValue`, keyed on `slot`), so a value under the wrong slot is
|
|
30865
30104
|
* a schema error before it reaches any owner.
|
|
30105
|
+
*
|
|
30106
|
+
* **Associations only.** A slot LISTS other devices on its host. A host that
|
|
30107
|
+
* GAINS a capability from other devices is a composition (D663, amends D648:
|
|
30108
|
+
* the reserved `graft` shape, its `projects` and its `enabled` switch were
|
|
30109
|
+
* retired unimplemented).
|
|
30866
30110
|
*/
|
|
30867
30111
|
/** Separator between the source and the slot id in a `slotRef`. It is the
|
|
30868
30112
|
* D554 routing separator: the dispatcher matches `<source>:` prefixes. */
|
|
@@ -30885,7 +30129,7 @@ var ExtensionSourceSchema = zod.z.object({
|
|
|
30885
30129
|
/**
|
|
30886
30130
|
* How one picked source stands. `missing` — no such device (deleted, or an id
|
|
30887
30131
|
* that never existed); `foreign` — a device the slot's owner cannot read from
|
|
30888
|
-
* (
|
|
30132
|
+
* (a source owned by another addon); `unavailable` — it exists but is not a
|
|
30889
30133
|
* valid source now (a container, which is never a pick). A source in any of
|
|
30890
30134
|
* these states is SHOWN, never silently dropped or re-pointed.
|
|
30891
30135
|
*/
|
|
@@ -30926,10 +30170,6 @@ var ExtensionSlotStateSchema = zod.z.object({
|
|
|
30926
30170
|
slot: ExtensionSlotIdSchema,
|
|
30927
30171
|
/** Names the store written (D62), e.g. `virtual-doorbell:doorbellSources`. */
|
|
30928
30172
|
authority: zod.z.string(),
|
|
30929
|
-
/** graft: its switch. association: null — removing every source is "off". */
|
|
30930
|
-
enabled: zod.z.boolean().nullable(),
|
|
30931
|
-
/** graft: the cap registered on the host. association: null. */
|
|
30932
|
-
projects: zod.z.string().nullable(),
|
|
30933
30173
|
activation: ExtensionSlotActivationSchema.nullable(),
|
|
30934
30174
|
value: ExtensionSlotValueSchema,
|
|
30935
30175
|
sources: zod.z.array(ExtensionSlotSourceSchema),
|
|
@@ -30980,7 +30220,8 @@ var ExtensionCandidatesSchema = zod.z.object({ candidates: zod.z.array(Extension
|
|
|
30980
30220
|
/**
|
|
30981
30221
|
* What a write did. `none` — applied in place. `host` / `parent` — the owner
|
|
30982
30222
|
* reloaded the host (or, for an accessory child, its parent) because the
|
|
30983
|
-
* write changed what the host REGISTERS
|
|
30223
|
+
* write changed what the host REGISTERS. A slot never adds a capability to its
|
|
30224
|
+
* host — that is a composition (D663) — so today's owners answer `none`.
|
|
30984
30225
|
*/
|
|
30985
30226
|
var ExtensionSetResultSchema = zod.z.object({
|
|
30986
30227
|
applied: zod.z.literal(true),
|
|
@@ -31318,7 +30559,7 @@ var webrtcSessionCapability = {
|
|
|
31318
30559
|
kind: "wrapper",
|
|
31319
30560
|
defaultActive: true,
|
|
31320
30561
|
preferredProvider: "stream-broker",
|
|
31321
|
-
deviceTypes: [
|
|
30562
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
31322
30563
|
methods: {
|
|
31323
30564
|
/**
|
|
31324
30565
|
* List available WebRTC streams for a device.
|
|
@@ -31599,18 +30840,18 @@ var accessoriesCapability = {
|
|
|
31599
30840
|
deviceNative: true,
|
|
31600
30841
|
mode: "singleton",
|
|
31601
30842
|
deviceTypes: [
|
|
31602
|
-
|
|
31603
|
-
|
|
31604
|
-
|
|
31605
|
-
|
|
31606
|
-
|
|
31607
|
-
|
|
31608
|
-
|
|
31609
|
-
|
|
31610
|
-
|
|
31611
|
-
|
|
31612
|
-
|
|
31613
|
-
|
|
30843
|
+
require_err_msg.DeviceType.Camera,
|
|
30844
|
+
require_err_msg.DeviceType.Hub,
|
|
30845
|
+
require_err_msg.DeviceType.Switch,
|
|
30846
|
+
require_err_msg.DeviceType.Light,
|
|
30847
|
+
require_err_msg.DeviceType.Sensor,
|
|
30848
|
+
require_err_msg.DeviceType.Thermostat,
|
|
30849
|
+
require_err_msg.DeviceType.Cover,
|
|
30850
|
+
require_err_msg.DeviceType.Lock,
|
|
30851
|
+
require_err_msg.DeviceType.Fan,
|
|
30852
|
+
require_err_msg.DeviceType.MediaPlayer,
|
|
30853
|
+
require_err_msg.DeviceType.AlarmPanel,
|
|
30854
|
+
require_err_msg.DeviceType.Generic
|
|
31614
30855
|
],
|
|
31615
30856
|
methods: {
|
|
31616
30857
|
/**
|
|
@@ -32251,7 +31492,7 @@ var airQualitySensorCapability = {
|
|
|
32251
31492
|
scope: "device",
|
|
32252
31493
|
deviceNative: true,
|
|
32253
31494
|
mode: "singleton",
|
|
32254
|
-
deviceTypes: [
|
|
31495
|
+
deviceTypes: [require_err_msg.DeviceType.Sensor],
|
|
32255
31496
|
methods: {},
|
|
32256
31497
|
status: {
|
|
32257
31498
|
schema: AirQualitySensorStatusSchema,
|
|
@@ -32295,7 +31536,7 @@ var ambientLightSensorCapability = {
|
|
|
32295
31536
|
scope: "device",
|
|
32296
31537
|
deviceNative: true,
|
|
32297
31538
|
mode: "singleton",
|
|
32298
|
-
deviceTypes: [
|
|
31539
|
+
deviceTypes: [require_err_msg.DeviceType.Sensor],
|
|
32299
31540
|
methods: {},
|
|
32300
31541
|
status: {
|
|
32301
31542
|
schema: AmbientLightSensorStatusSchema,
|
|
@@ -32413,7 +31654,7 @@ var audioMetricsCapability = {
|
|
|
32413
31654
|
name: "audio-metrics",
|
|
32414
31655
|
scope: "device",
|
|
32415
31656
|
mode: "singleton",
|
|
32416
|
-
deviceTypes: [
|
|
31657
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
32417
31658
|
methods: {
|
|
32418
31659
|
/** Latest snapshot for this device. Null until the analytics
|
|
32419
31660
|
* pipeline has processed at least one audio window. */
|
|
@@ -32481,7 +31722,7 @@ var automationControlCapability = {
|
|
|
32481
31722
|
scope: "device",
|
|
32482
31723
|
deviceNative: true,
|
|
32483
31724
|
mode: "singleton",
|
|
32484
|
-
deviceTypes: [
|
|
31725
|
+
deviceTypes: [require_err_msg.DeviceType.Automation],
|
|
32485
31726
|
methods: {
|
|
32486
31727
|
enable: require_sleep.method(zod.z.object({ deviceId: zod.z.number().int().nonnegative() }), zod.z.void(), {
|
|
32487
31728
|
kind: "mutation",
|
|
@@ -32607,10 +31848,12 @@ var batteryCapability = {
|
|
|
32607
31848
|
deviceNative: true,
|
|
32608
31849
|
mode: "singleton",
|
|
32609
31850
|
deviceTypes: [
|
|
32610
|
-
|
|
32611
|
-
|
|
32612
|
-
|
|
32613
|
-
|
|
31851
|
+
require_err_msg.DeviceType.Camera,
|
|
31852
|
+
require_err_msg.DeviceType.Sensor,
|
|
31853
|
+
require_err_msg.DeviceType.Button,
|
|
31854
|
+
require_err_msg.DeviceType.Switch,
|
|
31855
|
+
require_err_msg.DeviceType.PetFeeder,
|
|
31856
|
+
require_err_msg.DeviceType.Container
|
|
32614
31857
|
],
|
|
32615
31858
|
methods: {
|
|
32616
31859
|
/**
|
|
@@ -32637,6 +31880,19 @@ wakeForStream: require_sleep.method(zod.z.object({
|
|
|
32637
31880
|
awoke: zod.z.boolean(),
|
|
32638
31881
|
durationMs: zod.z.number()
|
|
32639
31882
|
}), { kind: "mutation" }) },
|
|
31883
|
+
/**
|
|
31884
|
+
* A composed provider (battery ADDED to a pet feeder or container that has
|
|
31885
|
+
* no wake surface) answers `wakeForStream` with the same "unavailable"
|
|
31886
|
+
* result the contract already defines above: "Returns `awoke: false` when
|
|
31887
|
+
* … the cap surface is unavailable." (D663).
|
|
31888
|
+
*/
|
|
31889
|
+
composedMethods: { wakeForStream: {
|
|
31890
|
+
kind: "answer",
|
|
31891
|
+
value: {
|
|
31892
|
+
awoke: false,
|
|
31893
|
+
durationMs: 0
|
|
31894
|
+
}
|
|
31895
|
+
} },
|
|
32640
31896
|
events: {
|
|
32641
31897
|
/**
|
|
32642
31898
|
* Emitted whenever the cached status changes (firmware push OR
|
|
@@ -32652,7 +31908,7 @@ onStatusChanged: { data: zod.z.object({
|
|
|
32652
31908
|
schema: BatteryStatusSchema,
|
|
32653
31909
|
kind: "push",
|
|
32654
31910
|
empty: {
|
|
32655
|
-
percentage:
|
|
31911
|
+
percentage: null,
|
|
32656
31912
|
charging: "unknown",
|
|
32657
31913
|
sleeping: false,
|
|
32658
31914
|
lastUpdated: 0
|
|
@@ -32702,7 +31958,7 @@ var binaryCapability = {
|
|
|
32702
31958
|
scope: "device",
|
|
32703
31959
|
deviceNative: true,
|
|
32704
31960
|
mode: "singleton",
|
|
32705
|
-
deviceTypes: [
|
|
31961
|
+
deviceTypes: [require_err_msg.DeviceType.Sensor],
|
|
32706
31962
|
methods: {},
|
|
32707
31963
|
status: {
|
|
32708
31964
|
schema: BinaryStatusSchema,
|
|
@@ -32745,7 +32001,7 @@ var brightnessCapability = {
|
|
|
32745
32001
|
scope: "device",
|
|
32746
32002
|
deviceNative: true,
|
|
32747
32003
|
mode: "singleton",
|
|
32748
|
-
deviceTypes: [
|
|
32004
|
+
deviceTypes: [require_err_msg.DeviceType.Light],
|
|
32749
32005
|
methods: { setBrightness: require_sleep.method(zod.z.object({
|
|
32750
32006
|
deviceId: zod.z.number().int().nonnegative(),
|
|
32751
32007
|
percentage: zod.z.number().min(0).max(100)
|
|
@@ -32799,7 +32055,7 @@ var buttonCapability = {
|
|
|
32799
32055
|
scope: "device",
|
|
32800
32056
|
deviceNative: true,
|
|
32801
32057
|
mode: "singleton",
|
|
32802
|
-
deviceTypes: [
|
|
32058
|
+
deviceTypes: [require_err_msg.DeviceType.Button],
|
|
32803
32059
|
methods: { press: require_sleep.method(zod.z.object({ deviceId: zod.z.number().int().nonnegative() }), zod.z.void(), {
|
|
32804
32060
|
kind: "mutation",
|
|
32805
32061
|
auth: "protected"
|
|
@@ -32876,7 +32132,7 @@ var cameraCredentialsCapability = {
|
|
|
32876
32132
|
scope: "device",
|
|
32877
32133
|
deviceNative: true,
|
|
32878
32134
|
mode: "singleton",
|
|
32879
|
-
deviceTypes: [
|
|
32135
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
32880
32136
|
methods: {
|
|
32881
32137
|
/**
|
|
32882
32138
|
* Return the camera's full credential bundle for admin consumers.
|
|
@@ -33033,7 +32289,7 @@ var cameraGridLayoutCapability = {
|
|
|
33033
32289
|
scope: "device",
|
|
33034
32290
|
deviceNative: true,
|
|
33035
32291
|
mode: "singleton",
|
|
33036
|
-
deviceTypes: [
|
|
32292
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
33037
32293
|
/**
|
|
33038
32294
|
* The section is built by the ADDON and returned from
|
|
33039
32295
|
* `getDeviceSettingsContribution`, not derived by the framework from a
|
|
@@ -33084,7 +32340,7 @@ var carbonMonoxideCapability = {
|
|
|
33084
32340
|
scope: "device",
|
|
33085
32341
|
deviceNative: true,
|
|
33086
32342
|
mode: "singleton",
|
|
33087
|
-
deviceTypes: [
|
|
32343
|
+
deviceTypes: [require_err_msg.DeviceType.Sensor],
|
|
33088
32344
|
methods: {},
|
|
33089
32345
|
status: {
|
|
33090
32346
|
schema: CarbonMonoxideStatusSchema,
|
|
@@ -33193,7 +32449,7 @@ var climateControlCapability = {
|
|
|
33193
32449
|
scope: "device",
|
|
33194
32450
|
deviceNative: true,
|
|
33195
32451
|
mode: "singleton",
|
|
33196
|
-
deviceTypes: [
|
|
32452
|
+
deviceTypes: [require_err_msg.DeviceType.Thermostat, require_err_msg.DeviceType.Climate],
|
|
33197
32453
|
methods: {
|
|
33198
32454
|
setMode: require_sleep.method(zod.z.object({
|
|
33199
32455
|
deviceId: zod.z.number().int().nonnegative(),
|
|
@@ -33346,7 +32602,7 @@ var colorCapability = {
|
|
|
33346
32602
|
scope: "device",
|
|
33347
32603
|
deviceNative: true,
|
|
33348
32604
|
mode: "singleton",
|
|
33349
|
-
deviceTypes: [
|
|
32605
|
+
deviceTypes: [require_err_msg.DeviceType.Light],
|
|
33350
32606
|
methods: { setColor: require_sleep.method(zod.z.object({
|
|
33351
32607
|
deviceId: zod.z.number().int().nonnegative(),
|
|
33352
32608
|
color: ColorInputSchema
|
|
@@ -33506,7 +32762,7 @@ var connectivityCapability = {
|
|
|
33506
32762
|
scope: "device",
|
|
33507
32763
|
deviceNative: true,
|
|
33508
32764
|
mode: "singleton",
|
|
33509
|
-
deviceTypes: [
|
|
32765
|
+
deviceTypes: [require_err_msg.DeviceType.Sensor],
|
|
33510
32766
|
methods: {},
|
|
33511
32767
|
status: {
|
|
33512
32768
|
schema: ConnectivityStatusSchema,
|
|
@@ -33538,6 +32794,19 @@ var connectivityCapability = {
|
|
|
33538
32794
|
* provider populates it by guessing (no HA inference). The UI renders a
|
|
33539
32795
|
* "No consumables reported" placeholder when `items` is empty.
|
|
33540
32796
|
*/
|
|
32797
|
+
/** Units a remaining-life counter is reported in. Closed: the panel renders
|
|
32798
|
+
* each. */
|
|
32799
|
+
var ConsumableRemainingUnitSchema = zod.z.enum([
|
|
32800
|
+
"days",
|
|
32801
|
+
"hours",
|
|
32802
|
+
"cycles"
|
|
32803
|
+
]);
|
|
32804
|
+
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
32805
|
+
* days). `value` null = unknown (D393). */
|
|
32806
|
+
var ConsumableRemainingSchema = zod.z.object({
|
|
32807
|
+
value: zod.z.number().min(0).nullable(),
|
|
32808
|
+
unit: ConsumableRemainingUnitSchema
|
|
32809
|
+
});
|
|
33541
32810
|
/** A single consumable item. Either a continuous `level` (remaining
|
|
33542
32811
|
* life %) or a discrete `status` may be known — both may be null when a
|
|
33543
32812
|
* provider only knows the item exists. `level` and `status` are not
|
|
@@ -33554,7 +32823,10 @@ var ConsumableItemSchema = zod.z.object({
|
|
|
33554
32823
|
/** Ms epoch of the last replace, when known. */
|
|
33555
32824
|
lastResetAt: zod.z.number().nullable(),
|
|
33556
32825
|
/** Whether `reset()` is meaningful for this item. */
|
|
33557
|
-
resettable: zod.z.boolean()
|
|
32826
|
+
resettable: zod.z.boolean(),
|
|
32827
|
+
/** Remaining life as a count (days/hours/cycles), when a provider reports
|
|
32828
|
+
* it that way instead of — or alongside — `level`. Absent = not reported. */
|
|
32829
|
+
remaining: ConsumableRemainingSchema.optional()
|
|
33558
32830
|
});
|
|
33559
32831
|
var ConsumablesStatusSchema = zod.z.object({
|
|
33560
32832
|
items: zod.z.array(ConsumableItemSchema),
|
|
@@ -33565,7 +32837,7 @@ var consumablesCapability = {
|
|
|
33565
32837
|
scope: "device",
|
|
33566
32838
|
deviceNative: true,
|
|
33567
32839
|
mode: "singleton",
|
|
33568
|
-
deviceTypes: Object.values(
|
|
32840
|
+
deviceTypes: Object.values(require_err_msg.DeviceType),
|
|
33569
32841
|
deviceConfig: { ui: {
|
|
33570
32842
|
kind: "widget",
|
|
33571
32843
|
widgetId: "host/consumables-panel",
|
|
@@ -33584,6 +32856,16 @@ reset: require_sleep.method(zod.z.object({
|
|
|
33584
32856
|
kind: "mutation",
|
|
33585
32857
|
auth: "admin"
|
|
33586
32858
|
}) },
|
|
32859
|
+
/**
|
|
32860
|
+
* A composed consumable (item added to a device with no native consumables
|
|
32861
|
+
* provider) refuses `reset` by name: "Only meaningful when the item's
|
|
32862
|
+
* `resettable` is true" — a composed item is never resettable until
|
|
32863
|
+
* commands (`forward`) arrive in slice 3 (D663).
|
|
32864
|
+
*/
|
|
32865
|
+
composedMethods: { reset: {
|
|
32866
|
+
kind: "refuse",
|
|
32867
|
+
reason: "a composed consumable is not resettable until commands (forward) arrive — slice 3"
|
|
32868
|
+
} },
|
|
33587
32869
|
status: {
|
|
33588
32870
|
schema: ConsumablesStatusSchema,
|
|
33589
32871
|
kind: "push",
|
|
@@ -33648,7 +32930,7 @@ var contactCapability = {
|
|
|
33648
32930
|
scope: "device",
|
|
33649
32931
|
deviceNative: true,
|
|
33650
32932
|
mode: "singleton",
|
|
33651
|
-
deviceTypes: [
|
|
32933
|
+
deviceTypes: [require_err_msg.DeviceType.Sensor],
|
|
33652
32934
|
methods: {},
|
|
33653
32935
|
status: {
|
|
33654
32936
|
schema: ContactStatusSchema,
|
|
@@ -33779,7 +33061,7 @@ var controlCapability = {
|
|
|
33779
33061
|
scope: "device",
|
|
33780
33062
|
deviceNative: true,
|
|
33781
33063
|
mode: "singleton",
|
|
33782
|
-
deviceTypes: [
|
|
33064
|
+
deviceTypes: [require_err_msg.DeviceType.Control],
|
|
33783
33065
|
methods: { setValue: require_sleep.method(zod.z.object({
|
|
33784
33066
|
deviceId: zod.z.number().int().nonnegative(),
|
|
33785
33067
|
control: ControlSetValueInputSchema
|
|
@@ -33851,7 +33133,7 @@ var coverCapability = {
|
|
|
33851
33133
|
scope: "device",
|
|
33852
33134
|
deviceNative: true,
|
|
33853
33135
|
mode: "singleton",
|
|
33854
|
-
deviceTypes: [
|
|
33136
|
+
deviceTypes: [require_err_msg.DeviceType.Cover],
|
|
33855
33137
|
methods: {
|
|
33856
33138
|
open: require_sleep.method(zod.z.object({ deviceId: zod.z.number().int().nonnegative() }), zod.z.void(), {
|
|
33857
33139
|
kind: "mutation",
|
|
@@ -33974,7 +33256,7 @@ var dayNightCapability = {
|
|
|
33974
33256
|
scope: "device",
|
|
33975
33257
|
deviceNative: true,
|
|
33976
33258
|
mode: "singleton",
|
|
33977
|
-
deviceTypes: [
|
|
33259
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
33978
33260
|
deviceConfig: { ui: {
|
|
33979
33261
|
kind: "derived-form",
|
|
33980
33262
|
builderId: "day-night",
|
|
@@ -34099,7 +33381,7 @@ var enumSensorCapability = {
|
|
|
34099
33381
|
scope: "device",
|
|
34100
33382
|
deviceNative: true,
|
|
34101
33383
|
mode: "singleton",
|
|
34102
|
-
deviceTypes: [
|
|
33384
|
+
deviceTypes: [require_err_msg.DeviceType.Sensor],
|
|
34103
33385
|
methods: {},
|
|
34104
33386
|
status: {
|
|
34105
33387
|
schema: EnumSensorStatusSchema,
|
|
@@ -34146,7 +33428,7 @@ var eventEmitterCapability = {
|
|
|
34146
33428
|
scope: "device",
|
|
34147
33429
|
deviceNative: true,
|
|
34148
33430
|
mode: "singleton",
|
|
34149
|
-
deviceTypes: [
|
|
33431
|
+
deviceTypes: [require_err_msg.DeviceType.EventEmitter],
|
|
34150
33432
|
methods: {},
|
|
34151
33433
|
events: { onEvent: { data: EventFireSchema } },
|
|
34152
33434
|
status: {
|
|
@@ -34614,7 +33896,7 @@ var fanControlCapability = {
|
|
|
34614
33896
|
scope: "device",
|
|
34615
33897
|
deviceNative: true,
|
|
34616
33898
|
mode: "singleton",
|
|
34617
|
-
deviceTypes: [
|
|
33899
|
+
deviceTypes: [require_err_msg.DeviceType.Fan],
|
|
34618
33900
|
methods: {
|
|
34619
33901
|
setPercentage: require_sleep.method(zod.z.object({
|
|
34620
33902
|
deviceId: zod.z.number().int().nonnegative(),
|
|
@@ -34768,7 +34050,7 @@ var floodCapability = {
|
|
|
34768
34050
|
scope: "device",
|
|
34769
34051
|
deviceNative: true,
|
|
34770
34052
|
mode: "singleton",
|
|
34771
|
-
deviceTypes: [
|
|
34053
|
+
deviceTypes: [require_err_msg.DeviceType.Sensor],
|
|
34772
34054
|
methods: {},
|
|
34773
34055
|
status: {
|
|
34774
34056
|
schema: FloodStatusSchema,
|
|
@@ -34803,7 +34085,7 @@ var gasCapability = {
|
|
|
34803
34085
|
scope: "device",
|
|
34804
34086
|
deviceNative: true,
|
|
34805
34087
|
mode: "singleton",
|
|
34806
|
-
deviceTypes: [
|
|
34088
|
+
deviceTypes: [require_err_msg.DeviceType.Sensor],
|
|
34807
34089
|
methods: {},
|
|
34808
34090
|
status: {
|
|
34809
34091
|
schema: GasStatusSchema,
|
|
@@ -34865,7 +34147,7 @@ var humidifierCapability = {
|
|
|
34865
34147
|
scope: "device",
|
|
34866
34148
|
deviceNative: true,
|
|
34867
34149
|
mode: "singleton",
|
|
34868
|
-
deviceTypes: [
|
|
34150
|
+
deviceTypes: [require_err_msg.DeviceType.Humidifier],
|
|
34869
34151
|
methods: {
|
|
34870
34152
|
setOn: require_sleep.method(zod.z.object({
|
|
34871
34153
|
deviceId: zod.z.number().int().nonnegative(),
|
|
@@ -34936,7 +34218,7 @@ var humiditySensorCapability = {
|
|
|
34936
34218
|
scope: "device",
|
|
34937
34219
|
deviceNative: true,
|
|
34938
34220
|
mode: "singleton",
|
|
34939
|
-
deviceTypes: [
|
|
34221
|
+
deviceTypes: [require_err_msg.DeviceType.Sensor, require_err_msg.DeviceType.Thermostat],
|
|
34940
34222
|
methods: {},
|
|
34941
34223
|
status: {
|
|
34942
34224
|
schema: HumiditySensorStatusSchema,
|
|
@@ -34982,7 +34264,7 @@ var imageCapability = {
|
|
|
34982
34264
|
scope: "device",
|
|
34983
34265
|
deviceNative: true,
|
|
34984
34266
|
mode: "singleton",
|
|
34985
|
-
deviceTypes: [
|
|
34267
|
+
deviceTypes: [require_err_msg.DeviceType.Image],
|
|
34986
34268
|
methods: {},
|
|
34987
34269
|
status: {
|
|
34988
34270
|
schema: ImageStatusSchema,
|
|
@@ -35130,7 +34412,7 @@ var imageSettingsCapability = {
|
|
|
35130
34412
|
scope: "device",
|
|
35131
34413
|
deviceNative: true,
|
|
35132
34414
|
mode: "singleton",
|
|
35133
|
-
deviceTypes: [
|
|
34415
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
35134
34416
|
deviceConfig: { ui: {
|
|
35135
34417
|
kind: "derived-form",
|
|
35136
34418
|
builderId: "image-settings",
|
|
@@ -35407,7 +34689,7 @@ var intercomCapability = {
|
|
|
35407
34689
|
scope: "device",
|
|
35408
34690
|
deviceNative: true,
|
|
35409
34691
|
mode: "singleton",
|
|
35410
|
-
deviceTypes: [
|
|
34692
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
35411
34693
|
/**
|
|
35412
34694
|
* **Auth tier: `protected` on every method — deliberate, and load-bearing.**
|
|
35413
34695
|
*
|
|
@@ -35613,7 +34895,7 @@ var lawnMowerControlCapability = {
|
|
|
35613
34895
|
scope: "device",
|
|
35614
34896
|
deviceNative: true,
|
|
35615
34897
|
mode: "singleton",
|
|
35616
|
-
deviceTypes: [
|
|
34898
|
+
deviceTypes: [require_err_msg.DeviceType.LawnMower],
|
|
35617
34899
|
methods: {
|
|
35618
34900
|
startMowing: require_sleep.method(zod.z.object({ deviceId: zod.z.number().int().nonnegative() }), zod.z.void(), {
|
|
35619
34901
|
kind: "mutation",
|
|
@@ -36043,7 +35325,7 @@ var lockControlCapability = {
|
|
|
36043
35325
|
scope: "device",
|
|
36044
35326
|
deviceNative: true,
|
|
36045
35327
|
mode: "singleton",
|
|
36046
|
-
deviceTypes: [
|
|
35328
|
+
deviceTypes: [require_err_msg.DeviceType.Lock],
|
|
36047
35329
|
methods: {
|
|
36048
35330
|
lock: require_sleep.method(zod.z.object({
|
|
36049
35331
|
deviceId: zod.z.number().int().nonnegative(),
|
|
@@ -36164,7 +35446,7 @@ var mediaPlayerCapability = {
|
|
|
36164
35446
|
scope: "device",
|
|
36165
35447
|
deviceNative: true,
|
|
36166
35448
|
mode: "singleton",
|
|
36167
|
-
deviceTypes: [
|
|
35449
|
+
deviceTypes: [require_err_msg.DeviceType.MediaPlayer],
|
|
36168
35450
|
methods: {
|
|
36169
35451
|
play: require_sleep.method(zod.z.object({ deviceId: zod.z.number().int().nonnegative() }), zod.z.void(), {
|
|
36170
35452
|
kind: "mutation",
|
|
@@ -36608,7 +35890,7 @@ var motionCapability = {
|
|
|
36608
35890
|
* `snapshot` and every other per-device native cap.
|
|
36609
35891
|
*/
|
|
36610
35892
|
deviceNative: true,
|
|
36611
|
-
deviceTypes: [
|
|
35893
|
+
deviceTypes: [require_err_msg.DeviceType.Camera, require_err_msg.DeviceType.Sensor],
|
|
36612
35894
|
methods: {
|
|
36613
35895
|
/**
|
|
36614
35896
|
* Pull the current motion state synchronously. Convenience shortcut
|
|
@@ -36701,9 +35983,9 @@ var motionTriggerCapability = {
|
|
|
36701
35983
|
deviceNative: true,
|
|
36702
35984
|
mode: "singleton",
|
|
36703
35985
|
deviceTypes: [
|
|
36704
|
-
|
|
36705
|
-
|
|
36706
|
-
|
|
35986
|
+
require_err_msg.DeviceType.Light,
|
|
35987
|
+
require_err_msg.DeviceType.Siren,
|
|
35988
|
+
require_err_msg.DeviceType.Switch
|
|
36707
35989
|
],
|
|
36708
35990
|
methods: { setMotionTrigger: require_sleep.method(zod.z.object({
|
|
36709
35991
|
deviceId: zod.z.number().int().nonnegative(),
|
|
@@ -36776,7 +36058,7 @@ var motionZonesCapability = {
|
|
|
36776
36058
|
scope: "device",
|
|
36777
36059
|
deviceNative: true,
|
|
36778
36060
|
mode: "singleton",
|
|
36779
|
-
deviceTypes: [
|
|
36061
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
36780
36062
|
deviceConfig: { ui: {
|
|
36781
36063
|
kind: "widget",
|
|
36782
36064
|
widgetId: "host/motion-zones-grid",
|
|
@@ -36902,7 +36184,7 @@ var nativeObjectDetectionCapability = {
|
|
|
36902
36184
|
scope: "device",
|
|
36903
36185
|
deviceNative: true,
|
|
36904
36186
|
mode: "singleton",
|
|
36905
|
-
deviceTypes: [
|
|
36187
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
36906
36188
|
methods: {
|
|
36907
36189
|
getOptions: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), NativeObjectDetectionOptionsSchema),
|
|
36908
36190
|
setSettings: require_sleep.method(zod.z.object({
|
|
@@ -37271,7 +36553,7 @@ var navigationCapability = {
|
|
|
37271
36553
|
scope: "device",
|
|
37272
36554
|
deviceNative: true,
|
|
37273
36555
|
mode: "singleton",
|
|
37274
|
-
deviceTypes: [
|
|
36556
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
37275
36557
|
deviceConfig: { ui: {
|
|
37276
36558
|
kind: "widget",
|
|
37277
36559
|
widgetId: "host/navigation-panel",
|
|
@@ -37441,13 +36723,13 @@ var networkLinkCapability = {
|
|
|
37441
36723
|
deviceNative: true,
|
|
37442
36724
|
mode: "singleton",
|
|
37443
36725
|
deviceTypes: [
|
|
37444
|
-
|
|
37445
|
-
|
|
37446
|
-
|
|
37447
|
-
|
|
37448
|
-
|
|
37449
|
-
|
|
37450
|
-
|
|
36726
|
+
require_err_msg.DeviceType.Camera,
|
|
36727
|
+
require_err_msg.DeviceType.Sensor,
|
|
36728
|
+
require_err_msg.DeviceType.Button,
|
|
36729
|
+
require_err_msg.DeviceType.Switch,
|
|
36730
|
+
require_err_msg.DeviceType.Light,
|
|
36731
|
+
require_err_msg.DeviceType.Lock,
|
|
36732
|
+
require_err_msg.DeviceType.Siren
|
|
37451
36733
|
],
|
|
37452
36734
|
methods: {},
|
|
37453
36735
|
events: {
|
|
@@ -37883,7 +37165,7 @@ var notifierCapability = {
|
|
|
37883
37165
|
scope: "device",
|
|
37884
37166
|
deviceNative: true,
|
|
37885
37167
|
mode: "singleton",
|
|
37886
|
-
deviceTypes: [
|
|
37168
|
+
deviceTypes: [require_err_msg.DeviceType.Notifier],
|
|
37887
37169
|
methods: {
|
|
37888
37170
|
send: require_sleep.method(NotifierSendInputSchema, NotifierSendResultSchema, {
|
|
37889
37171
|
kind: "mutation",
|
|
@@ -37965,7 +37247,7 @@ var numericSensorCapability = {
|
|
|
37965
37247
|
scope: "device",
|
|
37966
37248
|
deviceNative: true,
|
|
37967
37249
|
mode: "singleton",
|
|
37968
|
-
deviceTypes: [
|
|
37250
|
+
deviceTypes: [require_err_msg.DeviceType.Sensor],
|
|
37969
37251
|
methods: {},
|
|
37970
37252
|
status: {
|
|
37971
37253
|
schema: NumericSensorStatusSchema,
|
|
@@ -38034,7 +37316,7 @@ var osdCapability = {
|
|
|
38034
37316
|
scope: "device",
|
|
38035
37317
|
deviceNative: true,
|
|
38036
37318
|
mode: "singleton",
|
|
38037
|
-
deviceTypes: [
|
|
37319
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
38038
37320
|
methods: {
|
|
38039
37321
|
/**
|
|
38040
37322
|
* Patch a single overlay by id. Provider handles read-modify-write
|
|
@@ -38410,7 +37692,7 @@ var petFeederCapability = {
|
|
|
38410
37692
|
scope: "device",
|
|
38411
37693
|
deviceNative: true,
|
|
38412
37694
|
mode: "singleton",
|
|
38413
|
-
deviceTypes: [
|
|
37695
|
+
deviceTypes: [require_err_msg.DeviceType.PetFeeder],
|
|
38414
37696
|
methods: {
|
|
38415
37697
|
/**
|
|
38416
37698
|
* Dispense food now. Single-hopper feeders take `grams`; dual-hopper
|
|
@@ -38912,7 +38194,7 @@ var powerMeterCapability = {
|
|
|
38912
38194
|
scope: "device",
|
|
38913
38195
|
deviceNative: true,
|
|
38914
38196
|
mode: "singleton",
|
|
38915
|
-
deviceTypes: [
|
|
38197
|
+
deviceTypes: [require_err_msg.DeviceType.Sensor],
|
|
38916
38198
|
methods: {},
|
|
38917
38199
|
status: {
|
|
38918
38200
|
schema: PowerMeterStatusSchema,
|
|
@@ -38975,7 +38257,7 @@ var presenceCapability = {
|
|
|
38975
38257
|
scope: "device",
|
|
38976
38258
|
deviceNative: true,
|
|
38977
38259
|
mode: "singleton",
|
|
38978
|
-
deviceTypes: [
|
|
38260
|
+
deviceTypes: [require_err_msg.DeviceType.Presence],
|
|
38979
38261
|
methods: {},
|
|
38980
38262
|
status: {
|
|
38981
38263
|
schema: PresenceStatusSchema,
|
|
@@ -39029,7 +38311,7 @@ var pressureSensorCapability = {
|
|
|
39029
38311
|
scope: "device",
|
|
39030
38312
|
deviceNative: true,
|
|
39031
38313
|
mode: "singleton",
|
|
39032
|
-
deviceTypes: [
|
|
38314
|
+
deviceTypes: [require_err_msg.DeviceType.Sensor],
|
|
39033
38315
|
methods: {},
|
|
39034
38316
|
status: {
|
|
39035
38317
|
schema: PressureSensorStatusSchema,
|
|
@@ -39154,7 +38436,7 @@ var privacyMaskCapability = {
|
|
|
39154
38436
|
scope: "device",
|
|
39155
38437
|
deviceNative: true,
|
|
39156
38438
|
mode: "singleton",
|
|
39157
|
-
deviceTypes: [
|
|
38439
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
39158
38440
|
deviceConfig: { ui: {
|
|
39159
38441
|
kind: "widget",
|
|
39160
38442
|
widgetId: "host/privacy-mask-grid",
|
|
@@ -39418,7 +38700,7 @@ var ptzCapability = {
|
|
|
39418
38700
|
scope: "device",
|
|
39419
38701
|
deviceNative: true,
|
|
39420
38702
|
mode: "singleton",
|
|
39421
|
-
deviceTypes: [
|
|
38703
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
39422
38704
|
deviceConfig: { ui: {
|
|
39423
38705
|
kind: "widget",
|
|
39424
38706
|
widgetId: "host/ptz-panel",
|
|
@@ -39650,7 +38932,7 @@ var ptzAutotrackCapability = {
|
|
|
39650
38932
|
*/
|
|
39651
38933
|
kind: "wrapper",
|
|
39652
38934
|
defaultActive: false,
|
|
39653
|
-
deviceTypes: [
|
|
38935
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
39654
38936
|
deviceConfig: { ui: {
|
|
39655
38937
|
kind: "widget",
|
|
39656
38938
|
widgetId: "host/ptz-autotrack",
|
|
@@ -39741,9 +39023,9 @@ var rebootCapability = {
|
|
|
39741
39023
|
deviceNative: true,
|
|
39742
39024
|
mode: "singleton",
|
|
39743
39025
|
deviceTypes: [
|
|
39744
|
-
|
|
39745
|
-
|
|
39746
|
-
|
|
39026
|
+
require_err_msg.DeviceType.Camera,
|
|
39027
|
+
require_err_msg.DeviceType.Sensor,
|
|
39028
|
+
require_err_msg.DeviceType.Switch
|
|
39747
39029
|
],
|
|
39748
39030
|
methods: { reboot: require_sleep.method(zod.z.object({ deviceId: zod.z.number().int().nonnegative() }), zod.z.object({ success: zod.z.literal(true) }), {
|
|
39749
39031
|
kind: "mutation",
|
|
@@ -40023,7 +39305,7 @@ var recordingCapability = {
|
|
|
40023
39305
|
/** Recorded coverage is a property of a camera — the cap is meaningless on a
|
|
40024
39306
|
* sensor, a button or an event emitter, and the `defaultActive` auto-bind
|
|
40025
39307
|
* reads this to decide which devices it may claim. */
|
|
40026
|
-
deviceTypes: [
|
|
39308
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
40027
39309
|
methods: {
|
|
40028
39310
|
/**
|
|
40029
39311
|
* The sources this camera has, WITH the reason any of them cannot answer.
|
|
@@ -41711,7 +40993,7 @@ var recordingOnboardCapability = {
|
|
|
41711
40993
|
scope: "device",
|
|
41712
40994
|
deviceNative: true,
|
|
41713
40995
|
mode: "singleton",
|
|
41714
|
-
deviceTypes: [
|
|
40996
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
41715
40997
|
deviceConfig: { ui: {
|
|
41716
40998
|
kind: "derived-form",
|
|
41717
40999
|
builderId: "recording-onboard",
|
|
@@ -42054,7 +41336,7 @@ var recordingSignalCapability = {
|
|
|
42054
41336
|
scope: "device",
|
|
42055
41337
|
deviceNative: true,
|
|
42056
41338
|
mode: "singleton",
|
|
42057
|
-
deviceTypes: [
|
|
41339
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
42058
41340
|
methods: {
|
|
42059
41341
|
/** The current level, straight from the slice the provider keeps fresh. */
|
|
42060
41342
|
getStatus: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), RecordingSignalStatusSchema) },
|
|
@@ -42373,7 +41655,7 @@ var sceneMonitorCapability = {
|
|
|
42373
41655
|
mode: "singleton",
|
|
42374
41656
|
kind: "wrapper",
|
|
42375
41657
|
defaultActive: true,
|
|
42376
|
-
deviceTypes: [
|
|
41658
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
42377
41659
|
methods: {
|
|
42378
41660
|
listScenes: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), SceneMonitorStatusSchema),
|
|
42379
41661
|
/**
|
|
@@ -42626,7 +41908,7 @@ var scriptRunnerCapability = {
|
|
|
42626
41908
|
scope: "device",
|
|
42627
41909
|
deviceNative: true,
|
|
42628
41910
|
mode: "singleton",
|
|
42629
|
-
deviceTypes: [
|
|
41911
|
+
deviceTypes: [require_err_msg.DeviceType.Script],
|
|
42630
41912
|
methods: {
|
|
42631
41913
|
run: require_sleep.method(zod.z.object({
|
|
42632
41914
|
deviceId: zod.z.number().int().nonnegative(),
|
|
@@ -42684,7 +41966,7 @@ var smokeCapability = {
|
|
|
42684
41966
|
scope: "device",
|
|
42685
41967
|
deviceNative: true,
|
|
42686
41968
|
mode: "singleton",
|
|
42687
|
-
deviceTypes: [
|
|
41969
|
+
deviceTypes: [require_err_msg.DeviceType.Sensor],
|
|
42688
41970
|
methods: {},
|
|
42689
41971
|
status: {
|
|
42690
41972
|
schema: SmokeStatusSchema,
|
|
@@ -42783,7 +42065,7 @@ var streamCatalogCapability = {
|
|
|
42783
42065
|
scope: "device",
|
|
42784
42066
|
deviceNative: true,
|
|
42785
42067
|
mode: "singleton",
|
|
42786
|
-
deviceTypes: [
|
|
42068
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
42787
42069
|
methods: { getCatalog: require_sleep.method(zod.z.object({ deviceId: zod.z.number().int().nonnegative() }), zod.z.array(CamStreamDescriptorSchema).readonly()) },
|
|
42788
42070
|
runtimeState: StreamCatalogStateSchema,
|
|
42789
42071
|
/**
|
|
@@ -42901,7 +42183,7 @@ var streamParamsCapability = {
|
|
|
42901
42183
|
scope: "device",
|
|
42902
42184
|
deviceNative: true,
|
|
42903
42185
|
mode: "singleton",
|
|
42904
|
-
deviceTypes: [
|
|
42186
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
42905
42187
|
deviceConfig: { ui: {
|
|
42906
42188
|
kind: "derived-form",
|
|
42907
42189
|
builderId: "stream-params",
|
|
@@ -43233,9 +42515,9 @@ var switchCapability = {
|
|
|
43233
42515
|
deviceNative: true,
|
|
43234
42516
|
mode: "singleton",
|
|
43235
42517
|
deviceTypes: [
|
|
43236
|
-
|
|
43237
|
-
|
|
43238
|
-
|
|
42518
|
+
require_err_msg.DeviceType.Switch,
|
|
42519
|
+
require_err_msg.DeviceType.Siren,
|
|
42520
|
+
require_err_msg.DeviceType.Light
|
|
43239
42521
|
],
|
|
43240
42522
|
methods: { setState: require_sleep.method(zod.z.object({
|
|
43241
42523
|
deviceId: zod.z.number(),
|
|
@@ -43930,7 +43212,7 @@ var tamperCapability = {
|
|
|
43930
43212
|
scope: "device",
|
|
43931
43213
|
deviceNative: true,
|
|
43932
43214
|
mode: "singleton",
|
|
43933
|
-
deviceTypes: [
|
|
43215
|
+
deviceTypes: [require_err_msg.DeviceType.Sensor],
|
|
43934
43216
|
methods: {},
|
|
43935
43217
|
status: {
|
|
43936
43218
|
schema: TamperStatusSchema,
|
|
@@ -43987,7 +43269,7 @@ var temperatureSensorCapability = {
|
|
|
43987
43269
|
scope: "device",
|
|
43988
43270
|
deviceNative: true,
|
|
43989
43271
|
mode: "singleton",
|
|
43990
|
-
deviceTypes: [
|
|
43272
|
+
deviceTypes: [require_err_msg.DeviceType.Sensor, require_err_msg.DeviceType.Thermostat],
|
|
43991
43273
|
methods: {},
|
|
43992
43274
|
status: {
|
|
43993
43275
|
schema: TemperatureSensorStatusSchema,
|
|
@@ -44074,7 +43356,7 @@ var updateCapability = {
|
|
|
44074
43356
|
scope: "device",
|
|
44075
43357
|
deviceNative: true,
|
|
44076
43358
|
mode: "singleton",
|
|
44077
|
-
deviceTypes: [
|
|
43359
|
+
deviceTypes: [require_err_msg.DeviceType.Update],
|
|
44078
43360
|
methods: { installUpdate: require_sleep.method(zod.z.void(), zod.z.void(), {
|
|
44079
43361
|
kind: "mutation",
|
|
44080
43362
|
auth: "admin"
|
|
@@ -44432,7 +43714,7 @@ var vacuumControlCapability = {
|
|
|
44432
43714
|
scope: "device",
|
|
44433
43715
|
deviceNative: true,
|
|
44434
43716
|
mode: "singleton",
|
|
44435
|
-
deviceTypes: [
|
|
43717
|
+
deviceTypes: [require_err_msg.DeviceType.Vacuum],
|
|
44436
43718
|
methods: {
|
|
44437
43719
|
start: require_sleep.method(zod.z.object({ deviceId: zod.z.number().int().nonnegative() }), zod.z.void(), {
|
|
44438
43720
|
kind: "mutation",
|
|
@@ -44519,7 +43801,7 @@ var valveCapability = {
|
|
|
44519
43801
|
scope: "device",
|
|
44520
43802
|
deviceNative: true,
|
|
44521
43803
|
mode: "singleton",
|
|
44522
|
-
deviceTypes: [
|
|
43804
|
+
deviceTypes: [require_err_msg.DeviceType.Valve],
|
|
44523
43805
|
methods: {
|
|
44524
43806
|
open: require_sleep.method(zod.z.object({ deviceId: zod.z.number().int().nonnegative() }), zod.z.void(), {
|
|
44525
43807
|
kind: "mutation",
|
|
@@ -44574,7 +43856,7 @@ var vibrationCapability = {
|
|
|
44574
43856
|
scope: "device",
|
|
44575
43857
|
deviceNative: true,
|
|
44576
43858
|
mode: "singleton",
|
|
44577
|
-
deviceTypes: [
|
|
43859
|
+
deviceTypes: [require_err_msg.DeviceType.Sensor],
|
|
44578
43860
|
methods: {},
|
|
44579
43861
|
status: {
|
|
44580
43862
|
schema: VibrationStatusSchema,
|
|
@@ -44634,7 +43916,7 @@ var waterHeaterCapability = {
|
|
|
44634
43916
|
scope: "device",
|
|
44635
43917
|
deviceNative: true,
|
|
44636
43918
|
mode: "singleton",
|
|
44637
|
-
deviceTypes: [
|
|
43919
|
+
deviceTypes: [require_err_msg.DeviceType.WaterHeater],
|
|
44638
43920
|
methods: {
|
|
44639
43921
|
setTargetTemp: require_sleep.method(zod.z.object({
|
|
44640
43922
|
deviceId: zod.z.number().int().nonnegative(),
|
|
@@ -44724,7 +44006,7 @@ var weatherCapability = {
|
|
|
44724
44006
|
scope: "device",
|
|
44725
44007
|
deviceNative: true,
|
|
44726
44008
|
mode: "singleton",
|
|
44727
|
-
deviceTypes: [
|
|
44009
|
+
deviceTypes: [require_err_msg.DeviceType.Weather],
|
|
44728
44010
|
methods: {},
|
|
44729
44011
|
status: {
|
|
44730
44012
|
schema: WeatherStatusSchema,
|
|
@@ -44932,7 +44214,7 @@ var zoneAnalyticsCapability = {
|
|
|
44932
44214
|
name: "zone-analytics",
|
|
44933
44215
|
scope: "device",
|
|
44934
44216
|
mode: "singleton",
|
|
44935
|
-
deviceTypes: [
|
|
44217
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
44936
44218
|
methods: {
|
|
44937
44219
|
/** Latest computed occupancy snapshot for this camera. Null when
|
|
44938
44220
|
* the analytics pipeline hasn't seen a frame for this device yet
|
|
@@ -45024,7 +44306,7 @@ var zoneRulesCapability = {
|
|
|
45024
44306
|
name: "zone-rules",
|
|
45025
44307
|
scope: "device",
|
|
45026
44308
|
mode: "singleton",
|
|
45027
|
-
deviceTypes: [
|
|
44309
|
+
deviceTypes: [require_err_msg.DeviceType.Camera],
|
|
45028
44310
|
methods: {
|
|
45029
44311
|
/** Read the full rule list for a given stage (empty when no rules
|
|
45030
44312
|
* are defined yet). */
|
|
@@ -45160,8 +44442,6 @@ function createDeviceExtensionProvider(options) {
|
|
|
45160
44442
|
slotRef: extensionSlotRef(source, slot.slot),
|
|
45161
44443
|
slot: slot.slot,
|
|
45162
44444
|
authority: listing.authority,
|
|
45163
|
-
enabled: listing.enabled,
|
|
45164
|
-
projects: EXTENSION_SLOTS[slot.slot].descriptor.projects ?? null,
|
|
45165
44445
|
activation: listing.activation,
|
|
45166
44446
|
value: listing.value,
|
|
45167
44447
|
sources: [...listing.sources],
|
|
@@ -45196,44 +44476,68 @@ function createDeviceExtensionProvider(options) {
|
|
|
45196
44476
|
* through another composition, is refused at save by name (spec §2).
|
|
45197
44477
|
*
|
|
45198
44478
|
* The graph is built for ONE save: the CANDIDATE composition (the one being
|
|
45199
|
-
* validated) plus every STORED composition. The candidate
|
|
45200
|
-
*
|
|
45201
|
-
*
|
|
45202
|
-
*
|
|
45203
|
-
*
|
|
45204
|
-
*
|
|
44479
|
+
* validated) plus every STORED composition. The candidate replaces its own old
|
|
44480
|
+
* version, identified BY BLOCK ID wherever it sits in `stored` — whether a save
|
|
44481
|
+
* introduces or removes a cycle must never depend on array order. A DIFFERENT
|
|
44482
|
+
* block targeting the candidate's device is refused by name: one composition
|
|
44483
|
+
* per device (D663). Two different stored peers that (wrongly) target the same
|
|
44484
|
+
* device are corrupted state, not a cycle to resolve by picking one silently;
|
|
44485
|
+
* that is refused by name too (D391).
|
|
44486
|
+
*
|
|
44487
|
+
* A customization of an EXISTING device reads that device's NATIVE value for a
|
|
44488
|
+
* field it replaces or does not write ("Invert state" reads the `on` it
|
|
44489
|
+
* replaces): such a self-read is no edge, so it is never a cycle (D663).
|
|
44490
|
+
* Another composition reading that field reads the customizer's output.
|
|
45205
44491
|
*
|
|
45206
44492
|
* `findCompositionCycles` reports at least one cycle per cycle-SET (the DFS
|
|
45207
|
-
* marks a node `done` after its first expansion) —
|
|
45208
|
-
*
|
|
44493
|
+
* marks a node `done` after its first expansion) — not every elementary cycle
|
|
44494
|
+
* through a shared node, so the path it names may AVOID the candidate while
|
|
44495
|
+
* one through it goes unreported. What a save refuses is therefore decided per
|
|
44496
|
+
* strongly connected component (`findCandidateCycles`, C-1). A dotted
|
|
45209
44497
|
* `fieldPath` is matched only as an exact string: a write to `state.value` and
|
|
45210
44498
|
* a read of `state` would not connect (no nested field writes exist yet).
|
|
44499
|
+
*
|
|
44500
|
+
* An item leaf is its own node, `…#consumables.items[desiccant].status`
|
|
44501
|
+
* (`featureFieldEntries`), so two items sharing an inner path never merge. No
|
|
44502
|
+
* READ can name an array element (`describeStateField` never describes one),
|
|
44503
|
+
* so an item node is write-only: its edges to sources are what the check needs.
|
|
45211
44504
|
*/
|
|
45212
|
-
/** Two
|
|
44505
|
+
/** Two blocks' compositions target the same device — refused by name, never silently resolved. */
|
|
45213
44506
|
var CompositionGraphError = class extends Error {};
|
|
44507
|
+
/** `"cap.field"` of every field a peer writes — the same spelling as `compositionFieldKey`. */
|
|
44508
|
+
function writtenFields(peer) {
|
|
44509
|
+
return new Set(peer.composition.features.flatMap((feature) => feature.kind !== "fields" ? [] : require_composition.featureFieldEntries(feature).map(({ fieldPath }) => `${feature.cap}.${fieldPath}`)));
|
|
44510
|
+
}
|
|
44511
|
+
/** A read of the peer's OWN device is an edge only when it reads the peer's own output (rule 5, D663). */
|
|
44512
|
+
function readsComposedValue(peer, written, read) {
|
|
44513
|
+
if (require_composition.compositionSourceKey(read.source) !== require_composition.compositionSourceKey(peer.target)) return true;
|
|
44514
|
+
const field = `${read.cap}.${read.fieldPath}`;
|
|
44515
|
+
return written.has(field) && peer.replaced?.has(field) !== true;
|
|
44516
|
+
}
|
|
45214
44517
|
function peerEdges(peer) {
|
|
45215
|
-
|
|
44518
|
+
const written = writtenFields(peer);
|
|
44519
|
+
return peer.composition.features.flatMap((feature) => feature.kind !== "fields" ? [] : require_composition.featureFieldEntries(feature).map(({ fieldPath, source }) => [require_composition.compositionReadKey({
|
|
45216
44520
|
source: peer.target,
|
|
45217
44521
|
cap: feature.cap,
|
|
45218
|
-
fieldPath
|
|
45219
|
-
}), fieldReads(source).map(compositionReadKey)]));
|
|
44522
|
+
fieldPath
|
|
44523
|
+
}), require_composition.fieldReads(source).filter((read) => readsComposedValue(peer, written, read)).map(require_composition.compositionReadKey)]));
|
|
45220
44524
|
}
|
|
45221
44525
|
/**
|
|
45222
|
-
* Every peer that actually takes part in the graph: each stored peer minus
|
|
45223
|
-
*
|
|
45224
|
-
*
|
|
45225
|
-
*
|
|
45226
|
-
* candidate
|
|
45227
|
-
* DIFFERENT stored peers (neither of them the candidate's own old version)
|
|
45228
|
-
* target the same device.
|
|
44526
|
+
* Every peer that actually takes part in the graph: each stored peer minus the
|
|
44527
|
+
* candidate's own old version (same block id — the drop happens before any
|
|
44528
|
+
* edge is built, so its old edges never enter the map), plus the candidate
|
|
44529
|
+
* itself, exactly once. Throws {@link CompositionGraphError} when a DIFFERENT
|
|
44530
|
+
* block targets the candidate's device, or two stored peers share a device.
|
|
45229
44531
|
*/
|
|
45230
44532
|
function resolvedPeers(candidate, stored) {
|
|
45231
|
-
const candidateKey = compositionSourceKey(candidate.target);
|
|
44533
|
+
const candidateKey = require_composition.compositionSourceKey(candidate.target);
|
|
45232
44534
|
const survivors = /* @__PURE__ */ new Map();
|
|
45233
44535
|
for (const peer of stored) {
|
|
45234
|
-
|
|
45235
|
-
|
|
45236
|
-
if (
|
|
44536
|
+
if (peer.blockId === candidate.blockId) continue;
|
|
44537
|
+
const key = require_composition.compositionSourceKey(peer.target);
|
|
44538
|
+
if (key === candidateKey) throw new CompositionGraphError(`block \`${peer.blockId}\` and block \`${candidate.blockId}\` both target device \`${key}\` — one composition per device; delete or edit the existing one`);
|
|
44539
|
+
const clash = survivors.get(key);
|
|
44540
|
+
if (clash !== void 0) throw new CompositionGraphError(`two stored compositions (\`${clash.blockId}\`, \`${peer.blockId}\`) both target device \`${key}\` — refusing to build the field graph`);
|
|
45237
44541
|
survivors.set(key, peer);
|
|
45238
44542
|
}
|
|
45239
44543
|
return [...survivors.values(), candidate];
|
|
@@ -45262,172 +44566,215 @@ function findCompositionCycles(candidate, stored) {
|
|
|
45262
44566
|
for (const node of edges.keys()) visit(node, []);
|
|
45263
44567
|
return [...found.values()];
|
|
45264
44568
|
}
|
|
44569
|
+
/** Tarjan's strongly connected components over every node of the graph (sources included). */
|
|
44570
|
+
function stronglyConnected(edges) {
|
|
44571
|
+
const index = /* @__PURE__ */ new Map();
|
|
44572
|
+
const low = /* @__PURE__ */ new Map();
|
|
44573
|
+
const onStack = /* @__PURE__ */ new Set();
|
|
44574
|
+
const stack = [];
|
|
44575
|
+
const components = [];
|
|
44576
|
+
const connect = (node) => {
|
|
44577
|
+
index.set(node, index.size);
|
|
44578
|
+
low.set(node, index.get(node) ?? 0);
|
|
44579
|
+
stack.push(node);
|
|
44580
|
+
onStack.add(node);
|
|
44581
|
+
for (const next of edges.get(node) ?? []) if (!index.has(next)) {
|
|
44582
|
+
connect(next);
|
|
44583
|
+
low.set(node, Math.min(low.get(node) ?? 0, low.get(next) ?? 0));
|
|
44584
|
+
} else if (onStack.has(next)) low.set(node, Math.min(low.get(node) ?? 0, index.get(next) ?? 0));
|
|
44585
|
+
if (low.get(node) !== index.get(node)) return;
|
|
44586
|
+
const component = [];
|
|
44587
|
+
for (let member = stack.pop(); member !== void 0; member = stack.pop()) {
|
|
44588
|
+
onStack.delete(member);
|
|
44589
|
+
component.push(member);
|
|
44590
|
+
if (member === node) break;
|
|
44591
|
+
}
|
|
44592
|
+
components.push(component);
|
|
44593
|
+
};
|
|
44594
|
+
for (const node of edges.keys()) if (!index.has(node)) connect(node);
|
|
44595
|
+
return components;
|
|
44596
|
+
}
|
|
44597
|
+
/** The shortest walk from `start` back to itself inside `component` (one exists: the component has a cycle). */
|
|
44598
|
+
function cycleThrough(start, component, edges) {
|
|
44599
|
+
const parent = /* @__PURE__ */ new Map();
|
|
44600
|
+
const queue = [start];
|
|
44601
|
+
for (let head = 0; head < queue.length; head += 1) {
|
|
44602
|
+
const node = queue[head];
|
|
44603
|
+
if (node === void 0) break;
|
|
44604
|
+
for (const next of edges.get(node) ?? []) {
|
|
44605
|
+
if (next === start) {
|
|
44606
|
+
const chain = [];
|
|
44607
|
+
for (let at = node; at !== void 0 && at !== start; at = parent.get(at)) chain.push(at);
|
|
44608
|
+
return [
|
|
44609
|
+
start,
|
|
44610
|
+
...chain.reverse(),
|
|
44611
|
+
start
|
|
44612
|
+
];
|
|
44613
|
+
}
|
|
44614
|
+
if (!component.has(next) || parent.has(next)) continue;
|
|
44615
|
+
parent.set(next, node);
|
|
44616
|
+
queue.push(next);
|
|
44617
|
+
}
|
|
44618
|
+
}
|
|
44619
|
+
return [start, start];
|
|
44620
|
+
}
|
|
44621
|
+
/**
|
|
44622
|
+
* The cycles THIS save closes, decided per strongly connected component — never
|
|
44623
|
+
* per reported DFS path, which names one back-edge per revisit and can report a
|
|
44624
|
+
* component's cycle by a path that avoids the candidate while the one through it
|
|
44625
|
+
* goes unreported. A component refuses when it holds a candidate node and a
|
|
44626
|
+
* cycle (more than one node, or a self-loop). Components without a candidate
|
|
44627
|
+
* node are not this save's cycles.
|
|
44628
|
+
*/
|
|
44629
|
+
function findCandidateCycles(candidate, stored) {
|
|
44630
|
+
const edges = compositionEdges(candidate, stored);
|
|
44631
|
+
const prefix = `${require_composition.compositionSourceKey(candidate.target)}#`;
|
|
44632
|
+
return stronglyConnected(edges).flatMap((members) => {
|
|
44633
|
+
const start = members.find((n) => n.startsWith(prefix));
|
|
44634
|
+
if (start === void 0) return [];
|
|
44635
|
+
const component = new Set(members);
|
|
44636
|
+
const selfLoop = members.length === 1 && (edges.get(start) ?? []).includes(start);
|
|
44637
|
+
if (members.length === 1 && !selfLoop) return [];
|
|
44638
|
+
return [{
|
|
44639
|
+
path: cycleThrough(start, component, edges),
|
|
44640
|
+
component
|
|
44641
|
+
}];
|
|
44642
|
+
});
|
|
44643
|
+
}
|
|
45265
44644
|
//#endregion
|
|
45266
|
-
//#region src/
|
|
45267
|
-
|
|
45268
|
-
|
|
44645
|
+
//#region src/device/schema-fields.ts
|
|
44646
|
+
/** Unwrap ZodNullable / ZodOptional / ZodDefault wrappers to reach the inner type.
|
|
44647
|
+
* Zod v4 exposes `.unwrap()` on all three wrapper classes. */
|
|
44648
|
+
function unwrapSchema(schema) {
|
|
44649
|
+
let s = schema;
|
|
44650
|
+
while (s instanceof zod.z.ZodNullable || s instanceof zod.z.ZodOptional || s instanceof zod.z.ZodDefault) s = s.unwrap();
|
|
44651
|
+
return s;
|
|
45269
44652
|
}
|
|
45270
|
-
function
|
|
45271
|
-
|
|
45272
|
-
|
|
45273
|
-
|
|
45274
|
-
|
|
45275
|
-
fatal: reading.fatal
|
|
45276
|
-
};
|
|
45277
|
-
return {
|
|
45278
|
-
state: reading.state,
|
|
45279
|
-
value: reading.value,
|
|
45280
|
-
reason: reading.state === "stale" ? `${describeRead(read)}: ${reading.reason}` : null,
|
|
45281
|
-
deadline: null
|
|
44653
|
+
function leafKind(schema) {
|
|
44654
|
+
const s = unwrapSchema(schema);
|
|
44655
|
+
if (s instanceof zod.z.ZodEnum) return {
|
|
44656
|
+
kind: "enum",
|
|
44657
|
+
enumValues: s.options
|
|
45282
44658
|
};
|
|
44659
|
+
if (s instanceof zod.z.ZodNumber) return { kind: "number" };
|
|
44660
|
+
if (s instanceof zod.z.ZodString) return { kind: "string" };
|
|
44661
|
+
if (s instanceof zod.z.ZodBoolean) return { kind: "boolean" };
|
|
44662
|
+
return null;
|
|
45283
44663
|
}
|
|
45284
|
-
|
|
45285
|
-
|
|
45286
|
-
|
|
45287
|
-
|
|
45288
|
-
|
|
45289
|
-
|
|
45290
|
-
|
|
45291
|
-
|
|
45292
|
-
|
|
45293
|
-
|
|
45294
|
-
const
|
|
45295
|
-
|
|
45296
|
-
|
|
45297
|
-
|
|
45298
|
-
value: null,
|
|
45299
|
-
reason: `binding \`${name}\` (${describeRead(binding)}): ${reading.reason}`,
|
|
45300
|
-
fatal: reading.fatal
|
|
45301
|
-
};
|
|
45302
|
-
if (reading.fatal) {
|
|
45303
|
-
fatalUnavailable = outcome;
|
|
45304
|
-
break;
|
|
45305
|
-
}
|
|
45306
|
-
if (nonFatalUnavailable === null) nonFatalUnavailable = outcome;
|
|
44664
|
+
/** Walk a cap status schema into flat wireable leaf fields (dotted paths).
|
|
44665
|
+
* Recurses into nested ZodObject (unwrapping nullable/optional/default first),
|
|
44666
|
+
* so fields with null live values are still offered. Arrays / unknown shapes
|
|
44667
|
+
* are skipped — never throws. */
|
|
44668
|
+
function enumerateSchemaFields(schema, prefix = "") {
|
|
44669
|
+
const root = unwrapSchema(schema);
|
|
44670
|
+
if (!(root instanceof zod.z.ZodObject)) return [];
|
|
44671
|
+
const out = [];
|
|
44672
|
+
const shape = root.shape;
|
|
44673
|
+
for (const [key, field] of Object.entries(shape)) {
|
|
44674
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
44675
|
+
const inner = unwrapSchema(field);
|
|
44676
|
+
if (inner instanceof zod.z.ZodObject) {
|
|
44677
|
+
out.push(...enumerateSchemaFields(inner, path));
|
|
45307
44678
|
continue;
|
|
45308
44679
|
}
|
|
45309
|
-
|
|
45310
|
-
if (
|
|
44680
|
+
const leaf = leafKind(field);
|
|
44681
|
+
if (leaf) out.push({
|
|
44682
|
+
path,
|
|
44683
|
+
kind: leaf.kind,
|
|
44684
|
+
...leaf.enumValues ? { enumValues: leaf.enumValues } : {}
|
|
44685
|
+
});
|
|
45311
44686
|
}
|
|
45312
|
-
|
|
45313
|
-
if (nonFatalUnavailable !== null) return nonFatalUnavailable;
|
|
45314
|
-
const deadlines = [];
|
|
45315
|
-
const result = evaluateExpressionSource(source.expr, values, now, { hooks: { noteDeadline: (at) => deadlines.push(at) } });
|
|
45316
|
-
if (!result.ok) return {
|
|
45317
|
-
state: "unavailable",
|
|
45318
|
-
value: null,
|
|
45319
|
-
reason: `the expression failed: ${result.error}`,
|
|
45320
|
-
fatal: false
|
|
45321
|
-
};
|
|
45322
|
-
return {
|
|
45323
|
-
state: staleReasons.length > 0 ? "stale" : "fresh",
|
|
45324
|
-
value: result.value,
|
|
45325
|
-
reason: staleReasons.length > 0 ? staleReasons.join("; ") : null,
|
|
45326
|
-
deadline: deadlines.length > 0 ? Math.min(...deadlines) : null
|
|
45327
|
-
};
|
|
44687
|
+
return out;
|
|
45328
44688
|
}
|
|
45329
|
-
|
|
45330
|
-
|
|
45331
|
-
|
|
45332
|
-
|
|
45333
|
-
|
|
45334
|
-
|
|
45335
|
-
|
|
45336
|
-
|
|
45337
|
-
|
|
45338
|
-
|
|
45339
|
-
};
|
|
45340
|
-
}
|
|
44689
|
+
/** Enumerate the per-item wireable fields of an item-array cap (see
|
|
44690
|
+
* `CapabilityStatusItemArray`): the item schema's leaf fields, minus the
|
|
44691
|
+
* `keyField` (the key comes from the link's `itemKey`, never from a wired
|
|
44692
|
+
* source), each tagged `item: true` so the authoring UI collects an
|
|
44693
|
+
* `itemKey` alongside the field. Never throws. */
|
|
44694
|
+
function enumerateItemArrayFields(itemArray) {
|
|
44695
|
+
return enumerateSchemaFields(itemArray.itemSchema).filter((f) => f.path !== itemArray.keyField).map((f) => ({
|
|
44696
|
+
...f,
|
|
44697
|
+
item: true
|
|
44698
|
+
}));
|
|
45341
44699
|
}
|
|
45342
44700
|
//#endregion
|
|
45343
|
-
//#region src/composition/
|
|
44701
|
+
//#region src/composition/state-fields.ts
|
|
45344
44702
|
/**
|
|
45345
|
-
*
|
|
45346
|
-
*
|
|
45347
|
-
*
|
|
45348
|
-
* §4 item 4 asked for one).
|
|
44703
|
+
* What a capability's state field IS: kind, nullability, whether required. The
|
|
44704
|
+
* validator needs nullability, which `enumerateSchemaFields` does not report,
|
|
44705
|
+
* and that decides a field's unavailable mode (D393).
|
|
45349
44706
|
*/
|
|
45350
|
-
|
|
45351
|
-
|
|
45352
|
-
{
|
|
45353
|
-
|
|
45354
|
-
|
|
45355
|
-
|
|
45356
|
-
|
|
45357
|
-
|
|
45358
|
-
stableId: "sensor.sofa_temperature"
|
|
45359
|
-
},
|
|
45360
|
-
{
|
|
45361
|
-
addonId: "provider-homeassistant",
|
|
45362
|
-
stableId: "sensor.window_temperature"
|
|
44707
|
+
function fieldAt(schema, path) {
|
|
44708
|
+
let current = schema;
|
|
44709
|
+
for (const segment of path.split(".")) {
|
|
44710
|
+
const container = unwrapSchema(current);
|
|
44711
|
+
if (!(container instanceof zod.z.ZodObject)) return null;
|
|
44712
|
+
const next = container.shape[segment];
|
|
44713
|
+
if (!(next instanceof zod.z.ZodType)) return null;
|
|
44714
|
+
current = next;
|
|
45363
44715
|
}
|
|
45364
|
-
|
|
45365
|
-
|
|
45366
|
-
|
|
45367
|
-
|
|
45368
|
-
|
|
45369
|
-
|
|
45370
|
-
|
|
45371
|
-
}];
|
|
45372
|
-
function from(source, cap, fieldPath) {
|
|
44716
|
+
return current;
|
|
44717
|
+
}
|
|
44718
|
+
function describeStateField(schema, path) {
|
|
44719
|
+
const leaf = enumerateSchemaFields(schema).find((f) => f.path === path);
|
|
44720
|
+
if (leaf === void 0) return null;
|
|
44721
|
+
const field = fieldAt(schema, path);
|
|
44722
|
+
if (field === null) return null;
|
|
45373
44723
|
return {
|
|
45374
|
-
|
|
45375
|
-
|
|
45376
|
-
|
|
45377
|
-
|
|
44724
|
+
path,
|
|
44725
|
+
kind: leaf.kind,
|
|
44726
|
+
nullable: field.safeParse(null).success,
|
|
44727
|
+
required: !field.safeParse(void 0).success,
|
|
44728
|
+
...leaf.enumValues === void 0 ? {} : { enumValues: leaf.enumValues }
|
|
45378
44729
|
};
|
|
45379
44730
|
}
|
|
45380
|
-
function
|
|
45381
|
-
return
|
|
44731
|
+
function describeTopLevelStateFields(schema) {
|
|
44732
|
+
return new Map(enumerateSchemaFields(schema).filter((f) => !f.path.includes(".")).flatMap((f) => {
|
|
44733
|
+
const described = describeStateField(schema, f.path);
|
|
44734
|
+
return described === null ? [] : [[f.path, described]];
|
|
44735
|
+
}));
|
|
45382
44736
|
}
|
|
45383
|
-
|
|
45384
|
-
|
|
45385
|
-
const
|
|
45386
|
-
|
|
45387
|
-
|
|
45388
|
-
|
|
45389
|
-
|
|
45390
|
-
|
|
45391
|
-
|
|
45392
|
-
|
|
45393
|
-
|
|
45394
|
-
|
|
45395
|
-
|
|
45396
|
-
|
|
45397
|
-
|
|
45398
|
-
|
|
45399
|
-
|
|
45400
|
-
expr: `round(avg(${Object.keys(t).join(", ")}), 1)`,
|
|
45401
|
-
bindings: t
|
|
45402
|
-
},
|
|
45403
|
-
lastFetchedAt: {
|
|
45404
|
-
kind: "expression",
|
|
45405
|
-
expr: `max(${Object.keys(f).join(", ")})`,
|
|
45406
|
-
bindings: f
|
|
45407
|
-
}
|
|
45408
|
-
}
|
|
45409
|
-
}, {
|
|
45410
|
-
kind: "fields",
|
|
45411
|
-
cap: "binary",
|
|
45412
|
-
fields: {
|
|
45413
|
-
on: {
|
|
45414
|
-
kind: "expression",
|
|
45415
|
-
expr: `any(${[...Object.keys(d), ...windows].join(", ")})`,
|
|
45416
|
-
bindings: {
|
|
45417
|
-
...d,
|
|
45418
|
-
...m
|
|
45419
|
-
}
|
|
45420
|
-
},
|
|
45421
|
-
lastChangedAt: {
|
|
45422
|
-
kind: "expression",
|
|
45423
|
-
expr: "now",
|
|
45424
|
-
bindings: {}
|
|
45425
|
-
}
|
|
45426
|
-
}
|
|
45427
|
-
}]
|
|
44737
|
+
/** Top-level keys a value MUST carry: those whose schema refuses `undefined`. */
|
|
44738
|
+
function requiredTopLevelKeys(schema) {
|
|
44739
|
+
const root = unwrapSchema(schema);
|
|
44740
|
+
if (!(root instanceof zod.z.ZodObject)) return [];
|
|
44741
|
+
return Object.entries(root.shape).flatMap(([key, field]) => field instanceof zod.z.ZodType && !field.safeParse(void 0).success ? [key] : []);
|
|
44742
|
+
}
|
|
44743
|
+
/**
|
|
44744
|
+
* The proper prefixes of `path` whose schema accepts `undefined`: a required
|
|
44745
|
+
* leaf under one of them is required only once something writes that parent
|
|
44746
|
+
* (`remaining.unit` is required only when `remaining` is present).
|
|
44747
|
+
*/
|
|
44748
|
+
function optionalAncestors(schema, path) {
|
|
44749
|
+
const segments = path.split(".");
|
|
44750
|
+
return segments.slice(0, -1).flatMap((_, i) => {
|
|
44751
|
+
const prefix = segments.slice(0, i + 1).join(".");
|
|
44752
|
+
const field = fieldAt(schema, prefix);
|
|
44753
|
+
return field !== null && field.safeParse(void 0).success ? [prefix] : [];
|
|
45428
44754
|
});
|
|
45429
44755
|
}
|
|
45430
44756
|
//#endregion
|
|
44757
|
+
//#region src/composition/plan-result.ts
|
|
44758
|
+
function problem(code, path, message) {
|
|
44759
|
+
return {
|
|
44760
|
+
code,
|
|
44761
|
+
path,
|
|
44762
|
+
message
|
|
44763
|
+
};
|
|
44764
|
+
}
|
|
44765
|
+
function refused(...problems) {
|
|
44766
|
+
return {
|
|
44767
|
+
problems,
|
|
44768
|
+
fields: [],
|
|
44769
|
+
features: []
|
|
44770
|
+
};
|
|
44771
|
+
}
|
|
44772
|
+
/** Where a planned field sits in the composition: `features[N].fields.<path>` or `features[N].items.<key>.fields.<path>`. */
|
|
44773
|
+
function compositionFieldAt(field) {
|
|
44774
|
+
const inner = field.item === void 0 ? "fields" : `items.${field.item.key}.fields`;
|
|
44775
|
+
return `features[${field.featureIndex}].${inner}.${field.path}`;
|
|
44776
|
+
}
|
|
44777
|
+
//#endregion
|
|
45431
44778
|
//#region src/composition/expression-kinds.ts
|
|
45432
44779
|
var NUMBER = {
|
|
45433
44780
|
kind: "fixed",
|
|
@@ -45459,6 +44806,10 @@ var BUILTIN_RESULT_KINDS = Object.freeze({
|
|
|
45459
44806
|
latest: {
|
|
45460
44807
|
kind: "fixed",
|
|
45461
44808
|
result: ["number", "null"]
|
|
44809
|
+
},
|
|
44810
|
+
number: {
|
|
44811
|
+
kind: "fixed",
|
|
44812
|
+
result: ["number", "null"]
|
|
45462
44813
|
}
|
|
45463
44814
|
});
|
|
45464
44815
|
var KindInferenceError = class extends Error {};
|
|
@@ -45494,7 +44845,7 @@ function arityRange(builtin) {
|
|
|
45494
44845
|
return `${builtin.minArgs}–${builtin.maxArgs}`;
|
|
45495
44846
|
}
|
|
45496
44847
|
function callKinds(callee, args) {
|
|
45497
|
-
const builtin = EXPRESSION_BUILTINS[callee];
|
|
44848
|
+
const builtin = require_composition.EXPRESSION_BUILTINS[callee];
|
|
45498
44849
|
if (builtin !== void 0 && (args.length < builtin.minArgs || args.length > builtin.maxArgs)) throw new KindInferenceError(`${callee}: wrong number of arguments (${args.length}); expected ${arityRange(builtin)}`);
|
|
45499
44850
|
const rule = BUILTIN_RESULT_KINDS[callee];
|
|
45500
44851
|
if (rule === void 0) throw new KindInferenceError(`no result-kind rule for builtin '${callee}'`);
|
|
@@ -45519,7 +44870,7 @@ function kindsOf(node, bindings) {
|
|
|
45519
44870
|
}
|
|
45520
44871
|
}
|
|
45521
44872
|
function inferExpressionKinds(input) {
|
|
45522
|
-
const compiled = compileExpressionSafe(input.expr);
|
|
44873
|
+
const compiled = require_composition.compileExpressionSafe(input.expr);
|
|
45523
44874
|
if (!compiled.ok) return {
|
|
45524
44875
|
ok: false,
|
|
45525
44876
|
error: compiled.error
|
|
@@ -45538,129 +44889,14 @@ function inferExpressionKinds(input) {
|
|
|
45538
44889
|
}
|
|
45539
44890
|
}
|
|
45540
44891
|
//#endregion
|
|
45541
|
-
//#region src/
|
|
45542
|
-
/** Unwrap ZodNullable / ZodOptional / ZodDefault wrappers to reach the inner type.
|
|
45543
|
-
* Zod v4 exposes `.unwrap()` on all three wrapper classes. */
|
|
45544
|
-
function unwrapSchema(schema) {
|
|
45545
|
-
let s = schema;
|
|
45546
|
-
while (s instanceof zod.z.ZodNullable || s instanceof zod.z.ZodOptional || s instanceof zod.z.ZodDefault) s = s.unwrap();
|
|
45547
|
-
return s;
|
|
45548
|
-
}
|
|
45549
|
-
function leafKind(schema) {
|
|
45550
|
-
const s = unwrapSchema(schema);
|
|
45551
|
-
if (s instanceof zod.z.ZodEnum) return {
|
|
45552
|
-
kind: "enum",
|
|
45553
|
-
enumValues: s.options
|
|
45554
|
-
};
|
|
45555
|
-
if (s instanceof zod.z.ZodNumber) return { kind: "number" };
|
|
45556
|
-
if (s instanceof zod.z.ZodString) return { kind: "string" };
|
|
45557
|
-
if (s instanceof zod.z.ZodBoolean) return { kind: "boolean" };
|
|
45558
|
-
return null;
|
|
45559
|
-
}
|
|
45560
|
-
/** Walk a cap status schema into flat wireable leaf fields (dotted paths).
|
|
45561
|
-
* Recurses into nested ZodObject (unwrapping nullable/optional/default first),
|
|
45562
|
-
* so fields with null live values are still offered. Arrays / unknown shapes
|
|
45563
|
-
* are skipped — never throws. */
|
|
45564
|
-
function enumerateSchemaFields(schema, prefix = "") {
|
|
45565
|
-
const root = unwrapSchema(schema);
|
|
45566
|
-
if (!(root instanceof zod.z.ZodObject)) return [];
|
|
45567
|
-
const out = [];
|
|
45568
|
-
const shape = root.shape;
|
|
45569
|
-
for (const [key, field] of Object.entries(shape)) {
|
|
45570
|
-
const path = prefix ? `${prefix}.${key}` : key;
|
|
45571
|
-
const inner = unwrapSchema(field);
|
|
45572
|
-
if (inner instanceof zod.z.ZodObject) {
|
|
45573
|
-
out.push(...enumerateSchemaFields(inner, path));
|
|
45574
|
-
continue;
|
|
45575
|
-
}
|
|
45576
|
-
const leaf = leafKind(field);
|
|
45577
|
-
if (leaf) out.push({
|
|
45578
|
-
path,
|
|
45579
|
-
kind: leaf.kind,
|
|
45580
|
-
...leaf.enumValues ? { enumValues: leaf.enumValues } : {}
|
|
45581
|
-
});
|
|
45582
|
-
}
|
|
45583
|
-
return out;
|
|
45584
|
-
}
|
|
45585
|
-
/** Enumerate the per-item wireable fields of an item-array cap (see
|
|
45586
|
-
* `CapabilityStatusItemArray`): the item schema's leaf fields, minus the
|
|
45587
|
-
* `keyField` (the key comes from the link's `itemKey`, never from a wired
|
|
45588
|
-
* source), each tagged `item: true` so the authoring UI collects an
|
|
45589
|
-
* `itemKey` alongside the field. Never throws. */
|
|
45590
|
-
function enumerateItemArrayFields(itemArray) {
|
|
45591
|
-
return enumerateSchemaFields(itemArray.itemSchema).filter((f) => f.path !== itemArray.keyField).map((f) => ({
|
|
45592
|
-
...f,
|
|
45593
|
-
item: true
|
|
45594
|
-
}));
|
|
45595
|
-
}
|
|
45596
|
-
//#endregion
|
|
45597
|
-
//#region src/composition/state-fields.ts
|
|
44892
|
+
//#region src/composition/field-kinds.ts
|
|
45598
44893
|
/**
|
|
45599
|
-
*
|
|
45600
|
-
*
|
|
45601
|
-
*
|
|
44894
|
+
* The kind half of planning a composition field (D659): which kinds a source
|
|
44895
|
+
* can produce, whether they fit a target field, and the field's role.
|
|
44896
|
+
* Shared by the top-level planner (`validate-composition.ts`) and the item
|
|
44897
|
+
* planner (`composition-items.ts`). Internal to the composition module — NOT
|
|
44898
|
+
* in the barrel: these are planner internals, not a published contract.
|
|
45602
44899
|
*/
|
|
45603
|
-
function fieldAt(schema, path) {
|
|
45604
|
-
let current = schema;
|
|
45605
|
-
for (const segment of path.split(".")) {
|
|
45606
|
-
const container = unwrapSchema(current);
|
|
45607
|
-
if (!(container instanceof zod.z.ZodObject)) return null;
|
|
45608
|
-
const next = container.shape[segment];
|
|
45609
|
-
if (!(next instanceof zod.z.ZodType)) return null;
|
|
45610
|
-
current = next;
|
|
45611
|
-
}
|
|
45612
|
-
return current;
|
|
45613
|
-
}
|
|
45614
|
-
function describeStateField(schema, path) {
|
|
45615
|
-
const leaf = enumerateSchemaFields(schema).find((f) => f.path === path);
|
|
45616
|
-
if (leaf === void 0) return null;
|
|
45617
|
-
const field = fieldAt(schema, path);
|
|
45618
|
-
if (field === null) return null;
|
|
45619
|
-
return {
|
|
45620
|
-
path,
|
|
45621
|
-
kind: leaf.kind,
|
|
45622
|
-
nullable: field.safeParse(null).success,
|
|
45623
|
-
required: !field.safeParse(void 0).success,
|
|
45624
|
-
...leaf.enumValues === void 0 ? {} : { enumValues: leaf.enumValues }
|
|
45625
|
-
};
|
|
45626
|
-
}
|
|
45627
|
-
function describeTopLevelStateFields(schema) {
|
|
45628
|
-
return new Map(enumerateSchemaFields(schema).filter((f) => !f.path.includes(".")).flatMap((f) => {
|
|
45629
|
-
const described = describeStateField(schema, f.path);
|
|
45630
|
-
return described === null ? [] : [[f.path, described]];
|
|
45631
|
-
}));
|
|
45632
|
-
}
|
|
45633
|
-
/** Top-level keys a value MUST carry: those whose schema refuses `undefined`. */
|
|
45634
|
-
function requiredTopLevelKeys(schema) {
|
|
45635
|
-
const root = unwrapSchema(schema);
|
|
45636
|
-
if (!(root instanceof zod.z.ZodObject)) return [];
|
|
45637
|
-
return Object.entries(root.shape).flatMap(([key, field]) => field instanceof zod.z.ZodType && !field.safeParse(void 0).success ? [key] : []);
|
|
45638
|
-
}
|
|
45639
|
-
//#endregion
|
|
45640
|
-
//#region src/composition/validate-composition.ts
|
|
45641
|
-
function buildCapabilityLookup(defs) {
|
|
45642
|
-
const byName = new Map(defs.map((d) => [d.name, d]));
|
|
45643
|
-
return (capName) => byName.get(capName) ?? null;
|
|
45644
|
-
}
|
|
45645
|
-
/** Caps every `BaseDevice` registers on itself; a second registration throws. */
|
|
45646
|
-
var BASE_DEVICE_CAPS = new Set(["device-status", "feature-probe"]);
|
|
45647
|
-
var PENDING_SELF = {
|
|
45648
|
-
addonId: COMPOSER_ADDON_ID,
|
|
45649
|
-
stableId: `${COMPOSED_DEVICE_STABLE_ID_PREFIX}(unsaved)`
|
|
45650
|
-
};
|
|
45651
|
-
function problem(code, path, message) {
|
|
45652
|
-
return {
|
|
45653
|
-
code,
|
|
45654
|
-
path,
|
|
45655
|
-
message
|
|
45656
|
-
};
|
|
45657
|
-
}
|
|
45658
|
-
function refused(...problems) {
|
|
45659
|
-
return {
|
|
45660
|
-
problems,
|
|
45661
|
-
fields: []
|
|
45662
|
-
};
|
|
45663
|
-
}
|
|
45664
44900
|
function readKinds(read, lookupCap) {
|
|
45665
44901
|
const def = lookupCap(read.cap);
|
|
45666
44902
|
const schema = def?.runtimeState ?? def?.status?.schema;
|
|
@@ -45735,7 +44971,7 @@ function compatibility(cap, target, kinds, at) {
|
|
|
45735
44971
|
*/
|
|
45736
44972
|
function literalStringValue(source) {
|
|
45737
44973
|
if (source.kind !== "expression") return null;
|
|
45738
|
-
const compiled = compileExpressionSafe(source.expr);
|
|
44974
|
+
const compiled = require_composition.compileExpressionSafe(source.expr);
|
|
45739
44975
|
if (!compiled.ok) return null;
|
|
45740
44976
|
const ast = compiled.parsed.ast;
|
|
45741
44977
|
return ast.kind === "literal" && typeof ast.value === "string" ? ast.value : null;
|
|
@@ -45755,78 +44991,604 @@ function enumLiteralProblem(cap, target, source, at) {
|
|
|
45755
44991
|
}
|
|
45756
44992
|
function roleOf(source) {
|
|
45757
44993
|
if (source.kind !== "expression") return "derived";
|
|
45758
|
-
if (fieldReads(source).length > 0) return "derived";
|
|
45759
|
-
const compiled = compileExpressionSafe(source.expr);
|
|
44994
|
+
if (require_composition.fieldReads(source).length > 0) return "derived";
|
|
44995
|
+
const compiled = require_composition.compileExpressionSafe(source.expr);
|
|
45760
44996
|
return compiled.ok && compiled.parsed.identifiers.has("now") ? "clock" : "constant";
|
|
45761
44997
|
}
|
|
45762
|
-
|
|
45763
|
-
|
|
44998
|
+
/**
|
|
44999
|
+
* How a planned field says "unavailable", per feature mode and AFTER `roleOf`
|
|
45000
|
+
* (D393, D663 rulings S1 + S1b). The composer cannot take a device it does not
|
|
45001
|
+
* own offline, and D393 forbids a stale number, so on an existing target a
|
|
45002
|
+
* field that READS a source never gets `offline`.
|
|
45003
|
+
*/
|
|
45004
|
+
function unavailableFor(tf, role, mode, cap, at) {
|
|
45005
|
+
if (mode === "new" || role !== "derived") return {
|
|
45006
|
+
ok: true,
|
|
45007
|
+
unavailable: tf.nullable ? "null" : "offline"
|
|
45008
|
+
};
|
|
45009
|
+
if (mode === "replace") return {
|
|
45010
|
+
ok: true,
|
|
45011
|
+
unavailable: "release"
|
|
45012
|
+
};
|
|
45013
|
+
if (tf.nullable) return {
|
|
45014
|
+
ok: true,
|
|
45015
|
+
unavailable: "null"
|
|
45016
|
+
};
|
|
45017
|
+
if (tf.enumValues?.includes("unknown") === true) return {
|
|
45018
|
+
ok: true,
|
|
45019
|
+
unavailable: "unknown"
|
|
45020
|
+
};
|
|
45021
|
+
return {
|
|
45022
|
+
ok: false,
|
|
45023
|
+
problem: problem("not-replaceable", at, `\`${cap}.${tf.path}\` reads a source but can say neither null nor 'unknown', and an ADDED capability has no native reading to fall back to (D393, D663)`)
|
|
45024
|
+
};
|
|
45025
|
+
}
|
|
45026
|
+
//#endregion
|
|
45027
|
+
//#region src/composition/composition-items.ts
|
|
45028
|
+
/** Item fields the composer writes itself, with the value it writes. */
|
|
45029
|
+
var COMPOSED_ITEM_FIXED_FIELDS = { resettable: false };
|
|
45030
|
+
function reservedItemFields(itemArray) {
|
|
45031
|
+
return new Set([
|
|
45032
|
+
itemArray.keyField,
|
|
45033
|
+
...itemArray.labelField === void 0 ? [] : [itemArray.labelField],
|
|
45034
|
+
...Object.keys(COMPOSED_ITEM_FIXED_FIELDS)
|
|
45035
|
+
]);
|
|
45036
|
+
}
|
|
45037
|
+
/** A required leaf under an optional parent is required only once something writes that parent. */
|
|
45038
|
+
function leafRequired(itemArray, path, written) {
|
|
45039
|
+
const described = describeStateField(itemArray.itemSchema, path);
|
|
45040
|
+
if (described === null || !described.required) return false;
|
|
45041
|
+
return optionalAncestors(itemArray.itemSchema, path).every((parent) => written.some((w) => w.startsWith(`${parent}.`)));
|
|
45042
|
+
}
|
|
45043
|
+
function missingLeaves({ capName, itemArray, reserved }, item, at) {
|
|
45044
|
+
const written = Object.keys(item.fields);
|
|
45045
|
+
return enumerateSchemaFields(itemArray.itemSchema).flatMap((leaf) => {
|
|
45046
|
+
if (reserved.has(leaf.path) || leaf.path in item.fields) return [];
|
|
45047
|
+
if (!leafRequired(itemArray, leaf.path, written)) return [];
|
|
45048
|
+
const described = describeStateField(itemArray.itemSchema, leaf.path);
|
|
45049
|
+
if (described === null || described.nullable) return [];
|
|
45050
|
+
return [problem("missing-field", `${at}.fields.${leaf.path}`, `\`${capName}.${itemArray.path}[].${leaf.path}\` is required and has no source`)];
|
|
45051
|
+
});
|
|
45052
|
+
}
|
|
45053
|
+
function planItemField(ctx, leaf) {
|
|
45054
|
+
const { capName, itemArray, featureIndex, lookupCap } = ctx;
|
|
45055
|
+
const { key, label, path, source } = leaf;
|
|
45056
|
+
const at = `features[${featureIndex}].items.${key}.fields.${path}`;
|
|
45057
|
+
if (ctx.reserved.has(path)) return refused(problem("item-field-reserved", at, `\`${capName}.${itemArray.path}[].${path}\` is set by the composer itself — it takes no source`));
|
|
45058
|
+
const tf = describeStateField(itemArray.itemSchema, path);
|
|
45059
|
+
if (tf === null) return refused(problem("unknown-field", at, `a \`${capName}\` item has no field \`${path}\``));
|
|
45060
|
+
const kinds = sourceKinds(source, lookupCap);
|
|
45061
|
+
if (!kinds.ok) return refused(problem(kinds.code, at, kinds.message));
|
|
45062
|
+
const role = roleOf(source);
|
|
45063
|
+
const unavailable = unavailableFor(tf, role, ctx.mode, capName, at);
|
|
45064
|
+
if (!unavailable.ok) return refused(unavailable.problem);
|
|
45065
|
+
const plan = {
|
|
45066
|
+
cap: capName,
|
|
45067
|
+
path,
|
|
45068
|
+
item: {
|
|
45069
|
+
arrayPath: itemArray.path,
|
|
45070
|
+
key,
|
|
45071
|
+
label
|
|
45072
|
+
},
|
|
45073
|
+
featureIndex,
|
|
45074
|
+
kind: tf.kind,
|
|
45075
|
+
nullable: tf.nullable,
|
|
45076
|
+
required: tf.required,
|
|
45077
|
+
unavailable: unavailable.unavailable,
|
|
45078
|
+
role,
|
|
45079
|
+
source,
|
|
45080
|
+
reads: [...require_composition.fieldReads(source)]
|
|
45081
|
+
};
|
|
45082
|
+
const enumProblem = enumLiteralProblem(capName, tf, source, at);
|
|
45083
|
+
return {
|
|
45084
|
+
problems: [...compatibility(capName, tf, kinds.kinds, at), ...enumProblem === null ? [] : [enumProblem]],
|
|
45085
|
+
fields: [plan],
|
|
45086
|
+
features: []
|
|
45087
|
+
};
|
|
45088
|
+
}
|
|
45089
|
+
function planItems(def, feature, featureIndex, lookupCap, mode = "new") {
|
|
45090
|
+
const at = `features[${featureIndex}].items`;
|
|
45091
|
+
const itemArray = def.status?.itemArray;
|
|
45092
|
+
if (itemArray === void 0) return refused(problem("not-item-array", at, `\`${def.name}\` has no item array — it takes no \`items\``));
|
|
45093
|
+
if (itemArray.path !== "items") return refused(problem("not-item-array", at, `\`${def.name}\`'s item array is at \`${itemArray.path}\`, not \`${require_composition.COMPOSITION_ITEM_ARRAY_PATH}\` — not composable yet`));
|
|
45094
|
+
const ctx = {
|
|
45095
|
+
capName: def.name,
|
|
45096
|
+
itemArray,
|
|
45097
|
+
reserved: reservedItemFields(itemArray),
|
|
45098
|
+
featureIndex,
|
|
45099
|
+
lookupCap,
|
|
45100
|
+
mode
|
|
45101
|
+
};
|
|
45102
|
+
const results = Object.entries(feature.items ?? {}).flatMap(([key, item]) => [{
|
|
45103
|
+
problems: missingLeaves(ctx, item, `${at}.${key}`),
|
|
45104
|
+
fields: [],
|
|
45105
|
+
features: []
|
|
45106
|
+
}, ...Object.entries(item.fields).map(([path, source]) => planItemField(ctx, {
|
|
45107
|
+
key,
|
|
45108
|
+
label: item.label,
|
|
45109
|
+
path,
|
|
45110
|
+
source
|
|
45111
|
+
}))]);
|
|
45112
|
+
return {
|
|
45113
|
+
problems: results.flatMap((r) => r.problems),
|
|
45114
|
+
fields: results.flatMap((r) => r.fields),
|
|
45115
|
+
features: []
|
|
45116
|
+
};
|
|
45117
|
+
}
|
|
45118
|
+
//#endregion
|
|
45119
|
+
//#region src/composition/evaluate-field.ts
|
|
45120
|
+
function describeRead(read) {
|
|
45121
|
+
return `${require_composition.compositionSourceKey(read.source)} ${read.cap}.${read.fieldPath}`;
|
|
45122
|
+
}
|
|
45123
|
+
function isConfirmed(reading) {
|
|
45124
|
+
return reading.fatal || reading.confirmed === true;
|
|
45125
|
+
}
|
|
45126
|
+
function fromReading(reading, read) {
|
|
45127
|
+
if (reading.state === "unavailable") return {
|
|
45128
|
+
state: "unavailable",
|
|
45129
|
+
value: null,
|
|
45130
|
+
reason: `${describeRead(read)}: ${reading.reason}`,
|
|
45131
|
+
fatal: reading.fatal,
|
|
45132
|
+
confirmed: isConfirmed(reading)
|
|
45133
|
+
};
|
|
45134
|
+
return {
|
|
45135
|
+
state: reading.state,
|
|
45136
|
+
value: reading.value,
|
|
45137
|
+
reason: reading.state === "stale" ? `${describeRead(read)}: ${reading.reason}` : null,
|
|
45138
|
+
deadline: null
|
|
45139
|
+
};
|
|
45140
|
+
}
|
|
45141
|
+
function expressionOutcome(source, read, now) {
|
|
45142
|
+
const values = {};
|
|
45143
|
+
const staleReasons = [];
|
|
45144
|
+
let fatalUnavailable = null;
|
|
45145
|
+
let nonFatalUnavailable = null;
|
|
45146
|
+
for (const [name, binding] of Object.entries(source.bindings)) {
|
|
45147
|
+
if (binding.kind === "literal") {
|
|
45148
|
+
values[name] = binding.value;
|
|
45149
|
+
continue;
|
|
45150
|
+
}
|
|
45151
|
+
const reading = read(binding);
|
|
45152
|
+
if (reading.state === "unavailable") {
|
|
45153
|
+
const outcome = {
|
|
45154
|
+
state: "unavailable",
|
|
45155
|
+
value: null,
|
|
45156
|
+
reason: `binding \`${name}\` (${describeRead(binding)}): ${reading.reason}`,
|
|
45157
|
+
fatal: reading.fatal,
|
|
45158
|
+
confirmed: isConfirmed(reading)
|
|
45159
|
+
};
|
|
45160
|
+
if (reading.fatal) {
|
|
45161
|
+
fatalUnavailable = outcome;
|
|
45162
|
+
break;
|
|
45163
|
+
}
|
|
45164
|
+
if (nonFatalUnavailable === null || outcome.confirmed && !nonFatalUnavailable.confirmed) nonFatalUnavailable = outcome;
|
|
45165
|
+
continue;
|
|
45166
|
+
}
|
|
45167
|
+
values[name] = reading.value;
|
|
45168
|
+
if (reading.state === "stale") staleReasons.push(`\`${name}\`: ${reading.reason}`);
|
|
45169
|
+
}
|
|
45170
|
+
if (fatalUnavailable !== null) return fatalUnavailable;
|
|
45171
|
+
if (nonFatalUnavailable !== null) return nonFatalUnavailable;
|
|
45172
|
+
const deadlines = [];
|
|
45173
|
+
const result = require_composition.evaluateExpressionSource(source.expr, values, now, { hooks: { noteDeadline: (at) => deadlines.push(at) } });
|
|
45174
|
+
if (!result.ok) return {
|
|
45175
|
+
state: "unavailable",
|
|
45176
|
+
value: null,
|
|
45177
|
+
reason: `the expression failed: ${result.error}`,
|
|
45178
|
+
fatal: false,
|
|
45179
|
+
confirmed: true
|
|
45180
|
+
};
|
|
45181
|
+
return {
|
|
45182
|
+
state: staleReasons.length > 0 ? "stale" : "fresh",
|
|
45183
|
+
value: result.value,
|
|
45184
|
+
reason: staleReasons.length > 0 ? staleReasons.join("; ") : null,
|
|
45185
|
+
deadline: deadlines.length > 0 ? Math.min(...deadlines) : null
|
|
45186
|
+
};
|
|
45187
|
+
}
|
|
45188
|
+
function evaluateCompositionField(input) {
|
|
45189
|
+
const { source } = input;
|
|
45190
|
+
switch (source.kind) {
|
|
45191
|
+
case "from": return fromReading(input.read(source), source);
|
|
45192
|
+
case "expression": return expressionOutcome(source, input.read, input.now);
|
|
45193
|
+
case "code": return {
|
|
45194
|
+
state: "unavailable",
|
|
45195
|
+
value: null,
|
|
45196
|
+
reason: "code fields are not runnable in the composer — they arrive in slice 4",
|
|
45197
|
+
fatal: true,
|
|
45198
|
+
confirmed: true
|
|
45199
|
+
};
|
|
45200
|
+
}
|
|
45201
|
+
}
|
|
45202
|
+
//#endregion
|
|
45203
|
+
//#region src/composition/examples.ts
|
|
45204
|
+
/**
|
|
45205
|
+
* The worked composed-device example: a ROOM. Temperature is the average of N
|
|
45206
|
+
* sensors, and occupancy is any motion within the last five minutes. It is the
|
|
45207
|
+
* slice-1 acceptance case and the template an author starts from (Phase 4
|
|
45208
|
+
* §4 item 4 asked for one).
|
|
45209
|
+
*/
|
|
45210
|
+
var ROOM_OCCUPANCY_WINDOW_MS = 3e5;
|
|
45211
|
+
var ROOM_EXAMPLE_TEMPERATURE_SOURCES = [
|
|
45212
|
+
{
|
|
45213
|
+
addonId: "provider-homeassistant",
|
|
45214
|
+
stableId: "sensor.living_room_temperature"
|
|
45215
|
+
},
|
|
45216
|
+
{
|
|
45217
|
+
addonId: "provider-homeassistant",
|
|
45218
|
+
stableId: "sensor.sofa_temperature"
|
|
45219
|
+
},
|
|
45220
|
+
{
|
|
45221
|
+
addonId: "provider-homeassistant",
|
|
45222
|
+
stableId: "sensor.window_temperature"
|
|
45223
|
+
}
|
|
45224
|
+
];
|
|
45225
|
+
var ROOM_EXAMPLE_MOTION_SOURCES = [{
|
|
45226
|
+
addonId: "provider-homeassistant",
|
|
45227
|
+
stableId: "binary_sensor.living_room_motion"
|
|
45228
|
+
}, {
|
|
45229
|
+
addonId: "provider-homeassistant",
|
|
45230
|
+
stableId: "binary_sensor.living_room_presence"
|
|
45231
|
+
}];
|
|
45232
|
+
function from(source, cap, fieldPath) {
|
|
45233
|
+
return {
|
|
45234
|
+
kind: "from",
|
|
45235
|
+
source,
|
|
45236
|
+
cap,
|
|
45237
|
+
fieldPath
|
|
45238
|
+
};
|
|
45239
|
+
}
|
|
45240
|
+
function named(prefix, sources, cap, fieldPath) {
|
|
45241
|
+
return Object.fromEntries(sources.map((s, i) => [`${prefix}${i + 1}`, from(s, cap, fieldPath)]));
|
|
45242
|
+
}
|
|
45243
|
+
function roomCompositionExample(input) {
|
|
45244
|
+
const t = named("t", input.temperatureSources, "temperature-sensor", "celsius");
|
|
45245
|
+
const f = named("f", input.temperatureSources, "temperature-sensor", "lastFetchedAt");
|
|
45246
|
+
const d = named("d", input.motionSources, "motion", "detected");
|
|
45247
|
+
const m = named("m", input.motionSources, "motion", "lastDetectedAt");
|
|
45248
|
+
const windows = Object.keys(m).map((name) => `within(${name}, ${input.occupancyWindowMs})`);
|
|
45249
|
+
return require_composition.CompositionSchema.parse({
|
|
45250
|
+
target: {
|
|
45251
|
+
kind: "new",
|
|
45252
|
+
type: require_err_msg.DeviceType.Sensor
|
|
45253
|
+
},
|
|
45254
|
+
features: [{
|
|
45255
|
+
kind: "fields",
|
|
45256
|
+
cap: "temperature-sensor",
|
|
45257
|
+
fields: {
|
|
45258
|
+
celsius: {
|
|
45259
|
+
kind: "expression",
|
|
45260
|
+
expr: `round(avg(${Object.keys(t).join(", ")}), 1)`,
|
|
45261
|
+
bindings: t
|
|
45262
|
+
},
|
|
45263
|
+
lastFetchedAt: {
|
|
45264
|
+
kind: "expression",
|
|
45265
|
+
expr: `max(${Object.keys(f).join(", ")})`,
|
|
45266
|
+
bindings: f
|
|
45267
|
+
}
|
|
45268
|
+
}
|
|
45269
|
+
}, {
|
|
45270
|
+
kind: "fields",
|
|
45271
|
+
cap: "binary",
|
|
45272
|
+
fields: {
|
|
45273
|
+
on: {
|
|
45274
|
+
kind: "expression",
|
|
45275
|
+
expr: `any(${[...Object.keys(d), ...windows].join(", ")})`,
|
|
45276
|
+
bindings: {
|
|
45277
|
+
...d,
|
|
45278
|
+
...m
|
|
45279
|
+
}
|
|
45280
|
+
},
|
|
45281
|
+
lastChangedAt: {
|
|
45282
|
+
kind: "expression",
|
|
45283
|
+
expr: "now",
|
|
45284
|
+
bindings: {}
|
|
45285
|
+
}
|
|
45286
|
+
}
|
|
45287
|
+
}]
|
|
45288
|
+
});
|
|
45289
|
+
}
|
|
45290
|
+
/**
|
|
45291
|
+
* The slice-2 worked customization (D663): the PetKit "Fresh Element Infinity"
|
|
45292
|
+
* feeder as Home Assistant imports it — ONE `Container` with a child per entity
|
|
45293
|
+
* (`<container stableId>-<entityId>`), and NO native battery (its
|
|
45294
|
+
* `binary_sensor.*_battery` is `battery_charging`, which `isBatteryEntity` does
|
|
45295
|
+
* not match). The customization ADDS `consumables` (the desiccant) and
|
|
45296
|
+
* `battery`. It is the Task 14 acceptance case and the template slice 5's
|
|
45297
|
+
* presets start from.
|
|
45298
|
+
*
|
|
45299
|
+
* Every read names what the HA provider REALLY registers (read 2026-09-28):
|
|
45300
|
+
* the desiccant sensor has a unit (`d`) but no device_class, so HA hosts it as
|
|
45301
|
+
* an `enum-sensor` whose `value` is the raw STRING state — `number(d)` reads it,
|
|
45302
|
+
* and anything that is not a number is `null`, never 0 (D393). The battery
|
|
45303
|
+
* status sensor is an `enum-sensor` too (`unavailable` keeps its cold `''`, so
|
|
45304
|
+
* `percentage` is `null`). `charging` maps `battery_charging` off to
|
|
45305
|
+
* `'unknown'`, never `'none'`: off does not prove "on battery alone" (the
|
|
45306
|
+
* operator confirms the real semantics live).
|
|
45307
|
+
*/
|
|
45308
|
+
var FEEDER_EXAMPLE_HA_DEVICE_ID = "8dec3b512fda40cbb8cd121c7a99f890";
|
|
45309
|
+
var FEEDER_EXAMPLE_ADDON_ID = "provider-homeassistant";
|
|
45310
|
+
/** The HA container's stableId (`ha-discovery.ts`) and a child's (`<container>-<entityId>`). */
|
|
45311
|
+
function feederExampleSources(brokerId) {
|
|
45312
|
+
const feeder = {
|
|
45313
|
+
addonId: FEEDER_EXAMPLE_ADDON_ID,
|
|
45314
|
+
stableId: `ha:${brokerId}:dev:${FEEDER_EXAMPLE_HA_DEVICE_ID}`
|
|
45315
|
+
};
|
|
45316
|
+
const child = (entityId) => ({
|
|
45317
|
+
addonId: FEEDER_EXAMPLE_ADDON_ID,
|
|
45318
|
+
stableId: `${feeder.stableId}-${entityId}`
|
|
45319
|
+
});
|
|
45320
|
+
return {
|
|
45321
|
+
feeder,
|
|
45322
|
+
desiccantDays: child("sensor.freshelement_3_desiccant_days_remaining"),
|
|
45323
|
+
batteryStatus: child("sensor.freshelement_3_battery_status"),
|
|
45324
|
+
batteryCharging: child("binary_sensor.freshelement_3_battery")
|
|
45325
|
+
};
|
|
45326
|
+
}
|
|
45327
|
+
function feederCustomizationExample(sources) {
|
|
45328
|
+
const days = { d: from(sources.desiccantDays, "enum-sensor", "value") };
|
|
45329
|
+
return require_composition.CompositionSchema.parse({
|
|
45330
|
+
target: {
|
|
45331
|
+
kind: "existing",
|
|
45332
|
+
device: sources.feeder
|
|
45333
|
+
},
|
|
45334
|
+
features: [{
|
|
45335
|
+
kind: "fields",
|
|
45336
|
+
cap: "consumables",
|
|
45337
|
+
fields: {
|
|
45338
|
+
lastChangedAt: {
|
|
45339
|
+
kind: "expression",
|
|
45340
|
+
expr: "now",
|
|
45341
|
+
bindings: {}
|
|
45342
|
+
},
|
|
45343
|
+
lastFetchedAt: {
|
|
45344
|
+
kind: "expression",
|
|
45345
|
+
expr: "now",
|
|
45346
|
+
bindings: {}
|
|
45347
|
+
}
|
|
45348
|
+
},
|
|
45349
|
+
items: { desiccant: {
|
|
45350
|
+
label: "Desiccant",
|
|
45351
|
+
fields: {
|
|
45352
|
+
"remaining.value": {
|
|
45353
|
+
kind: "expression",
|
|
45354
|
+
expr: "number(d)",
|
|
45355
|
+
bindings: days
|
|
45356
|
+
},
|
|
45357
|
+
"remaining.unit": {
|
|
45358
|
+
kind: "expression",
|
|
45359
|
+
expr: "\"days\"",
|
|
45360
|
+
bindings: {}
|
|
45361
|
+
},
|
|
45362
|
+
status: {
|
|
45363
|
+
kind: "expression",
|
|
45364
|
+
expr: "number(d) == null ? null : (number(d) <= 0 ? \"replace\" : \"ok\")",
|
|
45365
|
+
bindings: days
|
|
45366
|
+
}
|
|
45367
|
+
}
|
|
45368
|
+
} }
|
|
45369
|
+
}, {
|
|
45370
|
+
kind: "fields",
|
|
45371
|
+
cap: "battery",
|
|
45372
|
+
fields: {
|
|
45373
|
+
percentage: {
|
|
45374
|
+
kind: "expression",
|
|
45375
|
+
expr: "s == \"low\" ? 15 : (s == \"normal\" ? 100 : null)",
|
|
45376
|
+
bindings: { s: from(sources.batteryStatus, "enum-sensor", "value") }
|
|
45377
|
+
},
|
|
45378
|
+
binary: {
|
|
45379
|
+
kind: "expression",
|
|
45380
|
+
expr: "true",
|
|
45381
|
+
bindings: {}
|
|
45382
|
+
},
|
|
45383
|
+
charging: {
|
|
45384
|
+
kind: "expression",
|
|
45385
|
+
expr: "c ? \"dc\" : \"unknown\"",
|
|
45386
|
+
bindings: { c: from(sources.batteryCharging, "binary", "on") }
|
|
45387
|
+
},
|
|
45388
|
+
sleeping: {
|
|
45389
|
+
kind: "expression",
|
|
45390
|
+
expr: "false",
|
|
45391
|
+
bindings: {}
|
|
45392
|
+
},
|
|
45393
|
+
lastUpdated: {
|
|
45394
|
+
kind: "expression",
|
|
45395
|
+
expr: "now",
|
|
45396
|
+
bindings: {}
|
|
45397
|
+
}
|
|
45398
|
+
}
|
|
45399
|
+
}]
|
|
45400
|
+
});
|
|
45401
|
+
}
|
|
45402
|
+
//#endregion
|
|
45403
|
+
//#region src/composition/validate-composition.ts
|
|
45404
|
+
function buildCapabilityLookup(defs) {
|
|
45405
|
+
const byName = new Map(defs.map((d) => [d.name, d]));
|
|
45406
|
+
return (capName) => byName.get(capName) ?? null;
|
|
45407
|
+
}
|
|
45408
|
+
/** Caps every `BaseDevice` registers on itself; a second registration throws. */
|
|
45409
|
+
var BASE_DEVICE_CAPS = new Set(["device-status", "feature-probe"]);
|
|
45410
|
+
var PENDING_SELF = {
|
|
45411
|
+
addonId: require_composition.COMPOSER_ADDON_ID,
|
|
45412
|
+
stableId: `${require_composition.COMPOSED_DEVICE_STABLE_ID_PREFIX}(unsaved)`
|
|
45413
|
+
};
|
|
45414
|
+
/** The candidate's block id before its first save. Stored block ids are `randomUUID()`, so none can carry it. */
|
|
45415
|
+
var PENDING_BLOCK_ID = "(unsaved)";
|
|
45416
|
+
function composableCap(feature, at, lookupCap) {
|
|
45764
45417
|
const def = lookupCap(feature.cap);
|
|
45765
|
-
if (def === null) return
|
|
45766
|
-
if (BASE_DEVICE_CAPS.has(def.name)) return
|
|
45418
|
+
if (def === null) return problem("unknown-capability", `${at}.cap`, `no capability is named \`${feature.cap}\``);
|
|
45419
|
+
if (BASE_DEVICE_CAPS.has(def.name)) return problem("not-composable", `${at}.cap`, `\`${def.name}\` is registered by every device itself — it cannot be composed`);
|
|
45767
45420
|
const state = def.runtimeState;
|
|
45768
|
-
if (def.scope !== "device" || state === void 0) return
|
|
45769
|
-
|
|
45770
|
-
|
|
45771
|
-
|
|
45772
|
-
|
|
45421
|
+
if (def.scope !== "device" || state === void 0) return problem("not-composable", `${at}.cap`, `\`${def.name}\` has no per-device state to compose`);
|
|
45422
|
+
return {
|
|
45423
|
+
def,
|
|
45424
|
+
state,
|
|
45425
|
+
fields: describeTopLevelStateFields(state)
|
|
45426
|
+
};
|
|
45427
|
+
}
|
|
45428
|
+
/**
|
|
45429
|
+
* A capability BUILT by the composition (a new device, or one ADDED to an
|
|
45430
|
+
* existing device) must fit the device type, serve no command, and have every
|
|
45431
|
+
* required field. A REPLACE needs none of it: the cap is bound (a fact), the
|
|
45432
|
+
* native keeps serving its methods, and only the named fields are owned (D663).
|
|
45433
|
+
*/
|
|
45434
|
+
function builtCapProblems({ def, state, fields: targetFields }, feature, at, deviceType) {
|
|
45435
|
+
const problems = [];
|
|
45436
|
+
if (def.deviceTypes !== void 0 && !def.deviceTypes.includes(deviceType)) problems.push(problem("wrong-device-type", `${at}.cap`, `\`${def.name}\` is not offered on a \`${deviceType}\` device (it allows ${def.deviceTypes.join(", ")})`));
|
|
45437
|
+
const served = Object.entries(def.methods).filter(([name, m]) => m.systemOnly !== true && def.composedMethods?.[name] === void 0).map(([name]) => `\`${name}\``);
|
|
45438
|
+
if (served.length > 0) problems.push(problem("has-commands", `${at}.cap`, `\`${def.name}\` has ${served.join(", ")}, which a composed device cannot serve until commands arrive (slice 3)`));
|
|
45439
|
+
const itemArrayPath = feature.items === void 0 ? null : def.status?.itemArray?.path ?? null;
|
|
45440
|
+
for (const key of requiredTopLevelKeys(state)) {
|
|
45441
|
+
if (key === itemArrayPath) continue;
|
|
45442
|
+
if (!targetFields.has(key)) problems.push(problem("not-composable", `${at}.fields`, `\`${def.name}.${key}\` is not a scalar — nested fields arrive in a later slice`));
|
|
45443
|
+
else if (!(key in feature.fields)) problems.push(problem("missing-field", `${at}.fields.${key}`, `\`${def.name}.${key}\` is required and has no source`));
|
|
45444
|
+
}
|
|
45445
|
+
return problems;
|
|
45446
|
+
}
|
|
45447
|
+
function planTopLevelField({ def, fields }, field, mode, lookupCap) {
|
|
45448
|
+
const { featureIndex, path, source } = field;
|
|
45449
|
+
const fieldAt = `features[${featureIndex}].fields.${path}`;
|
|
45450
|
+
if (path.includes(".")) return refused(problem("nested-field", fieldAt, `\`${path}\` is nested — nested fields arrive in a later slice`));
|
|
45451
|
+
const tf = fields.get(path);
|
|
45452
|
+
if (tf === void 0) return refused(problem("unknown-field", fieldAt, `\`${def.name}\` has no field \`${path}\``));
|
|
45453
|
+
const kinds = sourceKinds(source, lookupCap);
|
|
45454
|
+
if (!kinds.ok) return refused(problem(kinds.code, fieldAt, kinds.message));
|
|
45455
|
+
const role = roleOf(source);
|
|
45456
|
+
const unavailable = unavailableFor(tf, role, mode, def.name, fieldAt);
|
|
45457
|
+
if (!unavailable.ok) return refused(unavailable.problem);
|
|
45458
|
+
const plan = {
|
|
45459
|
+
cap: def.name,
|
|
45460
|
+
path,
|
|
45461
|
+
featureIndex,
|
|
45462
|
+
kind: tf.kind,
|
|
45463
|
+
nullable: tf.nullable,
|
|
45464
|
+
required: tf.required,
|
|
45465
|
+
unavailable: unavailable.unavailable,
|
|
45466
|
+
role,
|
|
45467
|
+
source,
|
|
45468
|
+
reads: [...require_composition.fieldReads(source)]
|
|
45469
|
+
};
|
|
45470
|
+
const enumProblem = enumLiteralProblem(def.name, tf, source, fieldAt);
|
|
45471
|
+
return {
|
|
45472
|
+
problems: [...compatibility(def.name, tf, kinds.kinds, fieldAt), ...enumProblem === null ? [] : [enumProblem]],
|
|
45473
|
+
fields: [plan],
|
|
45474
|
+
features: []
|
|
45475
|
+
};
|
|
45476
|
+
}
|
|
45477
|
+
function planFeature(feature, featureIndex, target, lookupCap) {
|
|
45478
|
+
const at = `features[${featureIndex}]`;
|
|
45479
|
+
const cap = composableCap(feature, at, lookupCap);
|
|
45480
|
+
if ("code" in cap) return refused(cap);
|
|
45481
|
+
const capProblems = target.mode === "replace" ? [] : [...builtCapProblems(cap, feature, at, target.deviceType)];
|
|
45773
45482
|
if (feature.commands !== void 0 && Object.keys(feature.commands).length > 0) capProblems.push(problem("reserved-variant", `${at}.commands`, "commands (`forward`) arrive in slice 3"));
|
|
45774
|
-
const
|
|
45775
|
-
|
|
45776
|
-
|
|
45777
|
-
|
|
45778
|
-
|
|
45779
|
-
|
|
45780
|
-
|
|
45781
|
-
|
|
45782
|
-
|
|
45783
|
-
|
|
45784
|
-
|
|
45785
|
-
cap: def.name,
|
|
45786
|
-
path,
|
|
45483
|
+
const perField = Object.entries(feature.fields).map(([path, source]) => planTopLevelField(cap, {
|
|
45484
|
+
featureIndex,
|
|
45485
|
+
path,
|
|
45486
|
+
source
|
|
45487
|
+
}, target.mode, lookupCap));
|
|
45488
|
+
const items = feature.items === void 0 ? [] : [planItems(cap.def, feature, featureIndex, lookupCap, target.mode)];
|
|
45489
|
+
const all = [...perField, ...items];
|
|
45490
|
+
return {
|
|
45491
|
+
problems: [...capProblems, ...all.flatMap((r) => r.problems)],
|
|
45492
|
+
fields: all.flatMap((r) => r.fields),
|
|
45493
|
+
features: [{
|
|
45787
45494
|
featureIndex,
|
|
45788
|
-
|
|
45789
|
-
|
|
45790
|
-
|
|
45791
|
-
|
|
45792
|
-
|
|
45793
|
-
|
|
45794
|
-
|
|
45795
|
-
|
|
45796
|
-
|
|
45797
|
-
|
|
45798
|
-
|
|
45799
|
-
|
|
45800
|
-
|
|
45801
|
-
|
|
45495
|
+
cap: cap.def.name,
|
|
45496
|
+
mode: target.mode
|
|
45497
|
+
}]
|
|
45498
|
+
};
|
|
45499
|
+
}
|
|
45500
|
+
/** A cap the device serves itself; one the composer grafted (an earlier ADD) is not native. */
|
|
45501
|
+
function isNativeCap(target, cap) {
|
|
45502
|
+
const owner = target.nativeCaps.get(cap);
|
|
45503
|
+
return owner !== void 0 && owner !== "composer";
|
|
45504
|
+
}
|
|
45505
|
+
/** The target read, or the refusal that replaces the whole plan when it could not be (D391). */
|
|
45506
|
+
function planTargetOf(composition, target) {
|
|
45507
|
+
if (composition.target.kind === "new") return {
|
|
45508
|
+
kind: "new",
|
|
45509
|
+
type: composition.target.type
|
|
45510
|
+
};
|
|
45511
|
+
const key = require_composition.compositionSourceKey(composition.target.device);
|
|
45512
|
+
if (target === void 0) return problem("target-unreadable", "target", `target device \`${key}\` was not read — the save is refused rather than stored unchecked`);
|
|
45513
|
+
if (target.kind === "absent") return problem("target-missing", "target", `target device \`${key}\` does not exist`);
|
|
45514
|
+
if (target.kind === "unreadable") return problem("target-unreadable", "target", `could not read target device \`${key}\` (${target.error}) — the save is refused rather than stored unchecked`);
|
|
45802
45515
|
return {
|
|
45803
|
-
|
|
45804
|
-
|
|
45516
|
+
kind: "existing",
|
|
45517
|
+
found: target
|
|
45805
45518
|
};
|
|
45806
45519
|
}
|
|
45807
|
-
function
|
|
45808
|
-
|
|
45809
|
-
|
|
45520
|
+
function featureTargetOf(target, cap) {
|
|
45521
|
+
if (target.kind === "new") return {
|
|
45522
|
+
mode: "new",
|
|
45523
|
+
deviceType: target.type
|
|
45524
|
+
};
|
|
45525
|
+
return {
|
|
45526
|
+
mode: isNativeCap(target.found, cap) ? "replace" : "add",
|
|
45527
|
+
deviceType: target.found.type
|
|
45528
|
+
};
|
|
45529
|
+
}
|
|
45530
|
+
/**
|
|
45531
|
+
* The static plan. `target` describes an EXISTING target device (one read);
|
|
45532
|
+
* it is ignored for a new one. On an existing target each feature REPLACES a
|
|
45533
|
+
* cap the device has natively, else ADDS it (D663).
|
|
45534
|
+
*/
|
|
45535
|
+
function planComposition(composition, lookupCap, target) {
|
|
45536
|
+
const planTarget = planTargetOf(composition, target);
|
|
45537
|
+
if ("code" in planTarget) return refused(planTarget);
|
|
45810
45538
|
const results = composition.features.map((feature, index) => {
|
|
45811
|
-
|
|
45812
|
-
|
|
45813
|
-
return planFeature(feature, index, target, lookupCap);
|
|
45539
|
+
if (feature.kind === "passthrough") return refused(problem("reserved-variant", `features[${index}]`, `whole-capability passthrough of \`${feature.cap}\` arrives in slice 3`));
|
|
45540
|
+
return planFeature(feature, index, featureTargetOf(planTarget, feature.cap), lookupCap);
|
|
45814
45541
|
});
|
|
45815
45542
|
return {
|
|
45816
45543
|
problems: results.flatMap((r) => r.problems),
|
|
45817
|
-
fields: results.flatMap((r) => r.fields)
|
|
45544
|
+
fields: results.flatMap((r) => r.fields),
|
|
45545
|
+
features: results.flatMap((r) => r.features)
|
|
45818
45546
|
};
|
|
45819
45547
|
}
|
|
45820
45548
|
function compositionSourceRefs(composition) {
|
|
45821
|
-
const refs = composition.features.flatMap((f) => f.kind === "fields" ?
|
|
45822
|
-
return [...new Map(refs.map((r) => [compositionSourceKey(r), r])).values()];
|
|
45549
|
+
const refs = composition.features.flatMap((f) => f.kind === "fields" ? require_composition.featureSources(f).flatMap(require_composition.fieldReads).map((r) => r.source) : []);
|
|
45550
|
+
return [...new Map(refs.map((r) => [require_composition.compositionSourceKey(r), r])).values()];
|
|
45823
45551
|
}
|
|
45824
|
-
|
|
45825
|
-
|
|
45552
|
+
/**
|
|
45553
|
+
* The candidate's device: the existing target itself, else `self`, else a
|
|
45554
|
+
* placeholder that cannot collide with a stored target. An existing target is
|
|
45555
|
+
* known even on create, so a second customization of it is refused on create too.
|
|
45556
|
+
*/
|
|
45557
|
+
function candidateSelf(composition, ctx, plan) {
|
|
45558
|
+
return {
|
|
45559
|
+
ref: composition.target.kind === "existing" ? composition.target.device : ctx.self ?? PENDING_SELF,
|
|
45560
|
+
native: composition.target.kind === "existing" && ctx.target?.kind === "found" ? ctx.target : null,
|
|
45561
|
+
replaced: replacedFieldKeys(plan)
|
|
45562
|
+
};
|
|
45563
|
+
}
|
|
45564
|
+
/**
|
|
45565
|
+
* `compositionFieldKey` of every field a REPLACE feature of `plan` owns — the
|
|
45566
|
+
* candidate's own, and a stored peer's `CompositionPeer.replaced` (D663): one
|
|
45567
|
+
* derivation, so the graph reads both the same way.
|
|
45568
|
+
*/
|
|
45569
|
+
function replacedFieldKeys(plan) {
|
|
45570
|
+
const replacing = new Set(plan.features.filter((f) => f.mode === "replace").map((f) => f.featureIndex));
|
|
45571
|
+
return new Set(plan.fields.filter((f) => replacing.has(f.featureIndex)).map(compositionFieldKey));
|
|
45572
|
+
}
|
|
45573
|
+
/**
|
|
45574
|
+
* A read of the candidate's own device. Its own composed output (a new device's
|
|
45575
|
+
* field, an ADDED field) is the slice-1 own-field rule; on an existing target
|
|
45576
|
+
* every other field — replaced, or not composed at all — is the NATIVE value,
|
|
45577
|
+
* valid when the device serves that cap natively (D663, rule 5).
|
|
45578
|
+
*/
|
|
45579
|
+
function selfReadProblems(read, at, fields, self) {
|
|
45580
|
+
const readKey = `${read.cap}.${read.fieldPath}`;
|
|
45581
|
+
if (fields.some((f) => compositionFieldKey(f) === readKey && !self.replaced.has(readKey))) return [];
|
|
45582
|
+
if (self.native === null) return [problem("source-field-unknown", at, `this device has no composed field \`${read.cap}.${read.fieldPath}\``)];
|
|
45583
|
+
if (isNativeCap(self.native, read.cap)) return [];
|
|
45584
|
+
return [problem("source-capability-missing", at, `the target device (device ${self.native.deviceId}) has no native \`${read.cap}\``)];
|
|
45585
|
+
}
|
|
45586
|
+
function sourceProblems(fields, ctx, self) {
|
|
45587
|
+
const selfKey = require_composition.compositionSourceKey(self.ref);
|
|
45826
45588
|
return fields.flatMap((field) => field.reads.flatMap((read) => {
|
|
45827
|
-
const at =
|
|
45828
|
-
const key = compositionSourceKey(read.source);
|
|
45829
|
-
if (key === selfKey) return
|
|
45589
|
+
const at = compositionFieldAt(field);
|
|
45590
|
+
const key = require_composition.compositionSourceKey(read.source);
|
|
45591
|
+
if (key === selfKey) return selfReadProblems(read, at, fields, self);
|
|
45830
45592
|
const desc = ctx.sources.get(key);
|
|
45831
45593
|
if (desc === void 0 || desc.kind === "unreadable") return [problem("source-unreadable", at, `could not read source \`${key}\` (${desc === void 0 ? "it was not read" : desc.error}) — the save is refused rather than stored unchecked`)];
|
|
45832
45594
|
if (desc.kind === "absent") return [problem("source-missing", at, `source \`${key}\` does not exist`)];
|
|
@@ -45839,8 +45601,9 @@ function sourceProblems(fields, ctx) {
|
|
|
45839
45601
|
* `<addonId>/<stableId>#<cap>.<fieldPath>`. When a node belongs to the
|
|
45840
45602
|
* CANDIDATE itself (this composition being saved), pull its `cap`/`fieldPath`
|
|
45841
45603
|
* back out so the refusal can point at that exact field, matching the
|
|
45842
|
-
* documented `features[N].fields.<path>` convention
|
|
45843
|
-
*
|
|
45604
|
+
* documented `features[N].fields.<path>` convention. A cap name has no `.`,
|
|
45605
|
+
* so splitting `rest` on the FIRST `.` is exact; an item leaf's remainder
|
|
45606
|
+
* (`items[desiccant].status`) is matched through `compositionFieldKey`.
|
|
45844
45607
|
*/
|
|
45845
45608
|
function candidateFieldOfNode(nodeKey, candidateKey) {
|
|
45846
45609
|
const prefix = `${candidateKey}#`;
|
|
@@ -45860,44 +45623,65 @@ function cyclePath(nodePath, candidateKey, fields) {
|
|
|
45860
45623
|
for (const nodeKey of nodePath) {
|
|
45861
45624
|
const hit = candidateFieldOfNode(nodeKey, candidateKey);
|
|
45862
45625
|
if (hit === null) continue;
|
|
45863
|
-
const
|
|
45864
|
-
|
|
45626
|
+
const hitKey = `${hit.cap}.${hit.fieldPath}`;
|
|
45627
|
+
const field = fields.find((f) => compositionFieldKey(f) === hitKey);
|
|
45628
|
+
if (field !== void 0) return compositionFieldAt(field);
|
|
45865
45629
|
}
|
|
45866
45630
|
return "features";
|
|
45867
45631
|
}
|
|
45632
|
+
/** The first unread device any of `nodes` belongs to; null when none does. */
|
|
45633
|
+
function unreadDeviceOf(nodes, unread) {
|
|
45634
|
+
for (const [key, error] of unread) if (nodes.some((node) => node.startsWith(`${key}#`))) return {
|
|
45635
|
+
key,
|
|
45636
|
+
error
|
|
45637
|
+
};
|
|
45638
|
+
return null;
|
|
45639
|
+
}
|
|
45868
45640
|
/**
|
|
45869
|
-
* Cycle check runs against the CANDIDATE (this composition,
|
|
45870
|
-
*
|
|
45871
|
-
*
|
|
45872
|
-
*
|
|
45873
|
-
*
|
|
45874
|
-
*
|
|
45641
|
+
* Cycle check runs against the CANDIDATE (this composition, as block
|
|
45642
|
+
* `ctx.blockId`, writing `self.ref`) plus every OTHER stored composition,
|
|
45643
|
+
* decided per strongly connected component (`findCandidateCycles`): a cyclic
|
|
45644
|
+
* component holding a candidate node refuses, with one representative cycle
|
|
45645
|
+
* through it; one without is not this save's cycle. A
|
|
45646
|
+
* stored composition of the same block is its old version; another block on
|
|
45647
|
+
* the same device, or two stored peers sharing a device, make
|
|
45648
|
+
* `compositionEdges` throw `CompositionGraphError` — refused BY NAME as
|
|
45649
|
+
* `duplicate-target` (D391, D663) instead of escaping as an uncaught throw.
|
|
45875
45650
|
*/
|
|
45876
|
-
function cycleProblems(composition, ctx, fields) {
|
|
45651
|
+
function cycleProblems(composition, ctx, fields, self) {
|
|
45877
45652
|
const candidate = {
|
|
45878
|
-
|
|
45879
|
-
|
|
45653
|
+
blockId: ctx.blockId ?? "(unsaved)",
|
|
45654
|
+
target: self.ref,
|
|
45655
|
+
composition,
|
|
45656
|
+
replaced: self.replaced
|
|
45880
45657
|
};
|
|
45881
|
-
const candidateKey = compositionSourceKey(candidate.target);
|
|
45658
|
+
const candidateKey = require_composition.compositionSourceKey(candidate.target);
|
|
45659
|
+
const unread = ctx.unreadTargets ?? /* @__PURE__ */ new Map();
|
|
45882
45660
|
try {
|
|
45883
|
-
return
|
|
45661
|
+
return findCandidateCycles(candidate, ctx.peers).map((c) => {
|
|
45662
|
+
const at = cyclePath(c.path, candidateKey, fields);
|
|
45663
|
+
const through = unreadDeviceOf([...c.component], unread);
|
|
45664
|
+
return through === null ? problem("cycle", at, `a field reads itself: ${c.path.join(" → ")}`) : problem("cycle", at, `possible cycle through \`${through.key}\` — its state could not be read (${through.error}): ${c.path.join(" → ")}`);
|
|
45665
|
+
});
|
|
45884
45666
|
} catch (err) {
|
|
45885
45667
|
if (err instanceof CompositionGraphError) return [problem("duplicate-target", "features", err.message)];
|
|
45886
45668
|
throw err;
|
|
45887
45669
|
}
|
|
45888
45670
|
}
|
|
45889
45671
|
function validateComposition(composition, ctx) {
|
|
45890
|
-
const plan = planComposition(composition, ctx.lookupCap);
|
|
45891
|
-
const
|
|
45672
|
+
const plan = planComposition(composition, ctx.lookupCap, ctx.target ?? void 0);
|
|
45673
|
+
const self = candidateSelf(composition, ctx, plan);
|
|
45674
|
+
const cycles = cycleProblems(composition, ctx, plan.fields, self);
|
|
45892
45675
|
const problems = [
|
|
45893
45676
|
...plan.problems,
|
|
45894
|
-
...sourceProblems(plan.fields, ctx),
|
|
45677
|
+
...sourceProblems(plan.fields, ctx, self),
|
|
45895
45678
|
...cycles
|
|
45896
45679
|
];
|
|
45897
45680
|
return {
|
|
45898
45681
|
ok: problems.length === 0,
|
|
45899
45682
|
problems,
|
|
45900
|
-
fields: [...plan.fields]
|
|
45683
|
+
fields: [...plan.fields],
|
|
45684
|
+
features: [...plan.features]
|
|
45901
45685
|
};
|
|
45902
45686
|
}
|
|
45903
45687
|
//#endregion
|
|
@@ -46062,14 +45846,14 @@ var RUNTIME_DEFAULTS = {
|
|
|
46062
45846
|
* any role works, including non-accessory ones like Doorbell).
|
|
46063
45847
|
*/
|
|
46064
45848
|
var AccessoryKind = {
|
|
46065
|
-
Siren:
|
|
46066
|
-
Floodlight:
|
|
46067
|
-
Spotlight:
|
|
46068
|
-
PirSensor:
|
|
46069
|
-
Chime:
|
|
46070
|
-
Autotrack:
|
|
46071
|
-
Nightvision:
|
|
46072
|
-
PrivacyMask:
|
|
45849
|
+
Siren: require_err_msg.DeviceRole.Siren,
|
|
45850
|
+
Floodlight: require_err_msg.DeviceRole.Floodlight,
|
|
45851
|
+
Spotlight: require_err_msg.DeviceRole.Spotlight,
|
|
45852
|
+
PirSensor: require_err_msg.DeviceRole.PirSensor,
|
|
45853
|
+
Chime: require_err_msg.DeviceRole.Chime,
|
|
45854
|
+
Autotrack: require_err_msg.DeviceRole.Autotrack,
|
|
45855
|
+
Nightvision: require_err_msg.DeviceRole.Nightvision,
|
|
45856
|
+
PrivacyMask: require_err_msg.DeviceRole.PrivacyMask
|
|
46073
45857
|
};
|
|
46074
45858
|
/**
|
|
46075
45859
|
* Default English label for each accessory kind. Drivers append this
|
|
@@ -46212,38 +45996,31 @@ var DeviceConfig = class DeviceConfig {
|
|
|
46212
45996
|
};
|
|
46213
45997
|
//#endregion
|
|
46214
45998
|
//#region src/device/device-runtime-state.ts
|
|
46215
|
-
/**
|
|
46216
|
-
* Concrete implementation. Routes every successful write through
|
|
46217
|
-
* `writer(capName, slice)` — the kernel hooks this up to
|
|
46218
|
-
* `device-state.setCapSlice`, the canonical cross-layer write
|
|
46219
|
-
* entrypoint, which handles disk persistence (debounced on the hub)
|
|
46220
|
-
* and mirror updates.
|
|
46221
|
-
*
|
|
46222
|
-
* Schema validation runs in-process before the writer is called —
|
|
46223
|
-
* the round-trip should never carry an invalid slice. `flush()`
|
|
46224
|
-
* awaits any in-flight writer promises so shutdown is lossless.
|
|
46225
|
-
*
|
|
46226
|
-
* `initial` is the persisted blob loaded at boot. Slices for caps
|
|
46227
|
-
* whose schema hasn't been installed yet are kept in-memory verbatim
|
|
46228
|
-
* and validated when the cap registers later.
|
|
46229
|
-
*/
|
|
46230
45999
|
var DeviceRuntimeState = class DeviceRuntimeState {
|
|
46231
46000
|
writer;
|
|
46001
|
+
onWriteFailed;
|
|
46232
46002
|
/** In-flight writer promises tracked so `flush()` can await them. */
|
|
46233
46003
|
pendingWrites = /* @__PURE__ */ new Set();
|
|
46004
|
+
/**
|
|
46005
|
+
* Caps whose last write the hub refused. The equality gate in
|
|
46006
|
+
* `applyCapWrite` is bypassed for these, so the SAME value is re-sent on the
|
|
46007
|
+
* next write instead of being swallowed forever; a landing write clears it.
|
|
46008
|
+
*/
|
|
46009
|
+
failedWrites = /* @__PURE__ */ new Set();
|
|
46234
46010
|
/** Per-cap committed slice — after schema validation when known. */
|
|
46235
46011
|
slices;
|
|
46236
46012
|
/** Per-cap registered schema (set by `installCapSchema`). */
|
|
46237
46013
|
schemas = /* @__PURE__ */ new Map();
|
|
46238
46014
|
listeners = /* @__PURE__ */ new Set();
|
|
46239
46015
|
capListeners = /* @__PURE__ */ new Map();
|
|
46240
|
-
constructor(initial, writer) {
|
|
46016
|
+
constructor(initial, writer, onWriteFailed) {
|
|
46241
46017
|
this.writer = writer;
|
|
46018
|
+
this.onWriteFailed = onWriteFailed;
|
|
46242
46019
|
this.slices = /* @__PURE__ */ new Map();
|
|
46243
46020
|
for (const [k, v] of Object.entries(initial)) if (v && typeof v === "object" && !Array.isArray(v)) this.slices.set(k, { ...v });
|
|
46244
46021
|
}
|
|
46245
|
-
static fromInitial(initial, writer) {
|
|
46246
|
-
return new DeviceRuntimeState(initial, writer);
|
|
46022
|
+
static fromInitial(initial, writer, onWriteFailed) {
|
|
46023
|
+
return new DeviceRuntimeState(initial, writer, onWriteFailed);
|
|
46247
46024
|
}
|
|
46248
46025
|
installCapSchema(capName, schema) {
|
|
46249
46026
|
const existing = this.schemas.get(capName);
|
|
@@ -46287,10 +46064,15 @@ var DeviceRuntimeState = class DeviceRuntimeState {
|
|
|
46287
46064
|
...value
|
|
46288
46065
|
} : { ...value };
|
|
46289
46066
|
const parsed = schema.parse(next);
|
|
46290
|
-
if (shallowEqual(current, parsed)) return;
|
|
46067
|
+
if (shallowEqual(current, parsed) && !this.failedWrites.has(capName)) return;
|
|
46291
46068
|
this.slices.set(capName, parsed);
|
|
46292
46069
|
this.fireListeners([capName]);
|
|
46293
|
-
const writePromise = this.writer(capName, { ...parsed }).
|
|
46070
|
+
const writePromise = this.writer(capName, { ...parsed }).then(() => {
|
|
46071
|
+
this.failedWrites.delete(capName);
|
|
46072
|
+
}).catch((err) => {
|
|
46073
|
+
this.failedWrites.add(capName);
|
|
46074
|
+
this.onWriteFailed?.(capName, err instanceof Error ? err.message : String(err));
|
|
46075
|
+
});
|
|
46294
46076
|
this.pendingWrites.add(writePromise);
|
|
46295
46077
|
writePromise.finally(() => {
|
|
46296
46078
|
this.pendingWrites.delete(writePromise);
|
|
@@ -46571,7 +46353,16 @@ var BaseDevice = class {
|
|
|
46571
46353
|
});
|
|
46572
46354
|
};
|
|
46573
46355
|
const initial = ctx.initialRuntimeState ?? {};
|
|
46574
|
-
|
|
46356
|
+
const onWriteFailed = (cap, error) => {
|
|
46357
|
+
ctx.logger.warn("runtime-state write refused by the hub — the slice is not mirrored; it is re-sent on the next write", {
|
|
46358
|
+
tags: { deviceId: ctx.id },
|
|
46359
|
+
meta: {
|
|
46360
|
+
cap,
|
|
46361
|
+
error
|
|
46362
|
+
}
|
|
46363
|
+
});
|
|
46364
|
+
};
|
|
46365
|
+
this.runtimeState = DeviceRuntimeState.fromInitial(initial, writer, onWriteFailed);
|
|
46575
46366
|
ctx.bindRuntimeState?.(this.runtimeState);
|
|
46576
46367
|
ctx.registerNativeCap?.(deviceStatusCapability, {});
|
|
46577
46368
|
const seed = {
|
|
@@ -47166,7 +46957,7 @@ var BaseDeviceProvider = class extends require_sleep.BaseAddon {
|
|
|
47166
46957
|
*/
|
|
47167
46958
|
async getManualCreationType() {
|
|
47168
46959
|
if (!await this.supportsManualCreation()) return { deviceType: null };
|
|
47169
|
-
return { deviceType: Object.values(
|
|
46960
|
+
return { deviceType: Object.values(require_err_msg.DeviceType).find((t) => this.deviceClasses[t] !== void 0) ?? null };
|
|
47170
46961
|
}
|
|
47171
46962
|
async adoptDiscoveredDevice(_input) {
|
|
47172
46963
|
throw new Error(`${this.providerName} provider does not support discovery-based adoption`);
|
|
@@ -47373,14 +47164,14 @@ var BaseDeviceProvider = class extends require_sleep.BaseAddon {
|
|
|
47373
47164
|
});
|
|
47374
47165
|
const meta = await this.ctx.api.deviceManager.loadMeta.query({ deviceId: id });
|
|
47375
47166
|
if (meta === null) throw new Error(`${this.providerName}: no persisted meta for "${stableId}" (id ${id}) — cannot reload`);
|
|
47376
|
-
const deviceType = Object.values(
|
|
47167
|
+
const deviceType = Object.values(require_err_msg.DeviceType).find((t) => t === meta.type);
|
|
47377
47168
|
const Class = deviceType !== void 0 ? this.deviceClasses[deviceType] : void 0;
|
|
47378
47169
|
if (!Class) throw new Error(`${this.providerName}: no device class for type "${meta.type}" — "${stableId}" is an accessory child; reload its parent instead`);
|
|
47379
47170
|
await devices.create(stableId, Class, {}, meta.parentDeviceId ?? null);
|
|
47380
47171
|
const rows = await this.ctx.api.deviceManager.listPersistedByAddon.query({ addonId: this.addonId });
|
|
47381
47172
|
for (const row of rows) {
|
|
47382
47173
|
if (row.parentDeviceId !== id) continue;
|
|
47383
|
-
const childType = Object.values(
|
|
47174
|
+
const childType = Object.values(require_err_msg.DeviceType).find((t) => t === row.type);
|
|
47384
47175
|
const ChildClass = childType !== void 0 ? this.deviceClasses[childType] : void 0;
|
|
47385
47176
|
if (!ChildClass) continue;
|
|
47386
47177
|
try {
|
|
@@ -47807,7 +47598,7 @@ function expandContainer(id, byId, byParent, visited, out) {
|
|
|
47807
47598
|
if (visited.has(id)) return;
|
|
47808
47599
|
const candidate = byId.get(id);
|
|
47809
47600
|
if (!candidate) return;
|
|
47810
|
-
if (candidate.type !==
|
|
47601
|
+
if (candidate.type !== require_err_msg.DeviceType.Container) {
|
|
47811
47602
|
out.add(id);
|
|
47812
47603
|
return;
|
|
47813
47604
|
}
|
|
@@ -47851,11 +47642,11 @@ function legacyAutoLinkIds(params) {
|
|
|
47851
47642
|
const ids = /* @__PURE__ */ new Set();
|
|
47852
47643
|
const expand = (id) => expandContainer(id, byId, byParent, /* @__PURE__ */ new Set(), ids);
|
|
47853
47644
|
for (const c of candidates) {
|
|
47854
|
-
if (c.type ===
|
|
47645
|
+
if (c.type === require_err_msg.DeviceType.Container) continue;
|
|
47855
47646
|
if (c.location !== selfLocation) continue;
|
|
47856
47647
|
if (c.parentDeviceId === selfId) continue;
|
|
47857
47648
|
const parent = c.parentDeviceId !== null ? byId.get(c.parentDeviceId) : void 0;
|
|
47858
|
-
if (parent !== void 0 && parent.type ===
|
|
47649
|
+
if (parent !== void 0 && parent.type === require_err_msg.DeviceType.Container) {
|
|
47859
47650
|
expand(parent.id);
|
|
47860
47651
|
continue;
|
|
47861
47652
|
}
|
|
@@ -48147,39 +47938,39 @@ var DeclaredDevices = class {
|
|
|
48147
47938
|
* placeholder HA types whose inline control renders a dash).
|
|
48148
47939
|
*/
|
|
48149
47940
|
var DEVICE_TYPE_CONTROL_KIND = {
|
|
48150
|
-
[
|
|
48151
|
-
[
|
|
48152
|
-
[
|
|
48153
|
-
[
|
|
48154
|
-
[
|
|
48155
|
-
[
|
|
48156
|
-
[
|
|
48157
|
-
[
|
|
48158
|
-
[
|
|
48159
|
-
[
|
|
48160
|
-
[
|
|
48161
|
-
[
|
|
48162
|
-
[
|
|
48163
|
-
[
|
|
48164
|
-
[
|
|
48165
|
-
[
|
|
48166
|
-
[
|
|
48167
|
-
[
|
|
48168
|
-
[
|
|
48169
|
-
[
|
|
48170
|
-
[
|
|
48171
|
-
[
|
|
48172
|
-
[
|
|
48173
|
-
[
|
|
48174
|
-
[
|
|
48175
|
-
[
|
|
48176
|
-
[
|
|
48177
|
-
[
|
|
48178
|
-
[
|
|
48179
|
-
[
|
|
48180
|
-
[
|
|
47941
|
+
[require_err_msg.DeviceType.Cover]: "cover",
|
|
47942
|
+
[require_err_msg.DeviceType.Valve]: "valve",
|
|
47943
|
+
[require_err_msg.DeviceType.Humidifier]: "humidifier",
|
|
47944
|
+
[require_err_msg.DeviceType.WaterHeater]: "water-heater",
|
|
47945
|
+
[require_err_msg.DeviceType.Camera]: "dummy",
|
|
47946
|
+
[require_err_msg.DeviceType.Hub]: "dummy",
|
|
47947
|
+
[require_err_msg.DeviceType.Switch]: "switch",
|
|
47948
|
+
[require_err_msg.DeviceType.Siren]: "switch",
|
|
47949
|
+
[require_err_msg.DeviceType.Light]: "light",
|
|
47950
|
+
[require_err_msg.DeviceType.Fan]: "fan",
|
|
47951
|
+
[require_err_msg.DeviceType.Sensor]: "sensor",
|
|
47952
|
+
[require_err_msg.DeviceType.Thermostat]: "thermostat",
|
|
47953
|
+
[require_err_msg.DeviceType.Climate]: "climate",
|
|
47954
|
+
[require_err_msg.DeviceType.Button]: "button",
|
|
47955
|
+
[require_err_msg.DeviceType.EventEmitter]: "dummy",
|
|
47956
|
+
[require_err_msg.DeviceType.Update]: "update",
|
|
47957
|
+
[require_err_msg.DeviceType.Generic]: "dummy",
|
|
47958
|
+
[require_err_msg.DeviceType.Notifier]: "dummy",
|
|
47959
|
+
[require_err_msg.DeviceType.Script]: "script",
|
|
47960
|
+
[require_err_msg.DeviceType.Automation]: "automation",
|
|
47961
|
+
[require_err_msg.DeviceType.Lock]: "lock",
|
|
47962
|
+
[require_err_msg.DeviceType.MediaPlayer]: "media-player",
|
|
47963
|
+
[require_err_msg.DeviceType.AlarmPanel]: "alarm",
|
|
47964
|
+
[require_err_msg.DeviceType.Control]: "control",
|
|
47965
|
+
[require_err_msg.DeviceType.Presence]: "sensor",
|
|
47966
|
+
[require_err_msg.DeviceType.Weather]: "weather",
|
|
47967
|
+
[require_err_msg.DeviceType.Vacuum]: "vacuum",
|
|
47968
|
+
[require_err_msg.DeviceType.LawnMower]: "lawn-mower",
|
|
47969
|
+
[require_err_msg.DeviceType.Container]: "dummy",
|
|
47970
|
+
[require_err_msg.DeviceType.Image]: "image",
|
|
47971
|
+
[require_err_msg.DeviceType.PetFeeder]: "pet-feeder"
|
|
48181
47972
|
};
|
|
48182
|
-
var DEVICE_TYPE_VALUES = new Set(Object.values(
|
|
47973
|
+
var DEVICE_TYPE_VALUES = new Set(Object.values(require_err_msg.DeviceType));
|
|
48183
47974
|
/**
|
|
48184
47975
|
* Runtime-string-safe base resolver: a device row's `type` crosses the wire as
|
|
48185
47976
|
* a plain string, so an unrecognised value resolves to `null` instead of
|
|
@@ -48223,15 +48014,15 @@ var SENSOR_FEATURES = [
|
|
|
48223
48014
|
function pickAccessoryControl(device) {
|
|
48224
48015
|
const set = new Set(device.features);
|
|
48225
48016
|
switch (device.type) {
|
|
48226
|
-
case
|
|
48227
|
-
case
|
|
48228
|
-
case
|
|
48229
|
-
case
|
|
48230
|
-
case
|
|
48231
|
-
case
|
|
48232
|
-
case
|
|
48233
|
-
case
|
|
48234
|
-
case
|
|
48017
|
+
case require_err_msg.DeviceType.Cover: return { kind: "cover" };
|
|
48018
|
+
case require_err_msg.DeviceType.Valve: return { kind: "valve" };
|
|
48019
|
+
case require_err_msg.DeviceType.Lock: return { kind: "lock" };
|
|
48020
|
+
case require_err_msg.DeviceType.AlarmPanel: return { kind: "alarm" };
|
|
48021
|
+
case require_err_msg.DeviceType.Light: return set.has("brightness") ? { kind: "brightness" } : { kind: "switch" };
|
|
48022
|
+
case require_err_msg.DeviceType.Switch:
|
|
48023
|
+
case require_err_msg.DeviceType.Siren: return { kind: "switch" };
|
|
48024
|
+
case require_err_msg.DeviceType.Sensor:
|
|
48025
|
+
case require_err_msg.DeviceType.Presence: {
|
|
48235
48026
|
const sensor = SENSOR_FEATURES.find((f) => set.has(f));
|
|
48236
48027
|
return sensor ? {
|
|
48237
48028
|
kind: "sensor",
|
|
@@ -48310,7 +48101,7 @@ function deviceMatchesProfile(features, profile) {
|
|
|
48310
48101
|
var BATTERY_DEVICE_PROFILE = {
|
|
48311
48102
|
id: "battery",
|
|
48312
48103
|
label: "Battery-operated camera",
|
|
48313
|
-
when: { hasFeature:
|
|
48104
|
+
when: { hasFeature: require_err_msg.DeviceFeature.BatteryOperated },
|
|
48314
48105
|
defaults: {
|
|
48315
48106
|
audioMode: "disabled",
|
|
48316
48107
|
detectionMode: "on-motion"
|
|
@@ -52941,6 +52732,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
52941
52732
|
addonId: null,
|
|
52942
52733
|
access: "view"
|
|
52943
52734
|
},
|
|
52735
|
+
"coreBlocks.getCustomization": {
|
|
52736
|
+
capName: "core-blocks",
|
|
52737
|
+
capScope: "system",
|
|
52738
|
+
addonId: null,
|
|
52739
|
+
access: "view"
|
|
52740
|
+
},
|
|
52944
52741
|
"coreBlocks.getTypeDefs": {
|
|
52945
52742
|
capName: "core-blocks",
|
|
52946
52743
|
capScope: "system",
|
|
@@ -54063,6 +53860,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
54063
53860
|
addonId: null,
|
|
54064
53861
|
access: "create"
|
|
54065
53862
|
},
|
|
53863
|
+
"deviceState.claimFields": {
|
|
53864
|
+
capName: "device-state",
|
|
53865
|
+
capScope: "system",
|
|
53866
|
+
addonId: null,
|
|
53867
|
+
access: "create"
|
|
53868
|
+
},
|
|
54066
53869
|
"deviceState.getAllSnapshots": {
|
|
54067
53870
|
capName: "device-state",
|
|
54068
53871
|
capScope: "system",
|
|
@@ -54075,12 +53878,36 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
54075
53878
|
addonId: null,
|
|
54076
53879
|
access: "view"
|
|
54077
53880
|
},
|
|
53881
|
+
"deviceState.getNativeCapSlice": {
|
|
53882
|
+
capName: "device-state",
|
|
53883
|
+
capScope: "system",
|
|
53884
|
+
addonId: null,
|
|
53885
|
+
access: "view"
|
|
53886
|
+
},
|
|
54078
53887
|
"deviceState.getSnapshot": {
|
|
54079
53888
|
capName: "device-state",
|
|
54080
53889
|
capScope: "system",
|
|
54081
53890
|
addonId: null,
|
|
54082
53891
|
access: "view"
|
|
54083
53892
|
},
|
|
53893
|
+
"deviceState.listClaims": {
|
|
53894
|
+
capName: "device-state",
|
|
53895
|
+
capScope: "system",
|
|
53896
|
+
addonId: null,
|
|
53897
|
+
access: "view"
|
|
53898
|
+
},
|
|
53899
|
+
"deviceState.patchOwnedFields": {
|
|
53900
|
+
capName: "device-state",
|
|
53901
|
+
capScope: "system",
|
|
53902
|
+
addonId: null,
|
|
53903
|
+
access: "create"
|
|
53904
|
+
},
|
|
53905
|
+
"deviceState.releaseClaim": {
|
|
53906
|
+
capName: "device-state",
|
|
53907
|
+
capScope: "system",
|
|
53908
|
+
addonId: null,
|
|
53909
|
+
access: "create"
|
|
53910
|
+
},
|
|
54084
53911
|
"deviceState.setCapSlice": {
|
|
54085
53912
|
capName: "device-state",
|
|
54086
53913
|
capScope: "system",
|
|
@@ -59931,16 +59758,36 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
|
|
|
59931
59758
|
form: "single",
|
|
59932
59759
|
optional: false
|
|
59933
59760
|
}],
|
|
59761
|
+
"deviceState.claimFields": [{
|
|
59762
|
+
name: "deviceId",
|
|
59763
|
+
form: "single",
|
|
59764
|
+
optional: false
|
|
59765
|
+
}],
|
|
59934
59766
|
"deviceState.getCapSlice": [{
|
|
59935
59767
|
name: "deviceId",
|
|
59936
59768
|
form: "single",
|
|
59937
59769
|
optional: false
|
|
59938
59770
|
}],
|
|
59771
|
+
"deviceState.getNativeCapSlice": [{
|
|
59772
|
+
name: "deviceId",
|
|
59773
|
+
form: "single",
|
|
59774
|
+
optional: false
|
|
59775
|
+
}],
|
|
59939
59776
|
"deviceState.getSnapshot": [{
|
|
59940
59777
|
name: "deviceId",
|
|
59941
59778
|
form: "single",
|
|
59942
59779
|
optional: false
|
|
59943
59780
|
}],
|
|
59781
|
+
"deviceState.patchOwnedFields": [{
|
|
59782
|
+
name: "deviceId",
|
|
59783
|
+
form: "single",
|
|
59784
|
+
optional: false
|
|
59785
|
+
}],
|
|
59786
|
+
"deviceState.releaseClaim": [{
|
|
59787
|
+
name: "deviceId",
|
|
59788
|
+
form: "single",
|
|
59789
|
+
optional: false
|
|
59790
|
+
}],
|
|
59944
59791
|
"deviceState.setCapSlice": [{
|
|
59945
59792
|
name: "deviceId",
|
|
59946
59793
|
form: "single",
|
|
@@ -61436,8 +61283,12 @@ var SYSTEM_SCOPE_DEVICE_METHODS = [
|
|
|
61436
61283
|
"deviceManager.updateConfig",
|
|
61437
61284
|
"deviceManager.updateDeviceField",
|
|
61438
61285
|
"deviceManager.updateDeviceFieldsBatch",
|
|
61286
|
+
"deviceState.claimFields",
|
|
61439
61287
|
"deviceState.getCapSlice",
|
|
61288
|
+
"deviceState.getNativeCapSlice",
|
|
61440
61289
|
"deviceState.getSnapshot",
|
|
61290
|
+
"deviceState.patchOwnedFields",
|
|
61291
|
+
"deviceState.releaseClaim",
|
|
61441
61292
|
"deviceState.setCapSlice",
|
|
61442
61293
|
"faceGallery.getFaceByTrack",
|
|
61443
61294
|
"faceGallery.listRecentFaces",
|
|
@@ -62117,6 +61968,7 @@ function createSystemProxy(api) {
|
|
|
62117
61968
|
updateComposition: (input) => dispatch("coreBlocks", "updateComposition", "mutation", input),
|
|
62118
61969
|
getComposition: (input) => dispatch("coreBlocks", "getComposition", "query", input),
|
|
62119
61970
|
listCompositions: (input) => dispatch("coreBlocks", "listCompositions", "query", input),
|
|
61971
|
+
getCustomization: (input) => dispatch("coreBlocks", "getCustomization", "query", input),
|
|
62120
61972
|
validateComposition: (input) => dispatch("coreBlocks", "validateComposition", "mutation", input)
|
|
62121
61973
|
},
|
|
62122
61974
|
decoder: {
|
|
@@ -62220,7 +62072,10 @@ function createSystemProxy(api) {
|
|
|
62220
62072
|
createDevice: (input) => dispatch("deviceProvider", "createDevice", "mutation", input),
|
|
62221
62073
|
testCreationField: (input) => dispatch("deviceProvider", "testCreationField", "mutation", input)
|
|
62222
62074
|
},
|
|
62223
|
-
deviceState: {
|
|
62075
|
+
deviceState: {
|
|
62076
|
+
getAllSnapshots: (input) => dispatch("deviceState", "getAllSnapshots", "query", input),
|
|
62077
|
+
listClaims: (input) => dispatch("deviceState", "listClaims", "query", input)
|
|
62078
|
+
},
|
|
62224
62079
|
faceGallery: {
|
|
62225
62080
|
listIdentities: (input) => dispatch("faceGallery", "listIdentities", "query", input),
|
|
62226
62081
|
createIdentity: (input) => dispatch("faceGallery", "createIdentity", "mutation", input),
|
|
@@ -68278,7 +68133,7 @@ exports.AUDIO_BACKEND_CHOICES = AUDIO_BACKEND_CHOICES;
|
|
|
68278
68133
|
exports.AUDIO_CHUNK_FORMATS = require_sleep.AUDIO_CHUNK_FORMATS;
|
|
68279
68134
|
exports.AUDIO_MACRO_LABELS = AUDIO_MACRO_LABELS;
|
|
68280
68135
|
exports.AUDIO_NOT_CLASSIFIED_REASONS = AUDIO_NOT_CLASSIFIED_REASONS;
|
|
68281
|
-
exports.AUDIO_PRESETS =
|
|
68136
|
+
exports.AUDIO_PRESETS = require_composition.AUDIO_PRESETS;
|
|
68282
68137
|
exports.AUDIO_SCALE_EPOCH_ISO = AUDIO_SCALE_EPOCH_ISO;
|
|
68283
68138
|
exports.AUDIO_SCALE_EPOCH_MS = AUDIO_SCALE_EPOCH_MS;
|
|
68284
68139
|
exports.AccessoriesStatusSchema = AccessoriesStatusSchema;
|
|
@@ -68428,13 +68283,17 @@ exports.CLUSTER_MODEL_SECTION_ID = CLUSTER_MODEL_SECTION_ID;
|
|
|
68428
68283
|
exports.CLUSTER_STEP_SETTING_FIELDS = CLUSTER_STEP_SETTING_FIELDS;
|
|
68429
68284
|
exports.COCO_80_LABELS = COCO_80_LABELS;
|
|
68430
68285
|
exports.COCO_TO_MACRO = COCO_TO_MACRO;
|
|
68431
|
-
exports.COMPOSED_DEVICE_STABLE_ID_PREFIX = COMPOSED_DEVICE_STABLE_ID_PREFIX;
|
|
68432
|
-
exports.
|
|
68286
|
+
exports.COMPOSED_DEVICE_STABLE_ID_PREFIX = require_composition.COMPOSED_DEVICE_STABLE_ID_PREFIX;
|
|
68287
|
+
exports.COMPOSED_ITEM_FIXED_FIELDS = COMPOSED_ITEM_FIXED_FIELDS;
|
|
68288
|
+
exports.COMPOSER_ADDON_ID = require_composition.COMPOSER_ADDON_ID;
|
|
68433
68289
|
exports.COMPOSER_RUNNER_ID = COMPOSER_RUNNER_ID;
|
|
68290
|
+
exports.COMPOSITION_ITEM_ARRAY_PATH = require_composition.COMPOSITION_ITEM_ARRAY_PATH;
|
|
68291
|
+
exports.COMPOSITION_ITEM_KEY_RE = require_composition.COMPOSITION_ITEM_KEY_RE;
|
|
68434
68292
|
exports.CONNECTION_TEST_TIMEOUT_MS = CONNECTION_TEST_TIMEOUT_MS;
|
|
68435
68293
|
exports.CONTAINER_CHILD_PRIORITY = CONTAINER_CHILD_PRIORITY;
|
|
68436
68294
|
exports.CORE_BLOCKS_ADDON_ID = CORE_BLOCKS_ADDON_ID;
|
|
68437
68295
|
exports.CORE_BLOCK_ADDON_PREFIX = CORE_BLOCK_ADDON_PREFIX;
|
|
68296
|
+
exports.CUSTOMIZATION_BLOCK_NAME_PREFIX = require_composition.CUSTOMIZATION_BLOCK_NAME_PREFIX;
|
|
68438
68297
|
exports.CamProfileSchema = require_sleep.CamProfileSchema;
|
|
68439
68298
|
exports.CamStreamDescriptorSchema = CamStreamDescriptorSchema;
|
|
68440
68299
|
exports.CamStreamKindSchema = require_sleep.CamStreamKindSchema;
|
|
@@ -68474,7 +68333,9 @@ exports.CandidateQueryFilterSchema = CandidateQueryFilterSchema;
|
|
|
68474
68333
|
exports.CapScopeSchema = CapScopeSchema;
|
|
68475
68334
|
exports.CapabilityBindingsSchema = CapabilityBindingsSchema;
|
|
68476
68335
|
exports.CarbonMonoxideStatusSchema = CarbonMonoxideStatusSchema;
|
|
68477
|
-
exports.ChargingStatus =
|
|
68336
|
+
exports.ChargingStatus = require_err_msg.ChargingStatus;
|
|
68337
|
+
exports.ClaimOutcomeSchema = ClaimOutcomeSchema;
|
|
68338
|
+
exports.ClaimsListingSchema = ClaimsListingSchema;
|
|
68478
68339
|
exports.ClientNetworkStatsSchema = ClientNetworkStatsSchema;
|
|
68479
68340
|
exports.ClimateControlStatusSchema = ClimateControlStatusSchema;
|
|
68480
68341
|
exports.ClipBytesOfferSchema = ClipBytesOfferSchema;
|
|
@@ -68504,37 +68365,42 @@ exports.ComposerApplyResultSchema = ComposerApplyResultSchema;
|
|
|
68504
68365
|
exports.ComposerBlockSchema = ComposerBlockSchema;
|
|
68505
68366
|
exports.ComposerBlockVerdictSchema = ComposerBlockVerdictSchema;
|
|
68506
68367
|
exports.ComposerUnreadableBlockSchema = ComposerUnreadableBlockSchema;
|
|
68507
|
-
exports.CompositionBindingSchema = CompositionBindingSchema;
|
|
68368
|
+
exports.CompositionBindingSchema = require_composition.CompositionBindingSchema;
|
|
68508
68369
|
exports.CompositionBlockInputSchema = CompositionBlockInputSchema;
|
|
68509
68370
|
exports.CompositionBlockStateSchema = CompositionBlockStateSchema;
|
|
68510
|
-
exports.CompositionCodeSourceSchema = CompositionCodeSourceSchema;
|
|
68511
|
-
exports.CompositionCommandTargetSchema = CompositionCommandTargetSchema;
|
|
68512
|
-
exports.
|
|
68513
|
-
exports.
|
|
68514
|
-
exports.
|
|
68371
|
+
exports.CompositionCodeSourceSchema = require_composition.CompositionCodeSourceSchema;
|
|
68372
|
+
exports.CompositionCommandTargetSchema = require_composition.CompositionCommandTargetSchema;
|
|
68373
|
+
exports.CompositionCustomizationReadSchema = CompositionCustomizationReadSchema;
|
|
68374
|
+
exports.CompositionExistingTargetSchema = require_composition.CompositionExistingTargetSchema;
|
|
68375
|
+
exports.CompositionExpressionSourceSchema = require_composition.CompositionExpressionSourceSchema;
|
|
68376
|
+
exports.CompositionFeatureModeSchema = CompositionFeatureModeSchema;
|
|
68377
|
+
exports.CompositionFeaturePlanSchema = CompositionFeaturePlanSchema;
|
|
68378
|
+
exports.CompositionFeatureSchema = require_composition.CompositionFeatureSchema;
|
|
68379
|
+
exports.CompositionFieldItemSchema = CompositionFieldItemSchema;
|
|
68515
68380
|
exports.CompositionFieldKindSchema = CompositionFieldKindSchema;
|
|
68516
68381
|
exports.CompositionFieldPlanSchema = CompositionFieldPlanSchema;
|
|
68517
|
-
exports.CompositionFieldReadSchema = CompositionFieldReadSchema;
|
|
68382
|
+
exports.CompositionFieldReadSchema = require_composition.CompositionFieldReadSchema;
|
|
68518
68383
|
exports.CompositionFieldRoleSchema = CompositionFieldRoleSchema;
|
|
68519
|
-
exports.CompositionFieldSourceSchema = CompositionFieldSourceSchema;
|
|
68384
|
+
exports.CompositionFieldSourceSchema = require_composition.CompositionFieldSourceSchema;
|
|
68520
68385
|
exports.CompositionFieldStateKindSchema = CompositionFieldStateKindSchema;
|
|
68521
68386
|
exports.CompositionFieldStateSchema = CompositionFieldStateSchema;
|
|
68522
|
-
exports.CompositionFieldsFeatureSchema = CompositionFieldsFeatureSchema;
|
|
68523
|
-
exports.CompositionForwardCommandSchema = CompositionForwardCommandSchema;
|
|
68524
|
-
exports.CompositionFromSourceSchema = CompositionFromSourceSchema;
|
|
68387
|
+
exports.CompositionFieldsFeatureSchema = require_composition.CompositionFieldsFeatureSchema;
|
|
68388
|
+
exports.CompositionForwardCommandSchema = require_composition.CompositionForwardCommandSchema;
|
|
68389
|
+
exports.CompositionFromSourceSchema = require_composition.CompositionFromSourceSchema;
|
|
68525
68390
|
exports.CompositionGetReadSchema = CompositionGetReadSchema;
|
|
68526
68391
|
exports.CompositionGraphError = CompositionGraphError;
|
|
68392
|
+
exports.CompositionItemEntrySchema = require_composition.CompositionItemEntrySchema;
|
|
68527
68393
|
exports.CompositionListReadSchema = CompositionListReadSchema;
|
|
68528
|
-
exports.CompositionLiteralBindingSchema = CompositionLiteralBindingSchema;
|
|
68529
|
-
exports.CompositionNewTargetSchema = CompositionNewTargetSchema;
|
|
68530
|
-
exports.CompositionPassthroughFeatureSchema = CompositionPassthroughFeatureSchema;
|
|
68394
|
+
exports.CompositionLiteralBindingSchema = require_composition.CompositionLiteralBindingSchema;
|
|
68395
|
+
exports.CompositionNewTargetSchema = require_composition.CompositionNewTargetSchema;
|
|
68396
|
+
exports.CompositionPassthroughFeatureSchema = require_composition.CompositionPassthroughFeatureSchema;
|
|
68531
68397
|
exports.CompositionProblemCodeSchema = CompositionProblemCodeSchema;
|
|
68532
68398
|
exports.CompositionProblemSchema = CompositionProblemSchema;
|
|
68533
68399
|
exports.CompositionRunStatusSchema = CompositionRunStatusSchema;
|
|
68534
|
-
exports.CompositionSchema = CompositionSchema;
|
|
68535
|
-
exports.CompositionSourceRefSchema = CompositionSourceRefSchema;
|
|
68400
|
+
exports.CompositionSchema = require_composition.CompositionSchema;
|
|
68401
|
+
exports.CompositionSourceRefSchema = require_composition.CompositionSourceRefSchema;
|
|
68536
68402
|
exports.CompositionStateReadSchema = CompositionStateReadSchema;
|
|
68537
|
-
exports.CompositionTargetSchema = CompositionTargetSchema;
|
|
68403
|
+
exports.CompositionTargetSchema = require_composition.CompositionTargetSchema;
|
|
68538
68404
|
exports.CompositionUnavailableModeSchema = CompositionUnavailableModeSchema;
|
|
68539
68405
|
exports.CompositionValidationSchema = CompositionValidationSchema;
|
|
68540
68406
|
exports.CompositionViewSchema = CompositionViewSchema;
|
|
@@ -68546,6 +68412,8 @@ exports.ConnectionTestInputSchema = ConnectionTestInputSchema;
|
|
|
68546
68412
|
exports.ConnectionTestOutcomeSchema = ConnectionTestOutcomeSchema;
|
|
68547
68413
|
exports.ConnectivityStatusSchema = ConnectivityStatusSchema;
|
|
68548
68414
|
exports.ConsumableItemSchema = ConsumableItemSchema;
|
|
68415
|
+
exports.ConsumableRemainingSchema = ConsumableRemainingSchema;
|
|
68416
|
+
exports.ConsumableRemainingUnitSchema = ConsumableRemainingUnitSchema;
|
|
68549
68417
|
exports.ConsumablesStatusSchema = ConsumablesStatusSchema;
|
|
68550
68418
|
exports.ContactStatusSchema = ContactStatusSchema;
|
|
68551
68419
|
exports.ControlKindSchema = ControlKindSchema;
|
|
@@ -68639,15 +68507,15 @@ exports.DeviceDiscoveryStatusSchema = DeviceDiscoveryStatusSchema;
|
|
|
68639
68507
|
exports.DeviceExportExposeInputSchema = ExposeInputSchema;
|
|
68640
68508
|
exports.DeviceExportStatusSchema = DeviceExportStatusSchema;
|
|
68641
68509
|
exports.DeviceExportUnexposeInputSchema = UnexposeInputSchema;
|
|
68642
|
-
exports.DeviceFeature =
|
|
68510
|
+
exports.DeviceFeature = require_err_msg.DeviceFeature;
|
|
68643
68511
|
exports.DeviceInfoSchema = DeviceInfoSchema;
|
|
68644
68512
|
exports.DeviceNetworkStatsSchema = DeviceNetworkStatsSchema;
|
|
68645
68513
|
exports.DeviceRestoreRetryScheduler = DeviceRestoreRetryScheduler;
|
|
68646
|
-
exports.DeviceRole =
|
|
68514
|
+
exports.DeviceRole = require_err_msg.DeviceRole;
|
|
68647
68515
|
exports.DeviceRuntimeState = DeviceRuntimeState;
|
|
68648
68516
|
exports.DeviceSelectorSchema = DeviceSelectorSchema;
|
|
68649
68517
|
exports.DeviceStatusSchema = DeviceStatusSchema;
|
|
68650
|
-
exports.DeviceType =
|
|
68518
|
+
exports.DeviceType = require_err_msg.DeviceType;
|
|
68651
68519
|
exports.DiagnosticIdSchema = DiagnosticIdSchema;
|
|
68652
68520
|
exports.DiagnosticWindowPatchSchema = DiagnosticWindowPatchSchema;
|
|
68653
68521
|
exports.DiagnosticWindowSchema = DiagnosticWindowSchema;
|
|
@@ -68670,11 +68538,11 @@ exports.EVENT_OWNER_TYPES = EVENT_OWNER_TYPES;
|
|
|
68670
68538
|
exports.EVENT_PAD_MS = EVENT_PAD_MS;
|
|
68671
68539
|
exports.EVENT_TAXONOMY = EVENT_TAXONOMY;
|
|
68672
68540
|
exports.EXPORT_DENSE_MAX_RANGES = EXPORT_DENSE_MAX_RANGES;
|
|
68673
|
-
exports.EXPRESSION_BUILTINS = EXPRESSION_BUILTINS;
|
|
68674
|
-
exports.EXPRESSION_BUILTIN_NAMES = EXPRESSION_BUILTIN_NAMES;
|
|
68675
|
-
exports.EXPRESSION_COMPILE_CACHE_CAPACITY = EXPRESSION_COMPILE_CACHE_CAPACITY;
|
|
68676
|
-
exports.EXPRESSION_IDENTIFIER_RE = EXPRESSION_IDENTIFIER_RE;
|
|
68677
|
-
exports.EXPRESSION_INJECTED_NOW = EXPRESSION_INJECTED_NOW;
|
|
68541
|
+
exports.EXPRESSION_BUILTINS = require_composition.EXPRESSION_BUILTINS;
|
|
68542
|
+
exports.EXPRESSION_BUILTIN_NAMES = require_composition.EXPRESSION_BUILTIN_NAMES;
|
|
68543
|
+
exports.EXPRESSION_COMPILE_CACHE_CAPACITY = require_composition.EXPRESSION_COMPILE_CACHE_CAPACITY;
|
|
68544
|
+
exports.EXPRESSION_IDENTIFIER_RE = require_composition.EXPRESSION_IDENTIFIER_RE;
|
|
68545
|
+
exports.EXPRESSION_INJECTED_NOW = require_composition.EXPRESSION_INJECTED_NOW;
|
|
68678
68546
|
exports.EXTENSION_HOST_DEVICE_TYPES = EXTENSION_HOST_DEVICE_TYPES;
|
|
68679
68547
|
exports.EXTENSION_SLOTS = EXTENSION_SLOTS;
|
|
68680
68548
|
exports.EXTENSION_SLOT_IDS = EXTENSION_SLOT_IDS;
|
|
@@ -68730,11 +68598,11 @@ exports.ExportTimelapseSchema = ExportTimelapseSchema;
|
|
|
68730
68598
|
exports.ExposedDeviceSchema = ExposedDeviceSchema;
|
|
68731
68599
|
exports.ExposureModeSchema = ExposureModeSchema;
|
|
68732
68600
|
exports.ExpressionBindingSourceSchema = ExpressionBindingSourceSchema;
|
|
68733
|
-
exports.ExpressionEvalError = ExpressionEvalError;
|
|
68601
|
+
exports.ExpressionEvalError = require_composition.ExpressionEvalError;
|
|
68734
68602
|
exports.ExpressionFieldBindingSchema = ExpressionFieldBindingSchema;
|
|
68735
68603
|
exports.ExpressionGlobalBindingSchema = ExpressionGlobalBindingSchema;
|
|
68736
68604
|
exports.ExpressionLiteralBindingSchema = ExpressionLiteralBindingSchema;
|
|
68737
|
-
exports.ExpressionParseError = ExpressionParseError;
|
|
68605
|
+
exports.ExpressionParseError = require_composition.ExpressionParseError;
|
|
68738
68606
|
exports.ExpressionSourceSchema = ExpressionSourceSchema;
|
|
68739
68607
|
exports.ExtensionCandidateSchema = ExtensionCandidateSchema;
|
|
68740
68608
|
exports.ExtensionCandidatesSchema = ExtensionCandidatesSchema;
|
|
@@ -68751,6 +68619,8 @@ exports.ExtensionSlotValueSchema = ExtensionSlotValueSchema;
|
|
|
68751
68619
|
exports.ExtensionSourceAvailabilitySchema = ExtensionSourceAvailabilitySchema;
|
|
68752
68620
|
exports.ExtensionSourceHealthSchema = ExtensionSourceHealthSchema;
|
|
68753
68621
|
exports.ExtensionSourceSchema = ExtensionSourceSchema;
|
|
68622
|
+
exports.FEEDER_EXAMPLE_ADDON_ID = FEEDER_EXAMPLE_ADDON_ID;
|
|
68623
|
+
exports.FEEDER_EXAMPLE_HA_DEVICE_ID = FEEDER_EXAMPLE_HA_DEVICE_ID;
|
|
68754
68624
|
exports.FIRST_LEVEL_MACRO_CLASSES = FIRST_LEVEL_MACRO_CLASSES;
|
|
68755
68625
|
exports.FULL_IMAGE_BBOX = FULL_IMAGE_BBOX;
|
|
68756
68626
|
exports.FailureContributionSchema = FailureContributionSchema;
|
|
@@ -68760,8 +68630,10 @@ exports.FanControlStatusSchema = FanControlStatusSchema;
|
|
|
68760
68630
|
exports.FanDirectionSchema = FanDirectionSchema;
|
|
68761
68631
|
exports.FeatureManifestSchema = FeatureManifestSchema;
|
|
68762
68632
|
exports.FeatureProbeStatusSchema = FeatureProbeStatusSchema;
|
|
68633
|
+
exports.FieldClaimModeSchema = FieldClaimModeSchema;
|
|
68634
|
+
exports.FieldClaimSchema = FieldClaimSchema;
|
|
68763
68635
|
exports.FloodStatusSchema = FloodStatusSchema;
|
|
68764
|
-
exports.Fmp4BoxSplitter =
|
|
68636
|
+
exports.Fmp4BoxSplitter = require_composition.Fmp4BoxSplitter;
|
|
68765
68637
|
exports.FrameHandleFormatSchema = require_sleep.FrameHandleFormatSchema;
|
|
68766
68638
|
exports.FrameHandleSchema = require_sleep.FrameHandleSchema;
|
|
68767
68639
|
exports.FrameInputSchema = FrameInputSchema;
|
|
@@ -68890,16 +68762,17 @@ exports.MAX_BIRTH_DECISION_RECORDS = MAX_BIRTH_DECISION_RECORDS;
|
|
|
68890
68762
|
exports.MAX_BIRTH_LATENCY_PROXY_MS = MAX_BIRTH_LATENCY_PROXY_MS;
|
|
68891
68763
|
exports.MAX_CLIP_EVENT_IDS = MAX_CLIP_EVENT_IDS;
|
|
68892
68764
|
exports.MAX_CLIP_LABELS = MAX_CLIP_LABELS;
|
|
68893
|
-
exports.MAX_COMPOSITION_CODE_LENGTH = MAX_COMPOSITION_CODE_LENGTH;
|
|
68894
|
-
exports.MAX_COMPOSITION_FEATURES = MAX_COMPOSITION_FEATURES;
|
|
68895
|
-
exports.MAX_COMPOSITION_FIELDS_PER_FEATURE = MAX_COMPOSITION_FIELDS_PER_FEATURE;
|
|
68765
|
+
exports.MAX_COMPOSITION_CODE_LENGTH = require_composition.MAX_COMPOSITION_CODE_LENGTH;
|
|
68766
|
+
exports.MAX_COMPOSITION_FEATURES = require_composition.MAX_COMPOSITION_FEATURES;
|
|
68767
|
+
exports.MAX_COMPOSITION_FIELDS_PER_FEATURE = require_composition.MAX_COMPOSITION_FIELDS_PER_FEATURE;
|
|
68768
|
+
exports.MAX_COMPOSITION_ITEMS = require_composition.MAX_COMPOSITION_ITEMS;
|
|
68896
68769
|
exports.MAX_CONDITION_DEPTH = MAX_CONDITION_DEPTH;
|
|
68897
68770
|
exports.MAX_CONDITION_LEAVES = MAX_CONDITION_LEAVES;
|
|
68898
|
-
exports.MAX_EXPRESSION_AST_NODES = MAX_EXPRESSION_AST_NODES;
|
|
68899
|
-
exports.MAX_EXPRESSION_BINDINGS = MAX_EXPRESSION_BINDINGS;
|
|
68900
|
-
exports.MAX_EXPRESSION_CALL_ARGS = MAX_EXPRESSION_CALL_ARGS;
|
|
68901
|
-
exports.MAX_EXPRESSION_EVAL_STEPS = MAX_EXPRESSION_EVAL_STEPS;
|
|
68902
|
-
exports.MAX_EXPRESSION_SOURCE_LENGTH = MAX_EXPRESSION_SOURCE_LENGTH;
|
|
68771
|
+
exports.MAX_EXPRESSION_AST_NODES = require_composition.MAX_EXPRESSION_AST_NODES;
|
|
68772
|
+
exports.MAX_EXPRESSION_BINDINGS = require_composition.MAX_EXPRESSION_BINDINGS;
|
|
68773
|
+
exports.MAX_EXPRESSION_CALL_ARGS = require_composition.MAX_EXPRESSION_CALL_ARGS;
|
|
68774
|
+
exports.MAX_EXPRESSION_EVAL_STEPS = require_composition.MAX_EXPRESSION_EVAL_STEPS;
|
|
68775
|
+
exports.MAX_EXPRESSION_SOURCE_LENGTH = require_composition.MAX_EXPRESSION_SOURCE_LENGTH;
|
|
68903
68776
|
exports.MAX_KEYS = MAX_KEYS;
|
|
68904
68777
|
exports.MAX_REASONS_PER_KEY = MAX_REASONS_PER_KEY;
|
|
68905
68778
|
exports.MAX_SENSOR_TRIGGER_DEVICES = MAX_SENSOR_TRIGGER_DEVICES;
|
|
@@ -69155,6 +69028,7 @@ exports.OPS_LOG_DEFAULT_LIMIT = OPS_LOG_DEFAULT_LIMIT;
|
|
|
69155
69028
|
exports.OPS_LOG_RING_DEFAULT_MAX = OPS_LOG_RING_DEFAULT_MAX;
|
|
69156
69029
|
exports.OVERFLOW_REASON = OVERFLOW_REASON;
|
|
69157
69030
|
exports.OVERLAY_LAYERS = OVERLAY_LAYERS;
|
|
69031
|
+
exports.OWNER_ONLY_EVENT_CATEGORIES = require_event_category.OWNER_ONLY_EVENT_CATEGORIES;
|
|
69158
69032
|
exports.OauthIntegrationDescriptorSchema = OauthIntegrationDescriptorSchema;
|
|
69159
69033
|
exports.ObjectEventSchema = ObjectEventSchema;
|
|
69160
69034
|
exports.OccupancyBurstRefusalSchema = OccupancyBurstRefusalSchema;
|
|
@@ -69185,6 +69059,7 @@ exports.PEER_BYTES_CHUNK_BYTES = require_sleep.PEER_BYTES_CHUNK_BYTES;
|
|
|
69185
69059
|
exports.PEER_BYTES_MAX_OUTSTANDING = require_sleep.PEER_BYTES_MAX_OUTSTANDING;
|
|
69186
69060
|
exports.PEER_BYTES_STALL_MS = require_sleep.PEER_BYTES_STALL_MS;
|
|
69187
69061
|
exports.PEER_BYTES_TICKET_TTL_MS = require_sleep.PEER_BYTES_TICKET_TTL_MS;
|
|
69062
|
+
exports.PENDING_BLOCK_ID = PENDING_BLOCK_ID;
|
|
69188
69063
|
exports.PET_FEEDER_MANUAL_FEED_MAX = PET_FEEDER_MANUAL_FEED_MAX;
|
|
69189
69064
|
exports.PET_FEEDER_MANUAL_FEED_MIN = PET_FEEDER_MANUAL_FEED_MIN;
|
|
69190
69065
|
exports.PIPELINE_ANALYTICS_CAP_NAME = PIPELINE_ANALYTICS_CAP_NAME;
|
|
@@ -69256,7 +69131,7 @@ exports.RECORDING_SOURCE_CAMSTACK = RECORDING_SOURCE_CAMSTACK;
|
|
|
69256
69131
|
exports.RECORDING_SOURCE_CAMSTACK_ADDON = RECORDING_SOURCE_CAMSTACK_ADDON;
|
|
69257
69132
|
exports.RECORDING_TIMELINE_BATCH_MAX = RECORDING_TIMELINE_BATCH_MAX;
|
|
69258
69133
|
exports.REDACTED_SECRET = REDACTED_SECRET;
|
|
69259
|
-
exports.RESERVED_BINDING_NAMES = RESERVED_BINDING_NAMES;
|
|
69134
|
+
exports.RESERVED_BINDING_NAMES = require_composition.RESERVED_BINDING_NAMES;
|
|
69260
69135
|
exports.RESERVED_COLLECTION_SOURCES = RESERVED_COLLECTION_SOURCES;
|
|
69261
69136
|
exports.RESTORED_CAP_NAMES = RESTORED_CAP_NAMES;
|
|
69262
69137
|
exports.ROOM_EXAMPLE_MOTION_SOURCES = ROOM_EXAMPLE_MOTION_SOURCES;
|
|
@@ -69644,7 +69519,7 @@ exports.audioLabelChoices = audioLabelChoices;
|
|
|
69644
69519
|
exports.audioMetricsCapability = audioMetricsCapability;
|
|
69645
69520
|
exports.audioModeOf = audioModeOf;
|
|
69646
69521
|
exports.audioOrDefaults = audioOrDefaults;
|
|
69647
|
-
exports.audioPlanFromEncodeProfile =
|
|
69522
|
+
exports.audioPlanFromEncodeProfile = require_composition.audioPlanFromEncodeProfile;
|
|
69648
69523
|
exports.audioScaleEraOf = audioScaleEraOf;
|
|
69649
69524
|
exports.authProviderCapability = authProviderCapability;
|
|
69650
69525
|
exports.autoAssignProfiles = autoAssignProfiles;
|
|
@@ -69658,17 +69533,17 @@ exports.bindAddonActions = bindAddonActions;
|
|
|
69658
69533
|
exports.brightnessCapability = brightnessCapability;
|
|
69659
69534
|
exports.brokerCapability = brokerCapability;
|
|
69660
69535
|
exports.buildAddonRouteProvider = buildAddonRouteProvider;
|
|
69661
|
-
exports.buildAudioArgs =
|
|
69536
|
+
exports.buildAudioArgs = require_composition.buildAudioArgs;
|
|
69662
69537
|
exports.buildCapabilityLookup = buildCapabilityLookup;
|
|
69663
69538
|
exports.buildDeviceAdminUrl = buildDeviceAdminUrl;
|
|
69664
69539
|
exports.buildEventKindDescriptor = buildEventKindDescriptor;
|
|
69665
|
-
exports.buildFfmpegArgs =
|
|
69666
|
-
exports.buildInputArgs =
|
|
69540
|
+
exports.buildFfmpegArgs = require_composition.buildFfmpegArgs;
|
|
69541
|
+
exports.buildInputArgs = require_composition.buildInputArgs;
|
|
69667
69542
|
exports.buildModelVariantGroups = buildModelVariantGroups;
|
|
69668
69543
|
exports.buildNcTaxonomy = buildNcTaxonomy;
|
|
69669
69544
|
exports.buildRoleScopes = buildRoleScopes;
|
|
69670
69545
|
exports.buildStreamParamsConfigSchema = buildStreamParamsConfigSchema;
|
|
69671
|
-
exports.buildVideoArgs =
|
|
69546
|
+
exports.buildVideoArgs = require_composition.buildVideoArgs;
|
|
69672
69547
|
exports.buttonCapability = buttonCapability;
|
|
69673
69548
|
exports.cameraCredentialsCapability = cameraCredentialsCapability;
|
|
69674
69549
|
exports.cameraGridLayoutCapability = cameraGridLayoutCapability;
|
|
@@ -69696,16 +69571,18 @@ exports.colorCapability = colorCapability;
|
|
|
69696
69571
|
exports.colorForKind = colorForKind;
|
|
69697
69572
|
exports.commitWatchdogRestart = commitWatchdogRestart;
|
|
69698
69573
|
exports.compareToTarget = compareToTarget;
|
|
69699
|
-
exports.compileExpression = compileExpression;
|
|
69700
|
-
exports.compileExpressionSafe = compileExpressionSafe;
|
|
69574
|
+
exports.compileExpression = require_composition.compileExpression;
|
|
69575
|
+
exports.compileExpressionSafe = require_composition.compileExpressionSafe;
|
|
69701
69576
|
exports.composeSwitchedOff = composeSwitchedOff;
|
|
69702
|
-
exports.composedDeviceRef = composedDeviceRef;
|
|
69703
|
-
exports.composedDeviceStableId = composedDeviceStableId;
|
|
69577
|
+
exports.composedDeviceRef = require_composition.composedDeviceRef;
|
|
69578
|
+
exports.composedDeviceStableId = require_composition.composedDeviceStableId;
|
|
69704
69579
|
exports.composerCapability = composerCapability;
|
|
69705
69580
|
exports.compositionEdges = compositionEdges;
|
|
69706
|
-
exports.
|
|
69707
|
-
exports.
|
|
69708
|
-
exports.
|
|
69581
|
+
exports.compositionFieldKey = compositionFieldKey;
|
|
69582
|
+
exports.compositionItemFieldPath = require_composition.compositionItemFieldPath;
|
|
69583
|
+
exports.compositionReadKey = require_composition.compositionReadKey;
|
|
69584
|
+
exports.compositionSliceKey = require_composition.compositionSliceKey;
|
|
69585
|
+
exports.compositionSourceKey = require_composition.compositionSourceKey;
|
|
69709
69586
|
exports.compositionSourceRefs = compositionSourceRefs;
|
|
69710
69587
|
exports.conditionDepth = conditionDepth;
|
|
69711
69588
|
exports.conditionExclusionReason = conditionExclusionReason;
|
|
@@ -69730,7 +69607,7 @@ exports.createDeviceProxy = require_sleep.createDeviceProxy;
|
|
|
69730
69607
|
exports.createDurableState = require_sleep.createDurableState;
|
|
69731
69608
|
exports.createEvent = require_sleep.createEvent;
|
|
69732
69609
|
exports.createEventBusSliceSource = require_sleep.createEventBusSliceSource;
|
|
69733
|
-
exports.createExpressionScope = createExpressionScope;
|
|
69610
|
+
exports.createExpressionScope = require_composition.createExpressionScope;
|
|
69734
69611
|
exports.createHwAccelCache = createHwAccelCache;
|
|
69735
69612
|
exports.createLazyTrpcSource = require_sleep.createLazyTrpcSource;
|
|
69736
69613
|
exports.createLogChannelsProvider = createLogChannelsProvider;
|
|
@@ -69801,9 +69678,9 @@ exports.enumerateInferenceDevices = enumerateInferenceDevices;
|
|
|
69801
69678
|
exports.enumerateItemArrayFields = enumerateItemArrayFields;
|
|
69802
69679
|
exports.enumerateSchemaFields = enumerateSchemaFields;
|
|
69803
69680
|
exports.errMsg = require_err_msg.errMsg;
|
|
69804
|
-
exports.evaluateAst = evaluateAst;
|
|
69681
|
+
exports.evaluateAst = require_composition.evaluateAst;
|
|
69805
69682
|
exports.evaluateCompositionField = evaluateCompositionField;
|
|
69806
|
-
exports.evaluateExpressionSource = evaluateExpressionSource;
|
|
69683
|
+
exports.evaluateExpressionSource = require_composition.evaluateExpressionSource;
|
|
69807
69684
|
exports.evaluatePoolMemory = evaluatePoolMemory;
|
|
69808
69685
|
exports.evaluateSensorEdge = evaluateSensorEdge;
|
|
69809
69686
|
exports.evaluateZoneRules = evaluateZoneRules;
|
|
@@ -69822,9 +69699,14 @@ exports.faceGalleryCapability = faceGalleryCapability;
|
|
|
69822
69699
|
exports.failureContributionCapability = failureContributionCapability;
|
|
69823
69700
|
exports.failureRate = failureRate;
|
|
69824
69701
|
exports.fanControlCapability = fanControlCapability;
|
|
69702
|
+
exports.featureFieldEntries = require_composition.featureFieldEntries;
|
|
69825
69703
|
exports.featureProbeCapability = featureProbeCapability;
|
|
69826
|
-
exports.
|
|
69704
|
+
exports.featureSources = require_composition.featureSources;
|
|
69705
|
+
exports.feederCustomizationExample = feederCustomizationExample;
|
|
69706
|
+
exports.feederExampleSources = feederExampleSources;
|
|
69707
|
+
exports.fieldReads = require_composition.fieldReads;
|
|
69827
69708
|
exports.filesystemBrowseCapability = filesystemBrowseCapability;
|
|
69709
|
+
exports.findCandidateCycles = findCandidateCycles;
|
|
69828
69710
|
exports.findCompositionCycles = findCompositionCycles;
|
|
69829
69711
|
exports.findTimezone = findTimezone;
|
|
69830
69712
|
exports.floodCapability = floodCapability;
|
|
@@ -69856,7 +69738,7 @@ exports.integrationsCapability = integrationsCapability;
|
|
|
69856
69738
|
exports.intercomCapability = intercomCapability;
|
|
69857
69739
|
exports.interpretStoredClusterModel = interpretStoredClusterModel;
|
|
69858
69740
|
exports.invalidClusterStepModelEntries = invalidClusterStepModelEntries;
|
|
69859
|
-
exports.invocationFromEncodeProfile =
|
|
69741
|
+
exports.invocationFromEncodeProfile = require_composition.invocationFromEncodeProfile;
|
|
69860
69742
|
exports.isAgentOnlyPlacement = isAgentOnlyPlacement;
|
|
69861
69743
|
exports.isArrayOutputSchema = isArrayOutputSchema;
|
|
69862
69744
|
exports.isAudioChunkFormat = require_sleep.isAudioChunkFormat;
|
|
@@ -69883,11 +69765,12 @@ exports.isMediaOwnerType = isMediaOwnerType;
|
|
|
69883
69765
|
exports.isNode = isNode;
|
|
69884
69766
|
exports.isObjectInput = isObjectInput;
|
|
69885
69767
|
exports.isOccupancyRule = isOccupancyRule;
|
|
69768
|
+
exports.isOwnerOnlyEventCategory = require_event_category.isOwnerOnlyEventCategory;
|
|
69886
69769
|
exports.isRestoredCap = isRestoredCap;
|
|
69887
69770
|
exports.isSameAddonId = isSameAddonId;
|
|
69888
69771
|
exports.isScheduleActive = isScheduleActive;
|
|
69889
69772
|
exports.isSecretConfigField = isSecretConfigField;
|
|
69890
|
-
exports.isSoftwareDecode =
|
|
69773
|
+
exports.isSoftwareDecode = require_composition.isSoftwareDecode;
|
|
69891
69774
|
exports.isSourceCap = isSourceCap;
|
|
69892
69775
|
exports.isStorageLocationMode = isStorageLocationMode;
|
|
69893
69776
|
exports.isSystemDelivery = isSystemDelivery;
|
|
@@ -69916,7 +69799,7 @@ exports.localNetworkCapability = localNetworkCapability;
|
|
|
69916
69799
|
exports.locationIconKey = locationIconKey;
|
|
69917
69800
|
exports.locationSimilarity = locationSimilarity;
|
|
69918
69801
|
exports.lockControlCapability = lockControlCapability;
|
|
69919
|
-
exports.logBannerArgs =
|
|
69802
|
+
exports.logBannerArgs = require_composition.logBannerArgs;
|
|
69920
69803
|
exports.logChannelsCapability = logChannelsCapability;
|
|
69921
69804
|
exports.logDestinationCapability = logDestinationCapability;
|
|
69922
69805
|
exports.logLevelAtMost = logLevelAtMost;
|
|
@@ -69969,6 +69852,7 @@ exports.oauthIntegrationCapability = oauthIntegrationCapability;
|
|
|
69969
69852
|
exports.objectInputDeclaresAddonId = objectInputDeclaresAddonId;
|
|
69970
69853
|
exports.objectInputDeclaresRequiredDeviceId = objectInputDeclaresRequiredDeviceId;
|
|
69971
69854
|
exports.occupancyScope = occupancyScope;
|
|
69855
|
+
exports.optionalAncestors = optionalAncestors;
|
|
69972
69856
|
exports.optionalMethod = require_sleep.optionalMethod;
|
|
69973
69857
|
exports.osdCapability = osdCapability;
|
|
69974
69858
|
exports.osdManagerCapability = osdManagerCapability;
|
|
@@ -69976,7 +69860,7 @@ exports.overlayClusterStepSettings = overlayClusterStepSettings;
|
|
|
69976
69860
|
exports.packagePickerItems = packagePickerItems;
|
|
69977
69861
|
exports.parseAdminBase = parseAdminBase;
|
|
69978
69862
|
exports.parseCameraStreamConfig = parseCameraStreamConfig;
|
|
69979
|
-
exports.parseExpression = parseExpression;
|
|
69863
|
+
exports.parseExpression = require_composition.parseExpression;
|
|
69980
69864
|
exports.parseJsonArray = require_sleep.parseJsonArray;
|
|
69981
69865
|
exports.parseJsonObject = require_sleep.parseJsonObject;
|
|
69982
69866
|
exports.parseJsonUnknown = require_sleep.parseJsonUnknown;
|
|
@@ -69996,13 +69880,14 @@ exports.pickInvalidClusterStepModels = pickInvalidClusterStepModels;
|
|
|
69996
69880
|
exports.pickNativeLeaseOverride = pickNativeLeaseOverride;
|
|
69997
69881
|
exports.pickPreferredRtspEntry = pickPreferredRtspEntry;
|
|
69998
69882
|
exports.pickRestartCandidate = pickRestartCandidate;
|
|
69999
|
-
exports.pickVideoEncoder =
|
|
69883
|
+
exports.pickVideoEncoder = require_composition.pickVideoEncoder;
|
|
70000
69884
|
exports.pickerForCondition = pickerForCondition;
|
|
70001
69885
|
exports.pipelineAnalyticsCapability = pipelineAnalyticsCapability;
|
|
70002
69886
|
exports.pipelineExecutorCapability = pipelineExecutorCapability;
|
|
70003
69887
|
exports.pipelineOrchestratorCapability = pipelineOrchestratorCapability;
|
|
70004
69888
|
exports.pipelineRunnerCapability = pipelineRunnerCapability;
|
|
70005
69889
|
exports.planComposition = planComposition;
|
|
69890
|
+
exports.planItems = planItems;
|
|
70006
69891
|
exports.plateGalleryCapability = plateGalleryCapability;
|
|
70007
69892
|
exports.platformProbeCapability = platformProbeCapability;
|
|
70008
69893
|
exports.poolMemoryThreshold = poolMemoryThreshold;
|
|
@@ -70015,6 +69900,7 @@ exports.privacyMaskCapability = privacyMaskCapability;
|
|
|
70015
69900
|
exports.procedureAuthKey = procedureAuthKey;
|
|
70016
69901
|
exports.ptzAutotrackCapability = ptzAutotrackCapability;
|
|
70017
69902
|
exports.ptzCapability = ptzCapability;
|
|
69903
|
+
exports.publicEventCategories = require_event_category.publicEventCategories;
|
|
70018
69904
|
exports.pythonScriptForBackend = pythonScriptForBackend;
|
|
70019
69905
|
exports.rankStreams = rankStreams;
|
|
70020
69906
|
exports.readClusterStepModels = readClusterStepModels;
|
|
@@ -70033,6 +69919,7 @@ exports.recordingOnboardCapability = recordingOnboardCapability;
|
|
|
70033
69919
|
exports.recordingSignalCapability = recordingSignalCapability;
|
|
70034
69920
|
exports.rectsToCells = rectsToCells;
|
|
70035
69921
|
exports.reducePoints = reducePoints;
|
|
69922
|
+
exports.replacedFieldKeys = replacedFieldKeys;
|
|
70036
69923
|
exports.requiredTopLevelKeys = requiredTopLevelKeys;
|
|
70037
69924
|
exports.requiresPython = requiresPython;
|
|
70038
69925
|
exports.reservedSourceOwner = reservedSourceOwner;
|
|
@@ -70059,7 +69946,7 @@ exports.resolveMutate = resolveMutate;
|
|
|
70059
69946
|
exports.resolvePoolMemoryPolicy = resolvePoolMemoryPolicy;
|
|
70060
69947
|
exports.resolveRecordingProfiles = resolveRecordingProfiles;
|
|
70061
69948
|
exports.resolveRunnerId = resolveRunnerId;
|
|
70062
|
-
exports.resolveStreamMaps =
|
|
69949
|
+
exports.resolveStreamMaps = require_composition.resolveStreamMaps;
|
|
70063
69950
|
exports.resolveVariantModelId = resolveVariantModelId;
|
|
70064
69951
|
exports.resolveViewableDeviceIds = resolveViewableDeviceIds;
|
|
70065
69952
|
exports.roleSpec = roleSpec;
|
|
@@ -70153,24 +70040,25 @@ exports.terminalSessionCapability = terminalSessionCapability;
|
|
|
70153
70040
|
exports.textToHtml = textToHtml;
|
|
70154
70041
|
exports.timeOfDayToMinutes = timeOfDayToMinutes;
|
|
70155
70042
|
exports.toDeviceSummary = toDeviceSummary;
|
|
70156
|
-
exports.toExpressionValue = toExpressionValue;
|
|
70043
|
+
exports.toExpressionValue = require_composition.toExpressionValue;
|
|
70157
70044
|
exports.toNodeId = require_sleep.toNodeId;
|
|
70158
70045
|
exports.toStreamSourceEntry = toStreamSourceEntry;
|
|
70159
70046
|
exports.toastCapability = toastCapability;
|
|
70160
70047
|
exports.toggleAudioLabel = toggleAudioLabel;
|
|
70161
|
-
exports.tokenize = tokenize;
|
|
70048
|
+
exports.tokenize = require_composition.tokenize;
|
|
70162
70049
|
exports.transcodeBody = transcodeBody;
|
|
70163
70050
|
exports.tryConvertUnit = tryConvertUnit;
|
|
70164
70051
|
exports.turnProviderCapability = turnProviderCapability;
|
|
70165
70052
|
exports.unitDimension = unitDimension;
|
|
70166
70053
|
exports.unitsForDimension = unitsForDimension;
|
|
70167
70054
|
exports.unreachableExtensionSlotRow = unreachableExtensionSlotRow;
|
|
70055
|
+
exports.unwrapSchema = unwrapSchema;
|
|
70168
70056
|
exports.updateCapability = updateCapability;
|
|
70169
70057
|
exports.userManagementCapability = userManagementCapability;
|
|
70170
70058
|
exports.userPasskeysCapability = userPasskeysCapability;
|
|
70171
70059
|
exports.vacuumControlCapability = vacuumControlCapability;
|
|
70172
70060
|
exports.validateComposition = validateComposition;
|
|
70173
|
-
exports.validateExpressionSource = validateExpressionSource;
|
|
70061
|
+
exports.validateExpressionSource = require_composition.validateExpressionSource;
|
|
70174
70062
|
exports.validateRecipeBounds = validateRecipeBounds;
|
|
70175
70063
|
exports.valveCapability = valveCapability;
|
|
70176
70064
|
exports.vectorDimFromBase64 = vectorDimFromBase64;
|