@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.
- package/dist/{MotionZonesSettings-vYt4dibj.mjs → MotionZonesSettings-gJgHYJJc.mjs} +2 -2
- package/dist/{PrivacyMaskSettings-BiQ78hst.mjs → PrivacyMaskSettings-HmUc5RFn.mjs} +4 -4
- package/dist/{SceneMonitorEditor-CJtJIyMf.mjs → SceneMonitorEditor-Dqc4eAZT.mjs} +3 -3
- package/dist/_stub.js +3065 -2707
- 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
- 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
- package/dist/{hostInit-0Mc7Fm1R.mjs → hostInit-o9ggbWOT.mjs} +1 -1
- package/dist/index.js +260 -46
- package/dist/index.mjs +240 -47
- package/dist/{player-overlays-BPyna-eI.mjs → player-overlays-BgDqoYs3.mjs} +1 -1
- package/dist/remoteEntry.js +1 -1
- package/dist/{responsive-B0yDP9vf.mjs → responsive-B7zCyVCX.mjs} +1 -1
- package/dist/{scene-monitor-copy-BzX20O6q.mjs → scene-monitor-copy-DWIcj1X6.mjs} +1 -1
- package/dist/{square-BOMOn_6j.mjs → square-D0YQUHMC.mjs} +1 -1
- package/dist/{trash-2-BolGRl2P.mjs → trash-2-C_1H5SIl.mjs} +1 -1
- 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
- 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
|
-
/**
|
|
39348
|
-
var
|
|
39349
|
-
|
|
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:
|
|
39358
|
-
* `{
|
|
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
|
-
|
|
39364
|
-
/** Parser with
|
|
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
|
|
58372
|
-
function
|
|
58373
|
-
return `{${
|
|
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.
|
|
58438
|
-
for (const
|
|
58439
|
-
const
|
|
58440
|
-
|
|
58441
|
-
|
|
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
|
|
58556
|
-
*
|
|
58557
|
-
*
|
|
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
|
|
58565
|
-
* first — that is what an operator reaches for, and a picker that
|
|
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)
|
|
58577
|
-
|
|
58578
|
-
|
|
58579
|
-
|
|
58580
|
-
|
|
58581
|
-
|
|
58582
|
-
|
|
58583
|
-
|
|
58584
|
-
|
|
58585
|
-
|
|
58586
|
-
|
|
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
|
-
|
|
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
|
|
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;
|