@camstack/addon-osd-manager 0.1.157 → 0.1.160

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 (17) hide show
  1. package/dist/{MotionZonesSettings-vYt4dibj.mjs → MotionZonesSettings-gJgHYJJc.mjs} +2 -2
  2. package/dist/{PrivacyMaskSettings-BiQ78hst.mjs → PrivacyMaskSettings-HmUc5RFn.mjs} +4 -4
  3. package/dist/{SceneMonitorEditor-CJtJIyMf.mjs → SceneMonitorEditor-Dqc4eAZT.mjs} +3 -3
  4. package/dist/_stub.js +3065 -2707
  5. package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_osd_manager_page-DdAtpC7z.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_osd_manager_page-BX8u4O5k.mjs} +2 -2
  6. package/dist/{_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BtgV-Ym5.mjs → _virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BzuGVFNp.mjs} +1 -1
  7. package/dist/{hostInit-0Mc7Fm1R.mjs → hostInit-o9ggbWOT.mjs} +1 -1
  8. package/dist/index.js +260 -46
  9. package/dist/index.mjs +240 -47
  10. package/dist/{player-overlays-BPyna-eI.mjs → player-overlays-BgDqoYs3.mjs} +1 -1
  11. package/dist/remoteEntry.js +1 -1
  12. package/dist/{responsive-B0yDP9vf.mjs → responsive-B7zCyVCX.mjs} +1 -1
  13. package/dist/{scene-monitor-copy-BzX20O6q.mjs → scene-monitor-copy-DWIcj1X6.mjs} +1 -1
  14. package/dist/{square-BOMOn_6j.mjs → square-D0YQUHMC.mjs} +1 -1
  15. package/dist/{trash-2-BolGRl2P.mjs → trash-2-C_1H5SIl.mjs} +1 -1
  16. package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_osd_manager_page__remoteEntry_js-UY9P_4V2.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_osd_manager_page__remoteEntry_js-BAuPDG6y.mjs} +1 -1
  17. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -39344,24 +39344,45 @@ setOverlay: method(object({
39344
39344
  * conditions it is shown at all. Named TEMPLATES combine many device
39345
39345
  * fields into one overlay string (Scrypted OSD Manager parity).
39346
39346
  */
39347
- /** One field reference inside a named multi-device template. */
39348
- var OsdTemplateFieldSchema = object({
39349
- deviceId: number().int(),
39347
+ /** What `{alias}` expands to for one template binding. Exactly one choice. */
39348
+ var OsdTemplateFormatSchema = _enum([
39349
+ "value+unit",
39350
+ "value",
39351
+ "unit"
39352
+ ]);
39353
+ /**
39354
+ * How the operator reached the leaf device. `deviceId` is ALWAYS the
39355
+ * OSD-supported leaf that is read; `containerId` is set when the pick
39356
+ * went through a container (gateway) first.
39357
+ */
39358
+ var OsdTemplatePickSchema = object({
39359
+ containerId: number().int().optional(),
39360
+ deviceId: number().int()
39361
+ });
39362
+ /**
39363
+ * One named binding inside a multi-device template. The parser only
39364
+ * sees `{alias}`; format / unit / decimals live here structurally.
39365
+ */
39366
+ var OsdTemplateBindingSchema = object({
39367
+ /** Token in the parser, e.g. `t` → `{t}`. Unique within the template. */
39368
+ alias: string().min(1).max(32).regex(/^[A-Za-z][A-Za-z0-9_-]*$/, "alias must start with a letter"),
39369
+ pick: OsdTemplatePickSchema,
39350
39370
  capName: string().min(1).max(64),
39351
39371
  valuePath: string().min(1).max(64),
39372
+ format: OsdTemplateFormatSchema.default("value+unit"),
39352
39373
  /** Convert TO this unit at render (`tryConvertUnit`). Absent = source unit. */
39353
39374
  displayUnit: string().max(16).optional(),
39354
39375
  maxDecimals: number().int().min(0).max(4).default(1)
39355
39376
  });
39356
39377
  /**
39357
- * A named template: several device fields → one parser string with
39358
- * `{deviceId.capName.valuePath}` tokens (Scrypted `{deviceId.sensorId}`).
39378
+ * A named template: bindings (alias → leaf field) + a parser that only
39379
+ * references `{alias}` tokens.
39359
39380
  */
39360
39381
  var OsdNamedTemplateSchema = object({
39361
39382
  id: string().min(1).max(64),
39362
39383
  name: string().min(1).max(64),
39363
- fields: array(OsdTemplateFieldSchema).max(32).default([]),
39364
- /** Parser with multi-token placeholders, e.g. `T {12.thermometer.value}°`. */
39384
+ bindings: array(OsdTemplateBindingSchema).max(32).default([]),
39385
+ /** Parser with alias placeholders, e.g. `{t} / {h}`. */
39365
39386
  parser: string().max(256).default("")
39366
39387
  });
39367
39388
  /** Where a slot's value comes from. */
@@ -58368,14 +58389,42 @@ function readStatePath(slice, path) {
58368
58389
  }
58369
58390
  //#endregion
58370
58391
  //#region src/template-tokens.ts
58371
- /** Build the placeholder token for one template field. */
58372
- function fieldToken(field) {
58373
- return `{${field.deviceId}.${field.capName}.${field.valuePath}}`;
58392
+ /** Build the placeholder token for one binding alias. */
58393
+ function aliasToken(alias) {
58394
+ return `{${alias}}`;
58395
+ }
58396
+ /** Chip / parser token for a binding. */
58397
+ function bindingToken(binding) {
58398
+ return aliasToken(binding.alias);
58399
+ }
58400
+ /** Parse `{alias}` tokens from a parser string (letters, digits, `_`, `-`). */
58401
+ function parseAliasTokens(parser) {
58402
+ const out = [];
58403
+ for (const match of parser.matchAll(/\{([A-Za-z][A-Za-z0-9_-]*)\}/g)) {
58404
+ const alias = match[1];
58405
+ if (alias === void 0 || alias === "") continue;
58406
+ if (!out.includes(alias)) out.push(alias);
58407
+ }
58408
+ return out;
58374
58409
  }
58375
58410
  /** Replace every occurrence of `token` in `parser` with `value`. */
58376
58411
  function replaceToken(parser, token, value) {
58377
58412
  return parser.replaceAll(token, value);
58378
58413
  }
58414
+ /**
58415
+ * Suggest a short unique alias from a device/field name.
58416
+ * Falls back to `b1`, `b2`, … when the slug collides.
58417
+ */
58418
+ function suggestAlias(seed, taken, fallbackPrefix = "b") {
58419
+ const slug = seed.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").replace(/^(\d)/, "a$1").slice(0, 24);
58420
+ const base = slug.length > 0 ? slug : fallbackPrefix;
58421
+ if (!taken.has(base)) return base;
58422
+ for (let i = 2; i < 1e3; i += 1) {
58423
+ const candidate = `${base}${i}`.slice(0, 32);
58424
+ if (!taken.has(candidate)) return candidate;
58425
+ }
58426
+ return `${fallbackPrefix}${Date.now().toString(36)}`;
58427
+ }
58379
58428
  //#endregion
58380
58429
  //#region src/unit-display.ts
58381
58430
  /**
@@ -58431,24 +58480,48 @@ function inferSourceUnit(slice, valuePath) {
58431
58480
  }
58432
58481
  //#endregion
58433
58482
  //#region src/named-template-render.ts
58483
+ /** Combine value/unit according to the binding's single format choice. */
58484
+ function applyTemplateFormat(value, unit, format) {
58485
+ if (format === "value") return value;
58486
+ if (format === "unit") return unit;
58487
+ const v = value.trim();
58488
+ const u = unit.trim();
58489
+ if (v === "") return u;
58490
+ if (u === "") return v;
58491
+ return `${v} ${u}`;
58492
+ }
58493
+ /** Resolve one binding to live value/unit/formatted parts (or a reason). */
58494
+ function resolveBindingLive(binding, facts) {
58495
+ const deviceId = binding.pick.deviceId;
58496
+ const deviceState = facts.stateByDevice.get(deviceId);
58497
+ if (deviceState === void 0) return { reason: `no state mirrored for device ${deviceId}` };
58498
+ const slice = deviceState[binding.capName];
58499
+ if (slice === void 0) return { reason: `device ${deviceId} publishes no "${binding.capName}" state` };
58500
+ const raw = readStatePath(slice, binding.valuePath);
58501
+ if (raw === void 0) return { reason: `"${binding.capName}.${binding.valuePath}" is absent on device ${deviceId}` };
58502
+ let value;
58503
+ let unit = "";
58504
+ if (typeof raw === "number") {
58505
+ const converted = convertForDisplay(raw, inferSourceUnit(slice, binding.valuePath), binding.displayUnit);
58506
+ value = truncateDecimals(converted.value, binding.maxDecimals);
58507
+ unit = converted.unit;
58508
+ } else if (typeof raw === "boolean") value = raw ? "ON" : "OFF";
58509
+ else if (raw === null) value = "";
58510
+ else value = String(raw);
58511
+ return {
58512
+ value,
58513
+ unit,
58514
+ formatted: applyTemplateFormat(value, unit, binding.format)
58515
+ };
58516
+ }
58434
58517
  /** Render one named template's parser from live states. */
58435
58518
  function renderNamedTemplate(template, facts) {
58436
58519
  let text = template.parser;
58437
- if (template.fields.length === 0) return text.trim() === "" ? { reason: `template "${template.id}" has no fields` } : { text };
58438
- for (const field of template.fields) {
58439
- const token = fieldToken(field);
58440
- const deviceState = facts.stateByDevice.get(field.deviceId);
58441
- if (deviceState === void 0) return { reason: `no state mirrored for device ${field.deviceId}` };
58442
- const slice = deviceState[field.capName];
58443
- if (slice === void 0) return { reason: `device ${field.deviceId} publishes no "${field.capName}" state` };
58444
- const raw = readStatePath(slice, field.valuePath);
58445
- if (raw === void 0) return { reason: `"${field.capName}.${field.valuePath}" is absent on device ${field.deviceId}` };
58446
- let rendered;
58447
- if (typeof raw === "number") rendered = truncateDecimals(convertForDisplay(raw, inferSourceUnit(slice, field.valuePath), field.displayUnit).value, field.maxDecimals);
58448
- else if (typeof raw === "boolean") rendered = raw ? "ON" : "OFF";
58449
- else if (raw === null) rendered = "";
58450
- else rendered = String(raw);
58451
- text = replaceToken(text, token, rendered);
58520
+ if (template.bindings.length === 0) return text.trim() === "" ? { reason: `template "${template.id}" has no bindings` } : { text };
58521
+ for (const binding of template.bindings) {
58522
+ const live = resolveBindingLive(binding, facts);
58523
+ if ("reason" in live) return live;
58524
+ text = replaceToken(text, aliasToken(binding.alias), live.formatted);
58452
58525
  }
58453
58526
  return { text };
58454
58527
  }
@@ -58550,20 +58623,98 @@ function settle(slotId, text, previousText, outcome, reason) {
58550
58623
  };
58551
58624
  }
58552
58625
  //#endregion
58626
+ //#region src/osd-source-fields.ts
58627
+ /** Caps the OSD source picker may bind. */
58628
+ var OSD_SOURCE_CAP_NAMES = new Set([
58629
+ "temperature-sensor",
58630
+ "humidity-sensor",
58631
+ "climate-control",
58632
+ "numeric-sensor",
58633
+ "weather",
58634
+ "air-quality-sensor",
58635
+ "lock-control",
58636
+ "contact",
58637
+ "binary",
58638
+ "battery"
58639
+ ]);
58640
+ /**
58641
+ * Per-cap leaf allowlist. Absent entry ⇒ every leaf from `stateLeavesOf`
58642
+ * that survives bookkeeping (single-metric sensors). Present ⇒ only these
58643
+ * paths (climate / weather / battery).
58644
+ */
58645
+ var OSD_SOURCE_PATHS = new Map([
58646
+ ["climate-control", new Set([
58647
+ "currentTemp",
58648
+ "currentHumidity",
58649
+ "target",
58650
+ "targetHumidity",
58651
+ "mode"
58652
+ ])],
58653
+ ["weather", new Set([
58654
+ "condition",
58655
+ "temperature",
58656
+ "humidity",
58657
+ "pressure",
58658
+ "windSpeed",
58659
+ "windBearing"
58660
+ ])],
58661
+ ["battery", new Set(["percentage"])],
58662
+ ["temperature-sensor", new Set(["celsius"])],
58663
+ ["humidity-sensor", new Set(["percent"])],
58664
+ ["numeric-sensor", new Set(["value"])],
58665
+ ["air-quality-sensor", new Set([
58666
+ "co2Ppm",
58667
+ "vocPpb",
58668
+ "pm25",
58669
+ "pm10",
58670
+ "aqi"
58671
+ ])],
58672
+ ["binary", new Set(["on"])],
58673
+ ["contact", new Set(["entryOpen"])],
58674
+ ["lock-control", new Set(["state"])]
58675
+ ]);
58676
+ function isOsdSourceCap(capName) {
58677
+ return OSD_SOURCE_CAP_NAMES.has(capName);
58678
+ }
58679
+ /** Bindable OSD leaves for one cap — empty when the cap is not OSD-relevant. */
58680
+ function osdStateLeavesOf(cap) {
58681
+ if (!isOsdSourceCap(cap.name)) return [];
58682
+ const leaves = stateLeavesOf(cap);
58683
+ const allowed = OSD_SOURCE_PATHS.get(cap.name);
58684
+ if (allowed === void 0) return leaves;
58685
+ return leaves.filter((leaf) => allowed.has(leaf.path));
58686
+ }
58687
+ /** Device types that never contribute their OWN catalog leaves. */
58688
+ var OSD_NON_LEAF_TYPES = new Set(["container"]);
58689
+ /** True when this device type may expose OSD leaves (not a container gateway). */
58690
+ function isOsdLeafDeviceType(type) {
58691
+ if (type === null || type === void 0) return true;
58692
+ return !OSD_NON_LEAF_TYPES.has(type);
58693
+ }
58694
+ /** @deprecated Prefer {@link isOsdLeafDeviceType}. */
58695
+ var OSD_PICKER_EXCLUDED_TYPES = OSD_NON_LEAF_TYPES;
58696
+ /** @deprecated Prefer {@link isOsdLeafDeviceType}. */
58697
+ function isOsdPickerDeviceType(type) {
58698
+ return isOsdLeafDeviceType(type);
58699
+ }
58700
+ function isContainerDeviceType(type) {
58701
+ return type === "container";
58702
+ }
58703
+ //#endregion
58553
58704
  //#region src/source-catalog.ts
58554
58705
  /**
58555
- * Build the editor's source picker from the CAP DEFINITIONS — never a
58556
- * hand-written list. A cap that ships a new runtime-state field becomes
58557
- * bindable the moment it deploys, with no change here.
58706
+ * Build the editor's source picker from OSD-relevant cap definitions.
58707
+ * Gateway / infrastructure caps (broker, mqtt, deviceExport, …) never
58708
+ * appear — see `osd-source-fields.ts`.
58558
58709
  */
58559
58710
  /** Turn `air-quality-sensor` + `pm25` into `Air Quality Sensor · pm25`. */
58560
58711
  function humanizeCapName(capName) {
58561
58712
  return capName.split("-").map((part) => part.length === 0 ? part : part[0].toUpperCase() + part.slice(1)).join(" ");
58562
58713
  }
58563
58714
  /**
58564
- * Every bindable value across the cluster, with the camera's own state
58565
- * first — that is what an operator reaches for, and a picker that buries
58566
- * it under 200 other devices is a picker nobody uses.
58715
+ * Every OSD-bindable value across the cluster, with the camera's own
58716
+ * state first — that is what an operator reaches for, and a picker that
58717
+ * buries it under 200 other devices is a picker nobody uses.
58567
58718
  */
58568
58719
  function sourceOptionsFor(cameraDeviceId, devices, capsByDevice) {
58569
58720
  const capsByName = new Map(ALL_CAPABILITY_DEFINITIONS.map((cap) => [cap.name, cap]));
@@ -58573,18 +58724,22 @@ function sourceOptionsFor(cameraDeviceId, devices, capsByDevice) {
58573
58724
  return a.id - b.id;
58574
58725
  });
58575
58726
  const options = [];
58576
- for (const device of ordered) for (const capName of capsByDevice.get(device.id) ?? []) {
58577
- const cap = capsByName.get(capName);
58578
- if (cap === void 0) continue;
58579
- for (const leaf of stateLeavesOf(cap)) options.push({
58580
- deviceId: device.id,
58581
- deviceName: device.name,
58582
- capName,
58583
- valuePath: leaf.path,
58584
- label: `${humanizeCapName(capName)} · ${leaf.path}`,
58585
- valueType: leaf.valueType,
58586
- ...leaf.enumValues !== void 0 ? { enumValues: leaf.enumValues } : {}
58587
- });
58727
+ for (const device of ordered) {
58728
+ if (!isOsdLeafDeviceType(device.type ?? null)) continue;
58729
+ for (const capName of capsByDevice.get(device.id) ?? []) {
58730
+ if (!isOsdSourceCap(capName)) continue;
58731
+ const cap = capsByName.get(capName);
58732
+ if (cap === void 0) continue;
58733
+ for (const leaf of osdStateLeavesOf(cap)) options.push({
58734
+ deviceId: device.id,
58735
+ deviceName: device.name,
58736
+ capName,
58737
+ valuePath: leaf.path,
58738
+ label: `${humanizeCapName(capName)} · ${leaf.path}`,
58739
+ valueType: leaf.valueType,
58740
+ ...leaf.enumValues !== void 0 ? { enumValues: leaf.enumValues } : {}
58741
+ });
58742
+ }
58588
58743
  }
58589
58744
  return options;
58590
58745
  }
@@ -58980,7 +59135,7 @@ var OsdManager = class {
58980
59135
  if (stored === void 0) throw new Error(`osd-manager: template "${template.id}" missing after upsert`);
58981
59136
  this.logger.info("osd-manager: named template upserted", { meta: {
58982
59137
  templateId: stored.id,
58983
- fieldCount: stored.fields.length
59138
+ bindingCount: stored.bindings.length
58984
59139
  } });
58985
59140
  return { template: stored };
58986
59141
  };
@@ -59068,7 +59223,7 @@ var OsdManager = class {
59068
59223
  const templatesById = /* @__PURE__ */ new Map();
59069
59224
  for (const named of allTemplates) {
59070
59225
  templatesById.set(named.id, named);
59071
- if (templateIds.has(named.id)) for (const field of named.fields) wanted.add(field.deviceId);
59226
+ if (templateIds.has(named.id)) for (const binding of named.bindings) wanted.add(binding.pick.deviceId);
59072
59227
  }
59073
59228
  const stateByDevice = /* @__PURE__ */ new Map();
59074
59229
  const gateState = /* @__PURE__ */ new Map();
@@ -59270,7 +59425,8 @@ var OsdManagerAddon = class extends BaseAddon {
59270
59425
  listDevices: async () => {
59271
59426
  return (await ctx.api.deviceManager.listAll.query({ projection: "slim" })).map((d) => ({
59272
59427
  id: d.id,
59273
- name: d.name
59428
+ name: d.name,
59429
+ type: d.type ?? null
59274
59430
  }));
59275
59431
  },
59276
59432
  listCameras: async () => {
@@ -59368,28 +59524,86 @@ var OsdManagerAddon = class extends BaseAddon {
59368
59524
  }
59369
59525
  };
59370
59526
  //#endregion
59527
+ //#region src/osd-picker-devices.ts
59528
+ /**
59529
+ * Devices offered to the OSD DevicePicker — containers INCLUDED so the
59530
+ * operator can pick a gateway, then an OSD-supported child.
59531
+ */
59532
+ function toOsdPickerDevices(devices) {
59533
+ return devices.map((d) => ({
59534
+ id: d.id,
59535
+ name: d.name,
59536
+ type: d.type ?? null,
59537
+ location: d.location ?? null,
59538
+ parentDeviceId: d.parentDeviceId ?? null
59539
+ }));
59540
+ }
59541
+ /** Children of a container that have at least one OSD catalog field. */
59542
+ function osdSupportedChildrenOf(containerId, devices, deviceIdsWithOsdFields) {
59543
+ return devices.filter((d) => d.parentDeviceId === containerId && isOsdLeafDeviceType(d.type) && deviceIdsWithOsdFields.has(d.id)).toSorted((a, b) => a.name.localeCompare(b.name));
59544
+ }
59545
+ function deviceById(devices, id) {
59546
+ return devices.find((d) => d.id === id);
59547
+ }
59548
+ //#endregion
59549
+ //#region src/template-id.ts
59550
+ /**
59551
+ * Named-template ids are system-generated — never an operator text field.
59552
+ * Create uses a uuid; the editable surface is the template name.
59553
+ */
59554
+ function generateTemplateId() {
59555
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
59556
+ return `tpl-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
59557
+ }
59558
+ /** Optional slug helper when a stable short id from the name is preferred. */
59559
+ function templateIdFromName(name) {
59560
+ const slug = name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
59561
+ return `${slug.length > 0 ? slug : "template"}-${Date.now().toString(36)}`;
59562
+ }
59563
+ //#endregion
59371
59564
  exports.DEFAULT_TICK_MS = DEFAULT_TICK_MS;
59372
59565
  exports.EMPTY_BINDINGS = EMPTY_BINDINGS;
59373
59566
  exports.OSD_BINDINGS_KEY = OSD_BINDINGS_KEY;
59567
+ exports.OSD_NON_LEAF_TYPES = OSD_NON_LEAF_TYPES;
59568
+ exports.OSD_PICKER_EXCLUDED_TYPES = OSD_PICKER_EXCLUDED_TYPES;
59569
+ exports.OSD_SOURCE_CAP_NAMES = OSD_SOURCE_CAP_NAMES;
59374
59570
  exports.OSD_SUPPORTED_CONDITIONS = OSD_SUPPORTED_CONDITIONS;
59375
59571
  exports.OsdBindingsStore = OsdBindingsStore;
59376
59572
  exports.OsdDeviceBindingsSchema = OsdDeviceBindingsSchema;
59377
59573
  exports.OsdManager = OsdManager;
59378
59574
  exports.OsdManagerAddon = OsdManagerAddon;
59575
+ exports.aliasToken = aliasToken;
59379
59576
  exports.applyTemplate = applyTemplate;
59577
+ exports.applyTemplateFormat = applyTemplateFormat;
59380
59578
  exports.assertSupportedConditions = assertSupportedConditions;
59579
+ exports.bindingToken = bindingToken;
59381
59580
  exports.default = OsdManagerAddon;
59581
+ exports.deviceById = deviceById;
59382
59582
  exports.displayValue = displayValue;
59383
59583
  exports.evaluateGate = evaluateGate;
59384
59584
  exports.formatClock = formatClock;
59385
59585
  exports.formatSlotText = formatSlotText;
59586
+ exports.generateTemplateId = generateTemplateId;
59386
59587
  exports.humanizeCapName = humanizeCapName;
59588
+ exports.isContainerDeviceType = isContainerDeviceType;
59589
+ exports.isOsdLeafDeviceType = isOsdLeafDeviceType;
59590
+ exports.isOsdPickerDeviceType = isOsdPickerDeviceType;
59591
+ exports.isOsdSourceCap = isOsdSourceCap;
59387
59592
  exports.limitText = limitText;
59593
+ exports.osdStateLeavesOf = osdStateLeavesOf;
59594
+ exports.osdSupportedChildrenOf = osdSupportedChildrenOf;
59595
+ exports.parseAliasTokens = parseAliasTokens;
59388
59596
  exports.readStatePath = readStatePath;
59597
+ exports.renderNamedTemplate = renderNamedTemplate;
59389
59598
  exports.renderSlot = renderSlot;
59599
+ exports.replaceToken = replaceToken;
59600
+ exports.resolveBindingLive = resolveBindingLive;
59390
59601
  exports.resolveSource = resolveSource;
59391
59602
  exports.sourceOptionsFor = sourceOptionsFor;
59392
59603
  exports.stateLeavesOf = stateLeavesOf;
59604
+ exports.suggestAlias = suggestAlias;
59605
+ exports.templateIdFromName = templateIdFromName;
59606
+ exports.toOsdPickerDevices = toOsdPickerDevices;
59393
59607
  exports.truncateDecimals = truncateDecimals;
59394
59608
  exports.unsupportedConditionKeys = unsupportedConditionKeys;
59395
59609
  exports.withBinding = withBinding;