@camstack/addon-admin-ui 1.1.20 → 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.
Files changed (89) hide show
  1. package/dist/assets/{AddLocationWizard-Brlh9UJ9.js → AddLocationWizard-hVwjbOvf.js} +1 -1
  2. package/dist/assets/{AddonCollectionPage-Bg5OVL_9.js → AddonCollectionPage-CTsqn59E.js} +1 -1
  3. package/dist/assets/Addons-CCbeVMQt.js +1 -0
  4. package/dist/assets/{AdminTabs-DVI3osLb.js → AdminTabs-H2eHA_BP.js} +1 -1
  5. package/dist/assets/{BrokerForm-CS__YhVd.js → BrokerForm-I-2eiXTD.js} +1 -1
  6. package/dist/assets/{Capabilities-sR8ZG2Sp.js → Capabilities-KNxdGU5R.js} +1 -1
  7. package/dist/assets/{CapabilityBadges-BtwEWtSB.js → CapabilityBadges-Bp9qwWAG.js} +1 -1
  8. package/dist/assets/Cluster-ChnNCri_.js +1 -0
  9. package/dist/assets/{Dashboard-cUXiEA9q.js → Dashboard-CgzNKw4S.js} +1 -1
  10. package/dist/assets/{Data-FggSTTQB.js → Data-GY9aNQ1Y.js} +1 -1
  11. package/dist/assets/{DetectionIntelligence-BG1dq_BC.js → DetectionIntelligence-CbBEvocZ.js} +1 -1
  12. package/dist/assets/DeviceDetail-sgGEfTXB.js +2 -0
  13. package/dist/assets/{Devices-DfYGm_-Y.js → Devices-2wZcDSXn.js} +1 -1
  14. package/dist/assets/EmbedPlayerPage-BSfF5HmG.js +1 -0
  15. package/dist/assets/{FormBuilder-B6OIFE8M.js → FormBuilder-CO6H7q61.js} +1 -1
  16. package/dist/assets/Identity-Ctx_yZtf.js +1 -0
  17. package/dist/assets/IntegrationDetail-DQI58WRY.js +1 -0
  18. package/dist/assets/{Integrations-BOUUPSGH.js → Integrations-Dee1SHhr.js} +1 -1
  19. package/dist/assets/Integrations-rZdfMVdZ.js +1 -0
  20. package/dist/assets/{Logs-C_K69uCx.js → Logs-BJ61UdxK.js} +1 -1
  21. package/dist/assets/{MotionZonesSettings-BnjJUOgY.js → MotionZonesSettings-CYzimYmN.js} +1 -1
  22. package/dist/assets/{MyAccess-BKZkUhvb.js → MyAccess-Bgewpx3A.js} +1 -1
  23. package/dist/assets/Network-Dc_a0WJ9.js +1 -0
  24. package/dist/assets/NodeAddonsSettingsPanel-CWrLPV6J.js +1 -0
  25. package/dist/assets/{NotificationTargets-DlPYj2Ic.js → NotificationTargets-lEW7Zldv.js} +1 -1
  26. package/dist/assets/Pipeline-CbfX9p5j.js +1 -0
  27. package/dist/assets/{PrivacyMaskSettings-RUAuOFuS.js → PrivacyMaskSettings-CzPxZHZ1.js} +1 -1
  28. package/dist/assets/{ProviderIcon-RCIWUZYh.js → ProviderIcon-Dm-sZ7Df.js} +1 -1
  29. package/dist/assets/{ScanNetworkModal-CVTAzCpc.js → ScanNetworkModal-Vcr_-aIb.js} +1 -1
  30. package/dist/assets/{Settings-BRGkGmWW.js → Settings-WQCzalu_.js} +1 -1
  31. package/dist/assets/{Showroom-nB3ihbXc.js → Showroom-BxISco8h.js} +1 -1
  32. package/dist/assets/{_virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-CCEnK7l6.js → _virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-CKTRvTR8.js} +1 -1
  33. package/dist/assets/circle-check-big-B9mpY_ym.js +1 -0
  34. package/dist/assets/{copy-Dx6PkNh2.js → copy-CjMMaCPu.js} +1 -1
  35. package/dist/assets/{dist-BcfEPpAI.js → dist-DsiSY20Z.js} +1 -1
  36. package/dist/assets/dist-u_nf627j.js +7 -0
  37. package/dist/assets/{download-hTrdF0db.js → download-35ioIRtw.js} +1 -1
  38. package/dist/assets/{esm-CU8QwYlu.js → esm-DPIMznCO.js} +1 -1
  39. package/dist/assets/{hostInit-Bkxnbz6r.js → hostInit-BQK5GXsV.js} +1 -1
  40. package/dist/assets/index-BQGzI2C-.css +2 -0
  41. package/dist/assets/index-BdGL2J0e.js +4 -0
  42. package/dist/assets/{key-round-CME-3JbN.js → key-round-CHE1k3cQ.js} +1 -1
  43. package/dist/assets/{mf-entry-bootstrap-0-b91b99eb.js → mf-entry-bootstrap-0-5940e459.js} +2 -2
  44. package/dist/assets/{pencil-DJ_y_Wy8.js → pencil-C1w2uLp9.js} +1 -1
  45. package/dist/assets/{player-overlays-DEDwF8Uo.js → player-overlays-DlPIT9xj.js} +1 -1
  46. package/dist/assets/plus-D9QBDEjM.js +1 -0
  47. package/dist/assets/{radio-C_HfliiA.js → radio-DpwfMzDk.js} +1 -1
  48. package/dist/assets/{refresh-cw-9oudg8kg.js → refresh-cw-DfSn-i0F.js} +1 -1
  49. package/dist/assets/remoteEntry-CIdYQQ-f.js +1 -0
  50. package/dist/assets/{rotate-ccw-5_RfArHn.js → rotate-ccw--rHGluty.js} +1 -1
  51. package/dist/assets/rotate-cw-DtSHMNUL.js +1 -0
  52. package/dist/assets/search-DgJL1Gey.js +1 -0
  53. package/dist/assets/{server-CQ1LH5PQ.js → server-BlM9U_dS.js} +1 -1
  54. package/dist/assets/{sparkles-DvV1ODWG.js → sparkles-COBUjBX-.js} +1 -1
  55. package/dist/assets/square-VsNW1mnX.js +1 -0
  56. package/dist/assets/{square-check-big-64TOhDex.js → square-check-big-Dej4DiE7.js} +1 -1
  57. package/dist/assets/src-C9eW94dA.js +7 -0
  58. package/dist/assets/src-CtvTbpOC.js +61 -0
  59. package/dist/assets/{upload-BgSvbRWR.js → upload-BJzZajFJ.js} +1 -1
  60. package/dist/assets/useDevice-CjqFlWNw.js +1 -0
  61. package/dist/assets/{useEventInvalidation-BTia6ZIb.js → useEventInvalidation-CY1yyH4R.js} +1 -1
  62. package/dist/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-tX1XrtZb.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-Dl7HuNe3.js} +2 -2
  63. package/dist/assets/{wifi-Ctshxl91.js → wifi-Dj3gSpzs.js} +1 -1
  64. package/dist/assets/{zap-BgTF9BOT.js → zap-DLkdpIj9.js} +1 -1
  65. package/dist/index.html +6 -6
  66. package/dist/server/addon.js +731 -15
  67. package/package.json +1 -1
  68. package/dist/assets/Addons-2VeHH2Fx.js +0 -1
  69. package/dist/assets/Cluster-BsMp1-aa.js +0 -1
  70. package/dist/assets/DeviceDetail-DD7tVaBH.js +0 -2
  71. package/dist/assets/EmbedPlayerPage-2oboqnId.js +0 -1
  72. package/dist/assets/Identity-CiOHNQP2.js +0 -1
  73. package/dist/assets/IntegrationDetail-BVhsZAdC.js +0 -1
  74. package/dist/assets/Integrations-CVCNKHh5.js +0 -1
  75. package/dist/assets/Network-Bu7lrlmc.js +0 -1
  76. package/dist/assets/NodeAddonsSettingsPanel-CsBUUhBI.js +0 -1
  77. package/dist/assets/Pipeline-CFOZ4ITe.js +0 -1
  78. package/dist/assets/circle-check-big-DUVoa4K8.js +0 -1
  79. package/dist/assets/dist-B40Mc3dp.js +0 -6
  80. package/dist/assets/index-DpDrVUWD.css +0 -2
  81. package/dist/assets/index-DvxZ6VPS.js +0 -4
  82. package/dist/assets/plus-BgpJnRYz.js +0 -1
  83. package/dist/assets/remoteEntry-Buh8tQ2B.js +0 -1
  84. package/dist/assets/rotate-cw-ClWkf91I.js +0 -1
  85. package/dist/assets/search-CxsQfiZy.js +0 -1
  86. package/dist/assets/square-CQY_D8K1.js +0 -1
  87. package/dist/assets/src-50esl92F.js +0 -61
  88. package/dist/assets/src-BnbSKfdg.js +0 -6
  89. package/dist/assets/useDevice-BGpZXQ7x.js +0 -1
@@ -4629,7 +4629,7 @@ function _instanceof(cls, params = {}) {
4629
4629
  return inst;
4630
4630
  }
4631
4631
  //#endregion
4632
- //#region ../types/dist/sleep-MHm--th-.mjs
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
@@ -12401,14 +12996,63 @@ var ChildLayoutEntrySchema = object({
12401
12996
  collapsed: boolean().optional()
12402
12997
  });
12403
12998
  /** Cap-wire shape of a DeviceLink — structurally mirrors `DeviceLink` in
12404
- * `device-management.ts`. */
12999
+ * `device-management.ts`. Source is a union: a FIELD source copies a sibling
13000
+ * accessory's status field (`kind` optional/absent for wire compat); a
13001
+ * LITERAL source carries a per-device constant (no sibling is read); a
13002
+ * GLOBAL source (P2e) copies ANY device's status field, addressed by the
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
+ });
12405
13048
  var DeviceLinkSchema = object({
12406
13049
  id: string(),
12407
- source: object({
12408
- sourceKey: string(),
12409
- cap: string(),
12410
- fieldPath: string()
12411
- }),
13050
+ source: union([
13051
+ DeviceLinkFieldSourceSchema,
13052
+ DeviceLinkLiteralSourceSchema,
13053
+ DeviceLinkGlobalSourceSchema,
13054
+ DeviceLinkExpressionSourceSchema
13055
+ ]),
12412
13056
  target: object({
12413
13057
  cap: string(),
12414
13058
  fieldPath: string(),
@@ -12437,6 +13081,31 @@ var DeviceLinkSchema = object({
12437
13081
  })
12438
13082
  ]).optional()
12439
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
+ });
12440
13109
  /**
12441
13110
  * Serializable projection of a live IDevice.
12442
13111
  * Returned by listAll, getDevice, getChildren.
@@ -12492,7 +13161,9 @@ var DeviceInfoSchema = object({
12492
13161
  * `DeviceMeta.childLayout`. Absent ⇒ no layout declared. */
12493
13162
  childLayout: array(ChildLayoutEntrySchema).readonly().optional(),
12494
13163
  /** Operator-authored cross-device field wirings. See `DeviceMeta.deviceLinks`. */
12495
- 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()
12496
13167
  });
12497
13168
  var ConfigEntrySchema = object({
12498
13169
  key: string(),
@@ -12557,7 +13228,9 @@ var DeviceMetaSchema = object({
12557
13228
  deviceLinks: array(DeviceLinkSchema).readonly().optional(),
12558
13229
  /** Semantic role string (`DeviceRole`) — propagated from the spawn pre-seed.
12559
13230
  * Optional: only present for accessory children that carry a known role. */
12560
- role: string().nullable().optional()
13231
+ role: string().nullable().optional(),
13232
+ /** Operator-authored per-device display override. See `DeviceMeta.display`. */
13233
+ display: DeviceDisplayOverrideSchema.optional()
12561
13234
  });
12562
13235
  /** ConfigUISchema passed through as unknown — mirrors device-provider's CreationSchemaOutputSchema */
12563
13236
  var ConfigUISchemaOutput = unknown().nullable();
@@ -12651,7 +13324,19 @@ method(object({
12651
13324
  }), _void(), {
12652
13325
  kind: "mutation",
12653
13326
  auth: "admin"
12654
- }), method(object({ deviceId: number() }), object({ caps: array(object({
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"
13336
+ }), method(object({
13337
+ deviceId: number(),
13338
+ includeSynthesizable: boolean().optional()
13339
+ }), object({ caps: array(object({
12655
13340
  cap: string(),
12656
13341
  fields: array(object({
12657
13342
  path: string(),
@@ -12661,8 +13346,13 @@ method(object({
12661
13346
  "boolean",
12662
13347
  "enum"
12663
13348
  ]),
12664
- enumValues: array(string()).optional()
12665
- })).readonly()
13349
+ enumValues: array(string()).optional(),
13350
+ item: boolean().optional()
13351
+ })).readonly(),
13352
+ itemArray: object({
13353
+ path: string(),
13354
+ keyField: string()
13355
+ }).optional()
12666
13356
  })).readonly() }), { kind: "query" }), method(object({
12667
13357
  deviceId: number(),
12668
13358
  role: string().nullable()
@@ -12732,7 +13422,11 @@ method(object({
12732
13422
  deviceId: number(),
12733
13423
  entries: array(object({
12734
13424
  capName: string(),
12735
- kind: _enum(["native", "wrapped"]),
13425
+ kind: _enum([
13426
+ "native",
13427
+ "wrapped",
13428
+ "linked"
13429
+ ]),
12736
13430
  providerAddonId: string(),
12737
13431
  providerNodeId: string(),
12738
13432
  nativeAddonId: string()
@@ -12741,7 +13435,11 @@ method(object({
12741
13435
  deviceId: number(),
12742
13436
  entries: array(object({
12743
13437
  capName: string(),
12744
- kind: _enum(["native", "wrapped"]),
13438
+ kind: _enum([
13439
+ "native",
13440
+ "wrapped",
13441
+ "linked"
13442
+ ]),
12745
13443
  providerAddonId: string(),
12746
13444
  providerNodeId: string(),
12747
13445
  nativeAddonId: string()
@@ -18314,6 +19012,12 @@ Object.freeze({
18314
19012
  addonId: null,
18315
19013
  access: "view"
18316
19014
  },
19015
+ "deviceManager.getRoleDisplayDefaults": {
19016
+ capName: "device-manager",
19017
+ capScope: "system",
19018
+ addonId: null,
19019
+ access: "view"
19020
+ },
18317
19021
  "deviceManager.getSettingsSchema": {
18318
19022
  capName: "device-manager",
18319
19023
  capScope: "system",
@@ -18464,6 +19168,12 @@ Object.freeze({
18464
19168
  addonId: null,
18465
19169
  access: "create"
18466
19170
  },
19171
+ "deviceManager.setDisplay": {
19172
+ capName: "device-manager",
19173
+ capScope: "system",
19174
+ addonId: null,
19175
+ access: "create"
19176
+ },
18467
19177
  "deviceManager.setIntegrationId": {
18468
19178
  capName: "device-manager",
18469
19179
  capScope: "system",
@@ -18506,6 +19216,12 @@ Object.freeze({
18506
19216
  addonId: null,
18507
19217
  access: "create"
18508
19218
  },
19219
+ "deviceManager.setRoleDisplayDefaults": {
19220
+ capName: "device-manager",
19221
+ capScope: "system",
19222
+ addonId: null,
19223
+ access: "create"
19224
+ },
18509
19225
  "deviceManager.setStreamProfileMap": {
18510
19226
  capName: "device-manager",
18511
19227
  capScope: "system",
@@ -21530,7 +22246,7 @@ var AdminUIAddon = class extends BaseAddon {
21530
22246
  capability: adminUiCapability,
21531
22247
  provider: {
21532
22248
  getStaticDir: async () => ({ staticDir: resolveAdminUiDistDir() }),
21533
- getVersion: async () => ({ version: "1.1.20" })
22249
+ getVersion: async () => ({ version: "1.1.22" })
21534
22250
  }
21535
22251
  }];
21536
22252
  }