@camstack/addon-admin-ui 1.1.21 → 1.1.22
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/assets/{AddLocationWizard-CtHh4Ucy.js → AddLocationWizard-hVwjbOvf.js} +1 -1
- package/dist/assets/{AddonCollectionPage-D7eIR9NV.js → AddonCollectionPage-CTsqn59E.js} +1 -1
- package/dist/assets/Addons-CCbeVMQt.js +1 -0
- package/dist/assets/{AdminTabs-SHELeszh.js → AdminTabs-H2eHA_BP.js} +1 -1
- package/dist/assets/{BrokerForm-Acer17Cj.js → BrokerForm-I-2eiXTD.js} +1 -1
- package/dist/assets/{Capabilities-F8EOFDyp.js → Capabilities-KNxdGU5R.js} +1 -1
- package/dist/assets/{CapabilityBadges-uN4xnNt9.js → CapabilityBadges-Bp9qwWAG.js} +1 -1
- package/dist/assets/{Cluster-Br54rXlE.js → Cluster-ChnNCri_.js} +1 -1
- package/dist/assets/{Dashboard-Ds4y9hsA.js → Dashboard-CgzNKw4S.js} +1 -1
- package/dist/assets/{Data-BadX573w.js → Data-GY9aNQ1Y.js} +1 -1
- package/dist/assets/{DetectionIntelligence-Crlw81K-.js → DetectionIntelligence-CbBEvocZ.js} +1 -1
- package/dist/assets/DeviceDetail-sgGEfTXB.js +2 -0
- package/dist/assets/{Devices-CSuhWvHj.js → Devices-2wZcDSXn.js} +1 -1
- package/dist/assets/EmbedPlayerPage-BSfF5HmG.js +1 -0
- package/dist/assets/{FormBuilder-CegbdtFO.js → FormBuilder-CO6H7q61.js} +1 -1
- package/dist/assets/Identity-Ctx_yZtf.js +1 -0
- package/dist/assets/IntegrationDetail-DQI58WRY.js +1 -0
- package/dist/assets/{Integrations-DiaCWNDC.js → Integrations-Dee1SHhr.js} +1 -1
- package/dist/assets/Integrations-rZdfMVdZ.js +1 -0
- package/dist/assets/{Logs-BLu18FYD.js → Logs-BJ61UdxK.js} +1 -1
- package/dist/assets/{MotionZonesSettings-CQu6k79T.js → MotionZonesSettings-CYzimYmN.js} +1 -1
- package/dist/assets/{MyAccess-CLaxbnXE.js → MyAccess-Bgewpx3A.js} +1 -1
- package/dist/assets/Network-Dc_a0WJ9.js +1 -0
- package/dist/assets/NodeAddonsSettingsPanel-CWrLPV6J.js +1 -0
- package/dist/assets/{NotificationTargets-C7ekw4dH.js → NotificationTargets-lEW7Zldv.js} +1 -1
- package/dist/assets/Pipeline-CbfX9p5j.js +1 -0
- package/dist/assets/{PrivacyMaskSettings-CyaPh6bF.js → PrivacyMaskSettings-CzPxZHZ1.js} +1 -1
- package/dist/assets/{ProviderIcon-BVyDFfZQ.js → ProviderIcon-Dm-sZ7Df.js} +1 -1
- package/dist/assets/{ScanNetworkModal-CAWMDwou.js → ScanNetworkModal-Vcr_-aIb.js} +1 -1
- package/dist/assets/{Settings-vLhU6eIs.js → Settings-WQCzalu_.js} +1 -1
- package/dist/assets/{Showroom-CyXCqK1A.js → Showroom-BxISco8h.js} +1 -1
- package/dist/assets/{_virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-DAX7XSx3.js → _virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-CKTRvTR8.js} +1 -1
- package/dist/assets/circle-check-big-B9mpY_ym.js +1 -0
- package/dist/assets/{copy-B6IIL8kT.js → copy-CjMMaCPu.js} +1 -1
- package/dist/assets/{dist-DwxrMREn.js → dist-DsiSY20Z.js} +1 -1
- package/dist/assets/dist-u_nf627j.js +7 -0
- package/dist/assets/{download-H_XK0DLj.js → download-35ioIRtw.js} +1 -1
- package/dist/assets/{esm-C1lbdX0r.js → esm-DPIMznCO.js} +1 -1
- package/dist/assets/{hostInit-BhkWchBW.js → hostInit-BQK5GXsV.js} +1 -1
- package/dist/assets/index-BQGzI2C-.css +2 -0
- package/dist/assets/index-BdGL2J0e.js +4 -0
- package/dist/assets/{key-round-Dyj4n5xw.js → key-round-CHE1k3cQ.js} +1 -1
- package/dist/assets/{mf-entry-bootstrap-0-efb2b672.js → mf-entry-bootstrap-0-5940e459.js} +2 -2
- package/dist/assets/{pencil-D4eE6uEV.js → pencil-C1w2uLp9.js} +1 -1
- package/dist/assets/{player-overlays-BH6aBUe-.js → player-overlays-DlPIT9xj.js} +1 -1
- package/dist/assets/plus-D9QBDEjM.js +1 -0
- package/dist/assets/{radio-CfQ90vM2.js → radio-DpwfMzDk.js} +1 -1
- package/dist/assets/{refresh-cw-DCVnt6DS.js → refresh-cw-DfSn-i0F.js} +1 -1
- package/dist/assets/remoteEntry-CIdYQQ-f.js +1 -0
- package/dist/assets/{rotate-ccw-D6a6yNNE.js → rotate-ccw--rHGluty.js} +1 -1
- package/dist/assets/rotate-cw-DtSHMNUL.js +1 -0
- package/dist/assets/search-DgJL1Gey.js +1 -0
- package/dist/assets/{server-DglCnPiH.js → server-BlM9U_dS.js} +1 -1
- package/dist/assets/{sparkles-Cfbrs3IH.js → sparkles-COBUjBX-.js} +1 -1
- package/dist/assets/square-VsNW1mnX.js +1 -0
- package/dist/assets/{square-check-big-DkE6GAlP.js → square-check-big-Dej4DiE7.js} +1 -1
- package/dist/assets/src-C9eW94dA.js +7 -0
- package/dist/assets/src-CtvTbpOC.js +61 -0
- package/dist/assets/{upload-D2GIH0tS.js → upload-BJzZajFJ.js} +1 -1
- package/dist/assets/useDevice-CjqFlWNw.js +1 -0
- package/dist/assets/{useEventInvalidation-B-rUQp_C.js → useEventInvalidation-CY1yyH4R.js} +1 -1
- package/dist/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-Im2hSrP1.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-Dl7HuNe3.js} +2 -2
- package/dist/assets/{wifi-TvDBvENo.js → wifi-Dj3gSpzs.js} +1 -1
- package/dist/assets/{zap-Cb9KqtLJ.js → zap-DLkdpIj9.js} +1 -1
- package/dist/index.html +6 -6
- package/dist/server/addon.js +703 -25
- package/package.json +1 -1
- package/dist/assets/Addons-BoCfiheF.js +0 -1
- package/dist/assets/DeviceDetail-DLlQRj_v.js +0 -2
- package/dist/assets/EmbedPlayerPage-ChE8oSUc.js +0 -1
- package/dist/assets/Identity-CVFKJESU.js +0 -1
- package/dist/assets/IntegrationDetail-DsUKq3z5.js +0 -1
- package/dist/assets/Integrations-CuVxDYIj.js +0 -1
- package/dist/assets/Network-kXez-Kpm.js +0 -1
- package/dist/assets/NodeAddonsSettingsPanel-BOqWOM7_.js +0 -1
- package/dist/assets/Pipeline-iwj4d4DN.js +0 -1
- package/dist/assets/circle-check-big-CgdBZ1l7.js +0 -1
- package/dist/assets/dist-BAhtRh_d.js +0 -6
- package/dist/assets/index-Bvv3nxPc.css +0 -2
- package/dist/assets/index-DjbbJhB4.js +0 -4
- package/dist/assets/plus-CDeS7IvC.js +0 -1
- package/dist/assets/remoteEntry-D3SUgyps.js +0 -1
- package/dist/assets/rotate-cw-BZnE1cAg.js +0 -1
- package/dist/assets/search-DGzI_eqI.js +0 -1
- package/dist/assets/square-Cgyuo7em.js +0 -1
- package/dist/assets/src-BVMxsNe8.js +0 -61
- package/dist/assets/src-CCmaAR6i.js +0 -6
- package/dist/assets/useDevice-CAq7iz29.js +0 -1
package/dist/server/addon.js
CHANGED
|
@@ -4629,7 +4629,7 @@ function _instanceof(cls, params = {}) {
|
|
|
4629
4629
|
return inst;
|
|
4630
4630
|
}
|
|
4631
4631
|
//#endregion
|
|
4632
|
-
//#region ../types/dist/sleep-
|
|
4632
|
+
//#region ../types/dist/sleep-BO1nweKv.mjs
|
|
4633
4633
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4634
4634
|
EventCategory["SystemBoot"] = "system.boot";
|
|
4635
4635
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -7431,6 +7431,601 @@ var _macroLookup = /* @__PURE__ */ new Map();
|
|
|
7431
7431
|
for (const [k, v] of Object.entries(YAMNET_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7432
7432
|
for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7433
7433
|
/**
|
|
7434
|
+
* Error types for the safe expression engine. Two distinct classes so callers
|
|
7435
|
+
* can tell a compile-time (grammar) failure from a runtime (evaluation)
|
|
7436
|
+
* failure — both are non-fatal to the host: read paths degrade to "skip link".
|
|
7437
|
+
*/
|
|
7438
|
+
/** Thrown by the tokenizer / parser. Carries a 0-based source `position` when
|
|
7439
|
+
* the failure is anchored to a character (author-facing inline feedback). */
|
|
7440
|
+
var ExpressionParseError = class extends Error {
|
|
7441
|
+
position;
|
|
7442
|
+
constructor(message, position) {
|
|
7443
|
+
super(message);
|
|
7444
|
+
this.name = "ExpressionParseError";
|
|
7445
|
+
this.position = position;
|
|
7446
|
+
}
|
|
7447
|
+
};
|
|
7448
|
+
/** Thrown by the evaluator (unknown identifier, type mismatch, non-finite
|
|
7449
|
+
* result, unknown builtin, step-budget exceeded). */
|
|
7450
|
+
var ExpressionEvalError = class extends Error {
|
|
7451
|
+
constructor(message) {
|
|
7452
|
+
super(message);
|
|
7453
|
+
this.name = "ExpressionEvalError";
|
|
7454
|
+
}
|
|
7455
|
+
};
|
|
7456
|
+
/**
|
|
7457
|
+
* Resource-bound constants for the safe expression engine.
|
|
7458
|
+
*
|
|
7459
|
+
* Every bound is defense-in-depth: the grammar is non-Turing-complete (no
|
|
7460
|
+
* loops, recursion, lambdas or member access — see `ast.ts`), so evaluation is
|
|
7461
|
+
* O(nodeCount) by construction. These caps merely put a hard ceiling on the
|
|
7462
|
+
* work a single author-supplied expression can request, so a hostile or
|
|
7463
|
+
* accidental pathological string can never spend unbounded CPU/memory.
|
|
7464
|
+
*/
|
|
7465
|
+
/** Max source length (chars) — checked BEFORE tokenizing so a huge string is
|
|
7466
|
+
* rejected without allocation. */
|
|
7467
|
+
var MAX_EXPRESSION_SOURCE_LENGTH = 2048;
|
|
7468
|
+
/** A legal binding / identifier name. */
|
|
7469
|
+
var EXPRESSION_IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
7470
|
+
/** Binding names an author may NOT use: `now` is auto-injected; the literal
|
|
7471
|
+
* keywords lex as values, not identifiers, so binding to them is meaningless. */
|
|
7472
|
+
var RESERVED_BINDING_NAMES = new Set([
|
|
7473
|
+
"now",
|
|
7474
|
+
"true",
|
|
7475
|
+
"false",
|
|
7476
|
+
"null"
|
|
7477
|
+
]);
|
|
7478
|
+
/**
|
|
7479
|
+
* Tokenizer for the safe expression mini-language. Hand-rolled, single-pass,
|
|
7480
|
+
* zero-dependency. The grammar is deliberately boring: decimal numbers,
|
|
7481
|
+
* single/double-quoted strings with a tiny escape set, identifiers, the three
|
|
7482
|
+
* value keywords (`true`/`false`/`null`) and a fixed punctuator set. Anything
|
|
7483
|
+
* outside that — a bare `.`, `=`, `[`, `]`, `{`, `}`, `;`, backtick, `&`, `|` —
|
|
7484
|
+
* is a parse error with a source position, so member access / assignment /
|
|
7485
|
+
* template literals are lexically impossible.
|
|
7486
|
+
*/
|
|
7487
|
+
var KEYWORDS = new Set([
|
|
7488
|
+
"true",
|
|
7489
|
+
"false",
|
|
7490
|
+
"null"
|
|
7491
|
+
]);
|
|
7492
|
+
function isDigit(ch) {
|
|
7493
|
+
return ch >= "0" && ch <= "9";
|
|
7494
|
+
}
|
|
7495
|
+
function isIdentStart(ch) {
|
|
7496
|
+
return ch >= "A" && ch <= "Z" || ch >= "a" && ch <= "z" || ch === "_";
|
|
7497
|
+
}
|
|
7498
|
+
function isIdentPart(ch) {
|
|
7499
|
+
return isIdentStart(ch) || isDigit(ch);
|
|
7500
|
+
}
|
|
7501
|
+
function isWhitespace(ch) {
|
|
7502
|
+
return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f" || ch === "\v";
|
|
7503
|
+
}
|
|
7504
|
+
/** Tokenize `source` into a flat token list ending with a single `eof` token.
|
|
7505
|
+
* Throws `ExpressionParseError` on any illegal character or unterminated
|
|
7506
|
+
* string. */
|
|
7507
|
+
function tokenize(source) {
|
|
7508
|
+
if (source.length > 2048) throw new ExpressionParseError(`expression too long (${source.length} > ${MAX_EXPRESSION_SOURCE_LENGTH} chars)`, 0);
|
|
7509
|
+
const tokens = [];
|
|
7510
|
+
let i = 0;
|
|
7511
|
+
const n = source.length;
|
|
7512
|
+
while (i < n) {
|
|
7513
|
+
const ch = source[i];
|
|
7514
|
+
if (isWhitespace(ch)) {
|
|
7515
|
+
i += 1;
|
|
7516
|
+
continue;
|
|
7517
|
+
}
|
|
7518
|
+
if (isDigit(ch)) {
|
|
7519
|
+
const start = i;
|
|
7520
|
+
while (i < n && isDigit(source[i])) i += 1;
|
|
7521
|
+
if (i < n && source[i] === ".") {
|
|
7522
|
+
if (i + 1 >= n || !isDigit(source[i + 1])) throw new ExpressionParseError("malformed number: decimal point needs a digit", i);
|
|
7523
|
+
i += 1;
|
|
7524
|
+
while (i < n && isDigit(source[i])) i += 1;
|
|
7525
|
+
}
|
|
7526
|
+
const text = source.slice(start, i);
|
|
7527
|
+
const value = Number(text);
|
|
7528
|
+
if (!Number.isFinite(value)) throw new ExpressionParseError(`malformed number: '${text}'`, start);
|
|
7529
|
+
tokens.push({
|
|
7530
|
+
type: "number",
|
|
7531
|
+
value,
|
|
7532
|
+
pos: start
|
|
7533
|
+
});
|
|
7534
|
+
continue;
|
|
7535
|
+
}
|
|
7536
|
+
if (ch === "'" || ch === "\"") {
|
|
7537
|
+
const quote = ch;
|
|
7538
|
+
const start = i;
|
|
7539
|
+
i += 1;
|
|
7540
|
+
let out = "";
|
|
7541
|
+
let closed = false;
|
|
7542
|
+
while (i < n) {
|
|
7543
|
+
const c = source[i];
|
|
7544
|
+
if (c === "\\") {
|
|
7545
|
+
const next = i + 1 < n ? source[i + 1] : "";
|
|
7546
|
+
if (next === "\\" || next === "'" || next === "\"") {
|
|
7547
|
+
out += next;
|
|
7548
|
+
i += 2;
|
|
7549
|
+
continue;
|
|
7550
|
+
}
|
|
7551
|
+
throw new ExpressionParseError(`invalid string escape: '\\${next}'`, i);
|
|
7552
|
+
}
|
|
7553
|
+
if (c === quote) {
|
|
7554
|
+
closed = true;
|
|
7555
|
+
i += 1;
|
|
7556
|
+
break;
|
|
7557
|
+
}
|
|
7558
|
+
out += c;
|
|
7559
|
+
i += 1;
|
|
7560
|
+
}
|
|
7561
|
+
if (!closed) throw new ExpressionParseError("unterminated string literal", start);
|
|
7562
|
+
tokens.push({
|
|
7563
|
+
type: "string",
|
|
7564
|
+
value: out,
|
|
7565
|
+
pos: start
|
|
7566
|
+
});
|
|
7567
|
+
continue;
|
|
7568
|
+
}
|
|
7569
|
+
if (isIdentStart(ch)) {
|
|
7570
|
+
const start = i;
|
|
7571
|
+
while (i < n && isIdentPart(source[i])) i += 1;
|
|
7572
|
+
const text = source.slice(start, i);
|
|
7573
|
+
if (KEYWORDS.has(text)) tokens.push({
|
|
7574
|
+
type: "keyword",
|
|
7575
|
+
keyword: keywordOf(text),
|
|
7576
|
+
pos: start
|
|
7577
|
+
});
|
|
7578
|
+
else tokens.push({
|
|
7579
|
+
type: "identifier",
|
|
7580
|
+
name: text,
|
|
7581
|
+
pos: start
|
|
7582
|
+
});
|
|
7583
|
+
continue;
|
|
7584
|
+
}
|
|
7585
|
+
const two = i + 1 < n ? source.slice(i, i + 2) : "";
|
|
7586
|
+
if (two === "<=" || two === ">=" || two === "==" || two === "!=" || two === "&&" || two === "||") {
|
|
7587
|
+
tokens.push({
|
|
7588
|
+
type: "punct",
|
|
7589
|
+
punct: two,
|
|
7590
|
+
pos: i
|
|
7591
|
+
});
|
|
7592
|
+
i += 2;
|
|
7593
|
+
continue;
|
|
7594
|
+
}
|
|
7595
|
+
if (isSinglePunct(ch)) {
|
|
7596
|
+
tokens.push({
|
|
7597
|
+
type: "punct",
|
|
7598
|
+
punct: ch,
|
|
7599
|
+
pos: i
|
|
7600
|
+
});
|
|
7601
|
+
i += 1;
|
|
7602
|
+
continue;
|
|
7603
|
+
}
|
|
7604
|
+
throw new ExpressionParseError(`unexpected character '${ch}'`, i);
|
|
7605
|
+
}
|
|
7606
|
+
tokens.push({
|
|
7607
|
+
type: "eof",
|
|
7608
|
+
pos: n
|
|
7609
|
+
});
|
|
7610
|
+
return tokens;
|
|
7611
|
+
}
|
|
7612
|
+
function keywordOf(text) {
|
|
7613
|
+
if (text === "true") return "true";
|
|
7614
|
+
if (text === "false") return "false";
|
|
7615
|
+
return "null";
|
|
7616
|
+
}
|
|
7617
|
+
function isSinglePunct(ch) {
|
|
7618
|
+
return ch === "(" || ch === ")" || ch === "," || ch === "?" || ch === ":" || ch === "+" || ch === "-" || ch === "*" || ch === "/" || ch === "%" || ch === "!" || ch === "<" || ch === ">";
|
|
7619
|
+
}
|
|
7620
|
+
/**
|
|
7621
|
+
* Frozen, null-prototype builtin function table for the expression engine
|
|
7622
|
+
* (spec §4 rule 4). The table is the SOLE surface of callable functions: the
|
|
7623
|
+
* parser rejects any callee not in it, and the evaluator gates each call on an
|
|
7624
|
+
* own-property check against it.
|
|
7625
|
+
*
|
|
7626
|
+
* Because the object has a NULL prototype AND is `Object.freeze`d:
|
|
7627
|
+
* - it cannot be polluted (no `__proto__` / `constructor` write reaches it);
|
|
7628
|
+
* - a lookup for `toString` / `hasOwnProperty` / `constructor` finds NOTHING
|
|
7629
|
+
* (there is no `Object.prototype` in the chain), so those names are not
|
|
7630
|
+
* callable — they are simply "unknown function" at parse time.
|
|
7631
|
+
*
|
|
7632
|
+
* Every numeric argument is validated as a finite number and every numeric
|
|
7633
|
+
* RESULT is re-checked finite, so `/0`, `sqrt(-1)` (→ NaN) and overflow
|
|
7634
|
+
* (`pow(10,400)` → Infinity) all raise `ExpressionEvalError` and fail the link
|
|
7635
|
+
* closed rather than emitting a garbage value.
|
|
7636
|
+
*/
|
|
7637
|
+
function asFiniteNumber(value, name, index) {
|
|
7638
|
+
if (typeof value !== "number" || !Number.isFinite(value)) throw new ExpressionEvalError(`${name}: argument ${index + 1} must be a finite number`);
|
|
7639
|
+
return value;
|
|
7640
|
+
}
|
|
7641
|
+
function asString$1(value, name, index) {
|
|
7642
|
+
if (typeof value !== "string") throw new ExpressionEvalError(`${name}: argument ${index + 1} must be a string`);
|
|
7643
|
+
return value;
|
|
7644
|
+
}
|
|
7645
|
+
function finiteResult(value, name) {
|
|
7646
|
+
if (!Number.isFinite(value)) throw new ExpressionEvalError(`${name}: produced a non-finite result`);
|
|
7647
|
+
return value;
|
|
7648
|
+
}
|
|
7649
|
+
function allFiniteNumbers(args, name) {
|
|
7650
|
+
return args.map((a, idx) => asFiniteNumber(a, name, idx));
|
|
7651
|
+
}
|
|
7652
|
+
var INF = Number.POSITIVE_INFINITY;
|
|
7653
|
+
var table = {
|
|
7654
|
+
min: {
|
|
7655
|
+
minArgs: 1,
|
|
7656
|
+
maxArgs: INF,
|
|
7657
|
+
apply: (args) => finiteResult(Math.min(...allFiniteNumbers(args, "min")), "min")
|
|
7658
|
+
},
|
|
7659
|
+
max: {
|
|
7660
|
+
minArgs: 1,
|
|
7661
|
+
maxArgs: INF,
|
|
7662
|
+
apply: (args) => finiteResult(Math.max(...allFiniteNumbers(args, "max")), "max")
|
|
7663
|
+
},
|
|
7664
|
+
abs: {
|
|
7665
|
+
minArgs: 1,
|
|
7666
|
+
maxArgs: 1,
|
|
7667
|
+
apply: (args) => finiteResult(Math.abs(asFiniteNumber(args[0], "abs", 0)), "abs")
|
|
7668
|
+
},
|
|
7669
|
+
floor: {
|
|
7670
|
+
minArgs: 1,
|
|
7671
|
+
maxArgs: 1,
|
|
7672
|
+
apply: (args) => finiteResult(Math.floor(asFiniteNumber(args[0], "floor", 0)), "floor")
|
|
7673
|
+
},
|
|
7674
|
+
ceil: {
|
|
7675
|
+
minArgs: 1,
|
|
7676
|
+
maxArgs: 1,
|
|
7677
|
+
apply: (args) => finiteResult(Math.ceil(asFiniteNumber(args[0], "ceil", 0)), "ceil")
|
|
7678
|
+
},
|
|
7679
|
+
sqrt: {
|
|
7680
|
+
minArgs: 1,
|
|
7681
|
+
maxArgs: 1,
|
|
7682
|
+
apply: (args) => finiteResult(Math.sqrt(asFiniteNumber(args[0], "sqrt", 0)), "sqrt")
|
|
7683
|
+
},
|
|
7684
|
+
round: {
|
|
7685
|
+
minArgs: 1,
|
|
7686
|
+
maxArgs: 2,
|
|
7687
|
+
apply: (args) => {
|
|
7688
|
+
const x = asFiniteNumber(args[0], "round", 0);
|
|
7689
|
+
const digits = args.length > 1 ? Math.trunc(asFiniteNumber(args[1], "round", 1)) : 0;
|
|
7690
|
+
if (digits < 0 || digits > 100) throw new ExpressionEvalError("round: digits must be between 0 and 100");
|
|
7691
|
+
const factor = 10 ** digits;
|
|
7692
|
+
return finiteResult(Math.round(x * factor) / factor, "round");
|
|
7693
|
+
}
|
|
7694
|
+
},
|
|
7695
|
+
pow: {
|
|
7696
|
+
minArgs: 2,
|
|
7697
|
+
maxArgs: 2,
|
|
7698
|
+
apply: (args) => finiteResult(asFiniteNumber(args[0], "pow", 0) ** asFiniteNumber(args[1], "pow", 1), "pow")
|
|
7699
|
+
},
|
|
7700
|
+
clamp: {
|
|
7701
|
+
minArgs: 3,
|
|
7702
|
+
maxArgs: 3,
|
|
7703
|
+
apply: (args) => {
|
|
7704
|
+
const x = asFiniteNumber(args[0], "clamp", 0);
|
|
7705
|
+
const lo = asFiniteNumber(args[1], "clamp", 1);
|
|
7706
|
+
const hi = asFiniteNumber(args[2], "clamp", 2);
|
|
7707
|
+
if (lo > hi) throw new ExpressionEvalError("clamp: lower bound is greater than upper bound");
|
|
7708
|
+
return finiteResult(Math.min(hi, Math.max(lo, x)), "clamp");
|
|
7709
|
+
}
|
|
7710
|
+
},
|
|
7711
|
+
avg: {
|
|
7712
|
+
minArgs: 1,
|
|
7713
|
+
maxArgs: INF,
|
|
7714
|
+
apply: (args) => {
|
|
7715
|
+
const nums = allFiniteNumbers(args, "avg");
|
|
7716
|
+
return finiteResult(nums.reduce((acc, v) => acc + v, 0) / nums.length, "avg");
|
|
7717
|
+
}
|
|
7718
|
+
},
|
|
7719
|
+
sum: {
|
|
7720
|
+
minArgs: 1,
|
|
7721
|
+
maxArgs: INF,
|
|
7722
|
+
apply: (args) => finiteResult(allFiniteNumbers(args, "sum").reduce((acc, v) => acc + v, 0), "sum")
|
|
7723
|
+
},
|
|
7724
|
+
coalesce: {
|
|
7725
|
+
minArgs: 1,
|
|
7726
|
+
maxArgs: INF,
|
|
7727
|
+
apply: (args) => {
|
|
7728
|
+
for (const a of args) if (a !== null) return a;
|
|
7729
|
+
return null;
|
|
7730
|
+
}
|
|
7731
|
+
},
|
|
7732
|
+
age: {
|
|
7733
|
+
minArgs: 2,
|
|
7734
|
+
maxArgs: 2,
|
|
7735
|
+
apply: (args) => finiteResult(asFiniteNumber(args[0], "age", 0) - asFiniteNumber(args[1], "age", 1), "age")
|
|
7736
|
+
},
|
|
7737
|
+
convert: {
|
|
7738
|
+
minArgs: 3,
|
|
7739
|
+
maxArgs: 3,
|
|
7740
|
+
apply: (args, hooks) => {
|
|
7741
|
+
const x = asFiniteNumber(args[0], "convert", 0);
|
|
7742
|
+
const from = asString$1(args[1], "convert", 1).trim();
|
|
7743
|
+
const to = asString$1(args[2], "convert", 2).trim();
|
|
7744
|
+
if (hooks.convert) {
|
|
7745
|
+
const out = hooks.convert(x, from, to);
|
|
7746
|
+
if (out === null) throw new ExpressionEvalError(`convert: cannot convert '${from}' to '${to}'`);
|
|
7747
|
+
return finiteResult(out, "convert");
|
|
7748
|
+
}
|
|
7749
|
+
if (from === to) return x;
|
|
7750
|
+
throw new ExpressionEvalError("convert: unit conversion table not installed");
|
|
7751
|
+
}
|
|
7752
|
+
}
|
|
7753
|
+
};
|
|
7754
|
+
Object.freeze(Object.assign(Object.create(null), table));
|
|
7755
|
+
/** The set of valid builtin names — used by the parser to reject unknown
|
|
7756
|
+
* callees at parse time (immediate author feedback). */
|
|
7757
|
+
var EXPRESSION_BUILTIN_NAMES = new Set(Object.keys(table));
|
|
7758
|
+
/**
|
|
7759
|
+
* Pratt (precedence-climbing) parser for the safe expression mini-language.
|
|
7760
|
+
*
|
|
7761
|
+
* Precedence (low → high): ternary `?:` (right-assoc) → `||` → `&&` → equality
|
|
7762
|
+
* → relational → additive → multiplicative → unary `! -` → call / primary.
|
|
7763
|
+
* Calls are ONLY `IDENT '(' args? ')'` at primary position — the callee is a
|
|
7764
|
+
* string validated against the builtin table at parse time, so an unknown
|
|
7765
|
+
* function is rejected immediately (author feedback) and a persisted expression
|
|
7766
|
+
* that references a since-removed builtin degrades at read.
|
|
7767
|
+
*
|
|
7768
|
+
* A node counter caps total AST size (`MAX_EXPRESSION_AST_NODES`) and call
|
|
7769
|
+
* arity is capped (`MAX_EXPRESSION_CALL_ARGS`) — both raise `ExpressionParseError`.
|
|
7770
|
+
*/
|
|
7771
|
+
/** Binary/logical operator precedence (higher binds tighter). */
|
|
7772
|
+
var BINARY_PRECEDENCE = {
|
|
7773
|
+
"||": 1,
|
|
7774
|
+
"&&": 2,
|
|
7775
|
+
"==": 3,
|
|
7776
|
+
"!=": 3,
|
|
7777
|
+
"<": 4,
|
|
7778
|
+
"<=": 4,
|
|
7779
|
+
">": 4,
|
|
7780
|
+
">=": 4,
|
|
7781
|
+
"+": 5,
|
|
7782
|
+
"-": 5,
|
|
7783
|
+
"*": 6,
|
|
7784
|
+
"/": 6,
|
|
7785
|
+
"%": 6
|
|
7786
|
+
};
|
|
7787
|
+
function isLogicalOp(op) {
|
|
7788
|
+
return op === "&&" || op === "||";
|
|
7789
|
+
}
|
|
7790
|
+
function isBinaryOp(op) {
|
|
7791
|
+
return op === "+" || op === "-" || op === "*" || op === "/" || op === "%" || op === "==" || op === "!=" || op === "<" || op === "<=" || op === ">" || op === ">=";
|
|
7792
|
+
}
|
|
7793
|
+
var Parser = class {
|
|
7794
|
+
tokens;
|
|
7795
|
+
pos = 0;
|
|
7796
|
+
nodeCount = 0;
|
|
7797
|
+
identifiers = /* @__PURE__ */ new Set();
|
|
7798
|
+
callees = /* @__PURE__ */ new Set();
|
|
7799
|
+
constructor(tokens) {
|
|
7800
|
+
this.tokens = tokens;
|
|
7801
|
+
}
|
|
7802
|
+
parse() {
|
|
7803
|
+
const ast = this.parseTernary();
|
|
7804
|
+
const tok = this.peek();
|
|
7805
|
+
if (tok.type !== "eof") throw new ExpressionParseError("unexpected trailing input", tok.pos);
|
|
7806
|
+
return {
|
|
7807
|
+
ast,
|
|
7808
|
+
identifiers: this.identifiers,
|
|
7809
|
+
callees: this.callees,
|
|
7810
|
+
nodeCount: this.nodeCount
|
|
7811
|
+
};
|
|
7812
|
+
}
|
|
7813
|
+
peek() {
|
|
7814
|
+
return this.tokens[this.pos];
|
|
7815
|
+
}
|
|
7816
|
+
next() {
|
|
7817
|
+
return this.tokens[this.pos++];
|
|
7818
|
+
}
|
|
7819
|
+
/** Consume a punctuator token, erroring if the next token isn't it. */
|
|
7820
|
+
expectPunct(punct) {
|
|
7821
|
+
const tok = this.peek();
|
|
7822
|
+
if (tok.type !== "punct" || tok.punct !== punct) throw new ExpressionParseError(`expected '${punct}'`, tok.pos);
|
|
7823
|
+
this.pos += 1;
|
|
7824
|
+
}
|
|
7825
|
+
matchPunct(punct) {
|
|
7826
|
+
const tok = this.peek();
|
|
7827
|
+
if (tok.type === "punct" && tok.punct === punct) {
|
|
7828
|
+
this.pos += 1;
|
|
7829
|
+
return true;
|
|
7830
|
+
}
|
|
7831
|
+
return false;
|
|
7832
|
+
}
|
|
7833
|
+
countNode() {
|
|
7834
|
+
this.nodeCount += 1;
|
|
7835
|
+
if (this.nodeCount > 256) throw new ExpressionParseError("expression too complex", this.peek().pos);
|
|
7836
|
+
}
|
|
7837
|
+
parseTernary() {
|
|
7838
|
+
const test = this.parseBinary(1);
|
|
7839
|
+
if (this.matchPunct("?")) {
|
|
7840
|
+
const consequent = this.parseTernary();
|
|
7841
|
+
this.expectPunct(":");
|
|
7842
|
+
const alternate = this.parseTernary();
|
|
7843
|
+
this.countNode();
|
|
7844
|
+
return {
|
|
7845
|
+
kind: "conditional",
|
|
7846
|
+
test,
|
|
7847
|
+
consequent,
|
|
7848
|
+
alternate
|
|
7849
|
+
};
|
|
7850
|
+
}
|
|
7851
|
+
return test;
|
|
7852
|
+
}
|
|
7853
|
+
parseBinary(minPrec) {
|
|
7854
|
+
let left = this.parseUnary();
|
|
7855
|
+
for (;;) {
|
|
7856
|
+
const tok = this.peek();
|
|
7857
|
+
if (tok.type !== "punct") break;
|
|
7858
|
+
const prec = BINARY_PRECEDENCE[tok.punct];
|
|
7859
|
+
if (prec === void 0 || prec < minPrec) break;
|
|
7860
|
+
const op = tok.punct;
|
|
7861
|
+
this.pos += 1;
|
|
7862
|
+
const right = this.parseBinary(prec + 1);
|
|
7863
|
+
this.countNode();
|
|
7864
|
+
if (isLogicalOp(op)) left = {
|
|
7865
|
+
kind: "logical",
|
|
7866
|
+
op,
|
|
7867
|
+
left,
|
|
7868
|
+
right
|
|
7869
|
+
};
|
|
7870
|
+
else if (isBinaryOp(op)) left = {
|
|
7871
|
+
kind: "binary",
|
|
7872
|
+
op,
|
|
7873
|
+
left,
|
|
7874
|
+
right
|
|
7875
|
+
};
|
|
7876
|
+
else throw new ExpressionParseError(`unexpected operator '${op}'`, tok.pos);
|
|
7877
|
+
}
|
|
7878
|
+
return left;
|
|
7879
|
+
}
|
|
7880
|
+
parseUnary() {
|
|
7881
|
+
const tok = this.peek();
|
|
7882
|
+
if (tok.type === "punct" && (tok.punct === "!" || tok.punct === "-")) {
|
|
7883
|
+
const op = tok.punct;
|
|
7884
|
+
this.pos += 1;
|
|
7885
|
+
const operand = this.parseUnary();
|
|
7886
|
+
this.countNode();
|
|
7887
|
+
return {
|
|
7888
|
+
kind: "unary",
|
|
7889
|
+
op,
|
|
7890
|
+
operand
|
|
7891
|
+
};
|
|
7892
|
+
}
|
|
7893
|
+
return this.parsePrimary();
|
|
7894
|
+
}
|
|
7895
|
+
parsePrimary() {
|
|
7896
|
+
const tok = this.next();
|
|
7897
|
+
switch (tok.type) {
|
|
7898
|
+
case "number":
|
|
7899
|
+
this.countNode();
|
|
7900
|
+
return {
|
|
7901
|
+
kind: "literal",
|
|
7902
|
+
value: tok.value
|
|
7903
|
+
};
|
|
7904
|
+
case "string":
|
|
7905
|
+
this.countNode();
|
|
7906
|
+
return {
|
|
7907
|
+
kind: "literal",
|
|
7908
|
+
value: tok.value
|
|
7909
|
+
};
|
|
7910
|
+
case "keyword":
|
|
7911
|
+
this.countNode();
|
|
7912
|
+
return {
|
|
7913
|
+
kind: "literal",
|
|
7914
|
+
value: tok.keyword === "null" ? null : tok.keyword === "true"
|
|
7915
|
+
};
|
|
7916
|
+
case "identifier": {
|
|
7917
|
+
const nextTok = this.peek();
|
|
7918
|
+
if (nextTok.type === "punct" && nextTok.punct === "(") return this.parseCall(tok.name, tok.pos);
|
|
7919
|
+
this.identifiers.add(tok.name);
|
|
7920
|
+
this.countNode();
|
|
7921
|
+
return {
|
|
7922
|
+
kind: "identifier",
|
|
7923
|
+
name: tok.name
|
|
7924
|
+
};
|
|
7925
|
+
}
|
|
7926
|
+
case "punct":
|
|
7927
|
+
if (tok.punct === "(") {
|
|
7928
|
+
const inner = this.parseTernary();
|
|
7929
|
+
this.expectPunct(")");
|
|
7930
|
+
return inner;
|
|
7931
|
+
}
|
|
7932
|
+
throw new ExpressionParseError(`unexpected token '${tok.punct}'`, tok.pos);
|
|
7933
|
+
case "eof": throw new ExpressionParseError("unexpected end of expression", tok.pos);
|
|
7934
|
+
}
|
|
7935
|
+
}
|
|
7936
|
+
parseCall(callee, pos) {
|
|
7937
|
+
if (!EXPRESSION_BUILTIN_NAMES.has(callee)) throw new ExpressionParseError(`unknown function '${callee}'`, pos);
|
|
7938
|
+
this.expectPunct("(");
|
|
7939
|
+
const args = [];
|
|
7940
|
+
if (!this.matchPunct(")")) for (;;) {
|
|
7941
|
+
args.push(this.parseTernary());
|
|
7942
|
+
if (args.length > 16) throw new ExpressionParseError(`too many arguments to '${callee}'`, pos);
|
|
7943
|
+
if (this.matchPunct(",")) continue;
|
|
7944
|
+
this.expectPunct(")");
|
|
7945
|
+
break;
|
|
7946
|
+
}
|
|
7947
|
+
this.callees.add(callee);
|
|
7948
|
+
this.countNode();
|
|
7949
|
+
return {
|
|
7950
|
+
kind: "call",
|
|
7951
|
+
callee,
|
|
7952
|
+
args
|
|
7953
|
+
};
|
|
7954
|
+
}
|
|
7955
|
+
};
|
|
7956
|
+
/** Tokenize + parse `source` into a validated `ParsedExpression`. Throws
|
|
7957
|
+
* `ExpressionParseError` on any lexical or grammatical failure. */
|
|
7958
|
+
function parseExpression(source) {
|
|
7959
|
+
return new Parser(tokenize(source)).parse();
|
|
7960
|
+
}
|
|
7961
|
+
Object.freeze({});
|
|
7962
|
+
/**
|
|
7963
|
+
* LRU compile cache for parsed expressions (spec §2.4 "parse once … LRU keyed
|
|
7964
|
+
* by expr"). The cache stores BOTH successes and failures (negative caching),
|
|
7965
|
+
* so a corrupt persisted string costs exactly one tokenize+parse total — not
|
|
7966
|
+
* one per read on a hot resolve path.
|
|
7967
|
+
*
|
|
7968
|
+
* The cache is a module-level singleton: entries are pure, content-addressed
|
|
7969
|
+
* ASTs keyed by the raw source string, so sharing one instance across all
|
|
7970
|
+
* callers is safe and maximises hit rate.
|
|
7971
|
+
*/
|
|
7972
|
+
var cache = /* @__PURE__ */ new Map();
|
|
7973
|
+
function getCached(source) {
|
|
7974
|
+
const hit = cache.get(source);
|
|
7975
|
+
if (hit !== void 0) {
|
|
7976
|
+
cache.delete(source);
|
|
7977
|
+
cache.set(source, hit);
|
|
7978
|
+
return hit;
|
|
7979
|
+
}
|
|
7980
|
+
let result;
|
|
7981
|
+
try {
|
|
7982
|
+
result = {
|
|
7983
|
+
ok: true,
|
|
7984
|
+
parsed: parseExpression(source)
|
|
7985
|
+
};
|
|
7986
|
+
} catch (err) {
|
|
7987
|
+
result = {
|
|
7988
|
+
ok: false,
|
|
7989
|
+
error: err instanceof ExpressionParseError ? err.message : String(err)
|
|
7990
|
+
};
|
|
7991
|
+
}
|
|
7992
|
+
cache.set(source, result);
|
|
7993
|
+
if (cache.size > 256) {
|
|
7994
|
+
const oldest = cache.keys().next().value;
|
|
7995
|
+
if (oldest !== void 0) cache.delete(oldest);
|
|
7996
|
+
}
|
|
7997
|
+
return result;
|
|
7998
|
+
}
|
|
7999
|
+
/** Compile `source`, returning a discriminated result instead of throwing.
|
|
8000
|
+
* Used by read paths that must degrade rather than raise. LRU/negative-cached. */
|
|
8001
|
+
function compileExpressionSafe(source) {
|
|
8002
|
+
return getCached(source);
|
|
8003
|
+
}
|
|
8004
|
+
/**
|
|
8005
|
+
* Author-time validation. Returns `null` when the source is valid, else a
|
|
8006
|
+
* human-readable error message. Checks: the expression compiles; binding count
|
|
8007
|
+
* is within `MAX_EXPRESSION_BINDINGS`; every binding name is a legal identifier,
|
|
8008
|
+
* is not reserved (`now`/keywords) and does not shadow a builtin; and every
|
|
8009
|
+
* FREE identifier of the AST is covered by a binding or the injected `now`.
|
|
8010
|
+
*/
|
|
8011
|
+
function validateExpressionSource(src) {
|
|
8012
|
+
const names = Object.keys(src.bindings);
|
|
8013
|
+
if (names.length > 32) return `too many bindings (${names.length} > 32)`;
|
|
8014
|
+
for (const name of names) {
|
|
8015
|
+
if (!EXPRESSION_IDENTIFIER_RE.test(name)) return `invalid binding name '${name}'`;
|
|
8016
|
+
if (RESERVED_BINDING_NAMES.has(name)) return `binding name '${name}' is reserved`;
|
|
8017
|
+
if (EXPRESSION_BUILTIN_NAMES.has(name)) return `binding name '${name}' shadows a builtin function`;
|
|
8018
|
+
}
|
|
8019
|
+
const compiled = compileExpressionSafe(src.expr);
|
|
8020
|
+
if (!compiled.ok) return compiled.error;
|
|
8021
|
+
const bound = new Set(names);
|
|
8022
|
+
for (const id of compiled.parsed.identifiers) {
|
|
8023
|
+
if (id === "now") continue;
|
|
8024
|
+
if (!bound.has(id)) return `expression references unbound identifier '${id}'`;
|
|
8025
|
+
}
|
|
8026
|
+
return null;
|
|
8027
|
+
}
|
|
8028
|
+
/**
|
|
7434
8029
|
* Accessory device helpers — shared across drivers.
|
|
7435
8030
|
*
|
|
7436
8031
|
* Many vendor-specific drivers register accessory child devices on
|
|
@@ -12406,30 +13001,57 @@ var ChildLayoutEntrySchema = object({
|
|
|
12406
13001
|
* LITERAL source carries a per-device constant (no sibling is read); a
|
|
12407
13002
|
* GLOBAL source (P2e) copies ANY device's status field, addressed by the
|
|
12408
13003
|
* source device's full re-sync-stable `stableId`. */
|
|
13004
|
+
var DeviceLinkFieldSourceSchema = object({
|
|
13005
|
+
kind: literal("field").optional(),
|
|
13006
|
+
sourceKey: string(),
|
|
13007
|
+
cap: string(),
|
|
13008
|
+
fieldPath: string()
|
|
13009
|
+
});
|
|
13010
|
+
var DeviceLinkLiteralSourceSchema = object({
|
|
13011
|
+
kind: literal("literal"),
|
|
13012
|
+
value: union([
|
|
13013
|
+
string(),
|
|
13014
|
+
number(),
|
|
13015
|
+
boolean(),
|
|
13016
|
+
_null()
|
|
13017
|
+
])
|
|
13018
|
+
});
|
|
13019
|
+
var DeviceLinkGlobalSourceSchema = object({
|
|
13020
|
+
kind: literal("global"),
|
|
13021
|
+
sourceStableId: string(),
|
|
13022
|
+
cap: string(),
|
|
13023
|
+
fieldPath: string()
|
|
13024
|
+
});
|
|
13025
|
+
/** Expression source (Stage X): compute the target field from N named bindings
|
|
13026
|
+
* via the safe expression engine. Bindings are field | literal | global — never
|
|
13027
|
+
* another expression (no nesting). The `superRefine` runs the SAME author-time
|
|
13028
|
+
* validation as `validateExpressionSource` (compiles the expr, checks binding
|
|
13029
|
+
* names + identifier coverage) so every wire boundary that parses a DeviceLink
|
|
13030
|
+
* (tRPC mount, kernel create pre-seed, projection output) validates-at-write.
|
|
13031
|
+
* Compiles are LRU-cached, so repeated validation of the same expr is a hit. */
|
|
13032
|
+
var DeviceLinkExpressionSourceSchema = object({
|
|
13033
|
+
kind: literal("expression"),
|
|
13034
|
+
expr: string().min(1).max(MAX_EXPRESSION_SOURCE_LENGTH),
|
|
13035
|
+
bindings: record(string().regex(EXPRESSION_IDENTIFIER_RE), union([
|
|
13036
|
+
DeviceLinkFieldSourceSchema,
|
|
13037
|
+
DeviceLinkLiteralSourceSchema,
|
|
13038
|
+
DeviceLinkGlobalSourceSchema
|
|
13039
|
+
]))
|
|
13040
|
+
}).superRefine((src, ctx) => {
|
|
13041
|
+
const err = validateExpressionSource(src);
|
|
13042
|
+
if (err !== null) ctx.addIssue({
|
|
13043
|
+
code: "custom",
|
|
13044
|
+
message: err,
|
|
13045
|
+
path: ["expr"]
|
|
13046
|
+
});
|
|
13047
|
+
});
|
|
12409
13048
|
var DeviceLinkSchema = object({
|
|
12410
13049
|
id: string(),
|
|
12411
13050
|
source: union([
|
|
12412
|
-
|
|
12413
|
-
|
|
12414
|
-
|
|
12415
|
-
|
|
12416
|
-
fieldPath: string()
|
|
12417
|
-
}),
|
|
12418
|
-
object({
|
|
12419
|
-
kind: literal("literal"),
|
|
12420
|
-
value: union([
|
|
12421
|
-
string(),
|
|
12422
|
-
number(),
|
|
12423
|
-
boolean(),
|
|
12424
|
-
_null()
|
|
12425
|
-
])
|
|
12426
|
-
}),
|
|
12427
|
-
object({
|
|
12428
|
-
kind: literal("global"),
|
|
12429
|
-
sourceStableId: string(),
|
|
12430
|
-
cap: string(),
|
|
12431
|
-
fieldPath: string()
|
|
12432
|
-
})
|
|
13051
|
+
DeviceLinkFieldSourceSchema,
|
|
13052
|
+
DeviceLinkLiteralSourceSchema,
|
|
13053
|
+
DeviceLinkGlobalSourceSchema,
|
|
13054
|
+
DeviceLinkExpressionSourceSchema
|
|
12433
13055
|
]),
|
|
12434
13056
|
target: object({
|
|
12435
13057
|
cap: string(),
|
|
@@ -12459,6 +13081,31 @@ var DeviceLinkSchema = object({
|
|
|
12459
13081
|
})
|
|
12460
13082
|
]).optional()
|
|
12461
13083
|
});
|
|
13084
|
+
/** Cap-wire shape of a per-cap display refinement — mirrors
|
|
13085
|
+
* `DeviceCapDisplayOverride` in `device-management.ts`. */
|
|
13086
|
+
var DeviceCapDisplayOverrideSchema = object({
|
|
13087
|
+
unit: string().min(1).optional(),
|
|
13088
|
+
precision: number().int().min(0).max(10).optional()
|
|
13089
|
+
});
|
|
13090
|
+
/** Cap-wire shape of an operator-authored per-device display override —
|
|
13091
|
+
* mirrors `DeviceDisplayOverride` in `device-management.ts`. `precision`
|
|
13092
|
+
* bounds mirror `numeric-sensor.cap.ts` (`int 0-10`). */
|
|
13093
|
+
var DeviceDisplayOverrideSchema = object({
|
|
13094
|
+
icon: string().min(1).optional(),
|
|
13095
|
+
label: string().min(1).optional(),
|
|
13096
|
+
unit: string().min(1).optional(),
|
|
13097
|
+
precision: number().int().min(0).max(10).optional(),
|
|
13098
|
+
hidden: boolean().optional(),
|
|
13099
|
+
perCap: record(string(), DeviceCapDisplayOverrideSchema).optional()
|
|
13100
|
+
});
|
|
13101
|
+
/** Cap-wire shape of a per-role display default — mirrors `RoleDisplayDefault`
|
|
13102
|
+
* in `device-management.ts`. Keyed by `DeviceRole` string (role strings cross
|
|
13103
|
+
* the wire as plain strings everywhere else — cf. `DeviceInfoSchema.role`). */
|
|
13104
|
+
var RoleDisplayDefaultSchema = object({
|
|
13105
|
+
unit: string().min(1).optional(),
|
|
13106
|
+
precision: number().int().min(0).max(10).optional(),
|
|
13107
|
+
icon: string().min(1).optional()
|
|
13108
|
+
});
|
|
12462
13109
|
/**
|
|
12463
13110
|
* Serializable projection of a live IDevice.
|
|
12464
13111
|
* Returned by listAll, getDevice, getChildren.
|
|
@@ -12514,7 +13161,9 @@ var DeviceInfoSchema = object({
|
|
|
12514
13161
|
* `DeviceMeta.childLayout`. Absent ⇒ no layout declared. */
|
|
12515
13162
|
childLayout: array(ChildLayoutEntrySchema).readonly().optional(),
|
|
12516
13163
|
/** Operator-authored cross-device field wirings. See `DeviceMeta.deviceLinks`. */
|
|
12517
|
-
deviceLinks: array(DeviceLinkSchema).readonly().optional()
|
|
13164
|
+
deviceLinks: array(DeviceLinkSchema).readonly().optional(),
|
|
13165
|
+
/** Operator-authored per-device display override. See `DeviceMeta.display`. */
|
|
13166
|
+
display: DeviceDisplayOverrideSchema.optional()
|
|
12518
13167
|
});
|
|
12519
13168
|
var ConfigEntrySchema = object({
|
|
12520
13169
|
key: string(),
|
|
@@ -12579,7 +13228,9 @@ var DeviceMetaSchema = object({
|
|
|
12579
13228
|
deviceLinks: array(DeviceLinkSchema).readonly().optional(),
|
|
12580
13229
|
/** Semantic role string (`DeviceRole`) — propagated from the spawn pre-seed.
|
|
12581
13230
|
* Optional: only present for accessory children that carry a known role. */
|
|
12582
|
-
role: string().nullable().optional()
|
|
13231
|
+
role: string().nullable().optional(),
|
|
13232
|
+
/** Operator-authored per-device display override. See `DeviceMeta.display`. */
|
|
13233
|
+
display: DeviceDisplayOverrideSchema.optional()
|
|
12583
13234
|
});
|
|
12584
13235
|
/** ConfigUISchema passed through as unknown — mirrors device-provider's CreationSchemaOutputSchema */
|
|
12585
13236
|
var ConfigUISchemaOutput = unknown().nullable();
|
|
@@ -12673,6 +13324,15 @@ method(object({
|
|
|
12673
13324
|
}), _void(), {
|
|
12674
13325
|
kind: "mutation",
|
|
12675
13326
|
auth: "admin"
|
|
13327
|
+
}), method(object({
|
|
13328
|
+
deviceId: number(),
|
|
13329
|
+
display: DeviceDisplayOverrideSchema.nullable()
|
|
13330
|
+
}), _void(), {
|
|
13331
|
+
kind: "mutation",
|
|
13332
|
+
auth: "admin"
|
|
13333
|
+
}), method(object({}), object({ defaults: record(string(), RoleDisplayDefaultSchema) }), { kind: "query" }), method(object({ defaults: record(string(), RoleDisplayDefaultSchema) }), _void(), {
|
|
13334
|
+
kind: "mutation",
|
|
13335
|
+
auth: "admin"
|
|
12676
13336
|
}), method(object({
|
|
12677
13337
|
deviceId: number(),
|
|
12678
13338
|
includeSynthesizable: boolean().optional()
|
|
@@ -18352,6 +19012,12 @@ Object.freeze({
|
|
|
18352
19012
|
addonId: null,
|
|
18353
19013
|
access: "view"
|
|
18354
19014
|
},
|
|
19015
|
+
"deviceManager.getRoleDisplayDefaults": {
|
|
19016
|
+
capName: "device-manager",
|
|
19017
|
+
capScope: "system",
|
|
19018
|
+
addonId: null,
|
|
19019
|
+
access: "view"
|
|
19020
|
+
},
|
|
18355
19021
|
"deviceManager.getSettingsSchema": {
|
|
18356
19022
|
capName: "device-manager",
|
|
18357
19023
|
capScope: "system",
|
|
@@ -18502,6 +19168,12 @@ Object.freeze({
|
|
|
18502
19168
|
addonId: null,
|
|
18503
19169
|
access: "create"
|
|
18504
19170
|
},
|
|
19171
|
+
"deviceManager.setDisplay": {
|
|
19172
|
+
capName: "device-manager",
|
|
19173
|
+
capScope: "system",
|
|
19174
|
+
addonId: null,
|
|
19175
|
+
access: "create"
|
|
19176
|
+
},
|
|
18505
19177
|
"deviceManager.setIntegrationId": {
|
|
18506
19178
|
capName: "device-manager",
|
|
18507
19179
|
capScope: "system",
|
|
@@ -18544,6 +19216,12 @@ Object.freeze({
|
|
|
18544
19216
|
addonId: null,
|
|
18545
19217
|
access: "create"
|
|
18546
19218
|
},
|
|
19219
|
+
"deviceManager.setRoleDisplayDefaults": {
|
|
19220
|
+
capName: "device-manager",
|
|
19221
|
+
capScope: "system",
|
|
19222
|
+
addonId: null,
|
|
19223
|
+
access: "create"
|
|
19224
|
+
},
|
|
18547
19225
|
"deviceManager.setStreamProfileMap": {
|
|
18548
19226
|
capName: "device-manager",
|
|
18549
19227
|
capScope: "system",
|
|
@@ -21568,7 +22246,7 @@ var AdminUIAddon = class extends BaseAddon {
|
|
|
21568
22246
|
capability: adminUiCapability,
|
|
21569
22247
|
provider: {
|
|
21570
22248
|
getStaticDir: async () => ({ staticDir: resolveAdminUiDistDir() }),
|
|
21571
|
-
getVersion: async () => ({ version: "1.1.
|
|
22249
|
+
getVersion: async () => ({ version: "1.1.22" })
|
|
21572
22250
|
}
|
|
21573
22251
|
}];
|
|
21574
22252
|
}
|