@camstack/types 1.2.446 → 1.2.448
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/CHANGELOG.md +14 -0
- package/dist/addon.js +3 -2
- package/dist/addon.mjs +3 -2
- package/dist/automation/action.d.ts +2 -0
- package/dist/automation/index.d.ts +3 -1
- package/dist/automation/normalize-units.d.ts +59 -0
- package/dist/automation/recipe.d.ts +15 -1
- package/dist/capabilities/action-source.cap.d.ts +1 -0
- package/dist/capabilities/actions.cap.d.ts +32 -1
- package/dist/capabilities/core-blocks.cap.d.ts +17 -0
- package/dist/capabilities/index.d.ts +3 -1
- package/dist/capabilities/remote-layout-components.cap.d.ts +81 -0
- package/dist/capabilities/remote.cap.d.ts +2 -0
- package/dist/client.js +1 -2
- package/dist/client.mjs +1 -2
- package/dist/device/cap-vocabulary/types.d.ts +9 -1
- package/dist/generated/addon-api.d.ts +15 -0
- package/dist/generated/capability-router-map.d.ts +5 -2
- package/dist/generated/collection-array-methods.d.ts +1 -1
- package/dist/generated/method-access-map.d.ts +1 -1
- package/dist/generated/system-proxy.d.ts +2 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +1786 -733
- package/dist/index.mjs +1750 -734
- package/dist/interfaces/event-bus.d.ts +9 -0
- package/dist/remote/remote-builtin-components.d.ts +15 -0
- package/dist/remote/remote-components.d.ts +109 -0
- package/dist/remote/remote-config.d.ts +121 -0
- package/dist/remote/remote-layout-ops.d.ts +68 -0
- package/dist/{sleep-6eG9C8Xl.mjs → sleep-63gM_1JR.mjs} +1 -0
- package/dist/{sleep-UXDHn-oJ.js → sleep-BSPhInRm.js} +1 -0
- package/dist/units/index.d.ts +3 -0
- package/dist/units/quantity-input.d.ts +58 -0
- package/dist/units/quantity-units.d.ts +8 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_sleep = require("./sleep-
|
|
2
|
+
const require_sleep = require("./sleep-BSPhInRm.js");
|
|
3
3
|
const require_event_category = require("./event-category-E17zaHjN.js");
|
|
4
4
|
const require_composition = require("./composition-CO6Sak-s.js");
|
|
5
5
|
const require_node_color = require("./node-color.js");
|
|
@@ -8060,6 +8060,791 @@ var ExpressionSourceSchema = zod.z.object({
|
|
|
8060
8060
|
});
|
|
8061
8061
|
});
|
|
8062
8062
|
//#endregion
|
|
8063
|
+
//#region src/device/schema-fields.ts
|
|
8064
|
+
/** Unwrap ZodNullable / ZodOptional / ZodDefault wrappers to reach the inner type.
|
|
8065
|
+
* Zod v4 exposes `.unwrap()` on all three wrapper classes. */
|
|
8066
|
+
function unwrapSchema(schema) {
|
|
8067
|
+
let s = schema;
|
|
8068
|
+
while (s instanceof zod.z.ZodNullable || s instanceof zod.z.ZodOptional || s instanceof zod.z.ZodDefault) s = s.unwrap();
|
|
8069
|
+
return s;
|
|
8070
|
+
}
|
|
8071
|
+
function isMetaBag(value) {
|
|
8072
|
+
return typeof value === "object" && value !== null;
|
|
8073
|
+
}
|
|
8074
|
+
function metaQuantity(schema) {
|
|
8075
|
+
const bag = zod.z.globalRegistry.get(schema);
|
|
8076
|
+
if (isMetaBag(bag) && require_sleep.isReadingQuantity(bag.quantity)) return bag.quantity;
|
|
8077
|
+
}
|
|
8078
|
+
/** Quantity declared with `readingMeta` on the field or on the unwrapped leaf. */
|
|
8079
|
+
function quantityOfField(schema) {
|
|
8080
|
+
return metaQuantity(schema) ?? metaQuantity(unwrapSchema(schema));
|
|
8081
|
+
}
|
|
8082
|
+
function leafKind(schema) {
|
|
8083
|
+
const s = unwrapSchema(schema);
|
|
8084
|
+
if (s instanceof zod.z.ZodEnum) return {
|
|
8085
|
+
kind: "enum",
|
|
8086
|
+
enumValues: s.options
|
|
8087
|
+
};
|
|
8088
|
+
if (s instanceof zod.z.ZodNumber) return { kind: "number" };
|
|
8089
|
+
if (s instanceof zod.z.ZodString) return { kind: "string" };
|
|
8090
|
+
if (s instanceof zod.z.ZodBoolean) return { kind: "boolean" };
|
|
8091
|
+
return null;
|
|
8092
|
+
}
|
|
8093
|
+
/** Walk a cap status schema into flat wireable leaf fields (dotted paths).
|
|
8094
|
+
* Recurses into nested ZodObject (unwrapping nullable/optional/default first),
|
|
8095
|
+
* so fields with null live values are still offered. Arrays / unknown shapes
|
|
8096
|
+
* are skipped — never throws. */
|
|
8097
|
+
function enumerateSchemaFields(schema, prefix = "") {
|
|
8098
|
+
const root = unwrapSchema(schema);
|
|
8099
|
+
if (!(root instanceof zod.z.ZodObject)) return [];
|
|
8100
|
+
const out = [];
|
|
8101
|
+
const shape = root.shape;
|
|
8102
|
+
for (const [key, field] of Object.entries(shape)) {
|
|
8103
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
8104
|
+
const inner = unwrapSchema(field);
|
|
8105
|
+
if (inner instanceof zod.z.ZodObject) {
|
|
8106
|
+
out.push(...enumerateSchemaFields(inner, path));
|
|
8107
|
+
continue;
|
|
8108
|
+
}
|
|
8109
|
+
const leaf = leafKind(field);
|
|
8110
|
+
if (leaf) {
|
|
8111
|
+
const quantity = quantityOfField(field);
|
|
8112
|
+
out.push({
|
|
8113
|
+
path,
|
|
8114
|
+
kind: leaf.kind,
|
|
8115
|
+
...leaf.enumValues ? { enumValues: leaf.enumValues } : {},
|
|
8116
|
+
...quantity !== void 0 ? { quantity } : {}
|
|
8117
|
+
});
|
|
8118
|
+
}
|
|
8119
|
+
}
|
|
8120
|
+
return out;
|
|
8121
|
+
}
|
|
8122
|
+
/** Enumerate the per-item wireable fields of an item-array cap (see
|
|
8123
|
+
* `CapabilityStatusItemArray`): the item schema's leaf fields, minus the
|
|
8124
|
+
* `keyField` (the key comes from the link's `itemKey`, never from a wired
|
|
8125
|
+
* source), each tagged `item: true` so the authoring UI collects an
|
|
8126
|
+
* `itemKey` alongside the field. Never throws. */
|
|
8127
|
+
function enumerateItemArrayFields(itemArray) {
|
|
8128
|
+
return enumerateSchemaFields(itemArray.itemSchema).filter((f) => f.path !== itemArray.keyField).map((f) => ({
|
|
8129
|
+
...f,
|
|
8130
|
+
item: true
|
|
8131
|
+
}));
|
|
8132
|
+
}
|
|
8133
|
+
//#endregion
|
|
8134
|
+
//#region src/device/source-info.ts
|
|
8135
|
+
/**
|
|
8136
|
+
* Identity envelope for a device's upstream-system metadata.
|
|
8137
|
+
*
|
|
8138
|
+
* Two jobs:
|
|
8139
|
+
*
|
|
8140
|
+
* 1. **Dispatch key.** `id` is the natural identifier the SOURCE system
|
|
8141
|
+
* uses to address this device (HA `entity_id`, Reolink MAC, ONVIF
|
|
8142
|
+
* WS-Discovery endpoint UUID, …). Provider code keeps a
|
|
8143
|
+
* `Map<sourceInfo.id, IDevice>` to route inbound push events in O(1)
|
|
8144
|
+
* without round-tripping through `stableId` / `id` mappings.
|
|
8145
|
+
*
|
|
8146
|
+
* 2. **Stability bridge.** `uniqueId` is the *immutable* upstream id when
|
|
8147
|
+
* one exists (HA `entity.unique_id`, Reolink MAC again — same as `id`
|
|
8148
|
+
* for vendors where MAC is the natural key). For systems where the
|
|
8149
|
+
* live dispatch key can be renamed (HA `entity_id` can be edited),
|
|
8150
|
+
* providers detect renames by matching `uniqueId` and patch `id`
|
|
8151
|
+
* in-place so dispatch keeps working.
|
|
8152
|
+
*
|
|
8153
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
8154
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
8155
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
8156
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
8157
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
8158
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
8159
|
+
*
|
|
8160
|
+
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
8161
|
+
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
8162
|
+
* details, …). Providers control what lands here.
|
|
8163
|
+
*/
|
|
8164
|
+
var SourceInfoSchema = zod.z.object({
|
|
8165
|
+
/** Live dispatch key — mutable when the source system allows rename. */
|
|
8166
|
+
id: zod.z.string(),
|
|
8167
|
+
/** Source system tag — e.g. 'homeassistant' | 'reolink' | 'onvif'. */
|
|
8168
|
+
system: zod.z.string(),
|
|
8169
|
+
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
8170
|
+
* Used to detect rename when `id` changes. */
|
|
8171
|
+
uniqueId: zod.z.string().optional(),
|
|
8172
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
8173
|
+
quantity: require_sleep.ReadingQuantitySchema.optional(),
|
|
8174
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
8175
|
+
dateTimeShape: zod.z.enum([
|
|
8176
|
+
"date",
|
|
8177
|
+
"time",
|
|
8178
|
+
"datetime"
|
|
8179
|
+
]).optional(),
|
|
8180
|
+
/** Provider-specific extras that don't fit the structured slots.
|
|
8181
|
+
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
8182
|
+
* attribute blobs (would explode the meta JSON column). */
|
|
8183
|
+
raw: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
|
|
8184
|
+
});
|
|
8185
|
+
/**
|
|
8186
|
+
* Build the synthetic SourceInfo every existing provider falls back to
|
|
8187
|
+
* when no upstream value has been persisted. Keeps non-migrated providers
|
|
8188
|
+
* (Reolink / Hikvision / ONVIF / RTSP) functional without code
|
|
8189
|
+
* changes — `id` reuses the CamStack stableId, `system` reuses the addon
|
|
8190
|
+
* id. Real upstream identity replaces this once a provider migrates and
|
|
8191
|
+
* calls `updateSourceInfo()` with concrete values.
|
|
8192
|
+
*/
|
|
8193
|
+
function synthesizeSourceInfo(input) {
|
|
8194
|
+
return {
|
|
8195
|
+
id: input.stableId,
|
|
8196
|
+
system: input.addonId
|
|
8197
|
+
};
|
|
8198
|
+
}
|
|
8199
|
+
/**
|
|
8200
|
+
* Shallow-merge a partial patch over a prior SourceInfo. `undefined`
|
|
8201
|
+
* patch values are ignored (no field clobber); to clear a field
|
|
8202
|
+
* explicitly, providers omit it from the patch and rebuild from scratch
|
|
8203
|
+
* via `updateSourceInfo({})` cycles — uncommon enough that we don't
|
|
8204
|
+
* bother with a `null`-means-delete sentinel.
|
|
8205
|
+
*
|
|
8206
|
+
* The `raw` field is also shallow-merged: passing `raw: { foo: 1 }`
|
|
8207
|
+
* merges over existing `raw` keys instead of replacing the whole bag.
|
|
8208
|
+
*/
|
|
8209
|
+
function mergeSourceInfo(prev, patch) {
|
|
8210
|
+
const next = { ...prev };
|
|
8211
|
+
for (const [k, v] of Object.entries(patch)) {
|
|
8212
|
+
if (v === void 0) continue;
|
|
8213
|
+
if (k === "raw" && typeof v === "object" && v !== null) {
|
|
8214
|
+
next.raw = {
|
|
8215
|
+
...prev.raw,
|
|
8216
|
+
...v
|
|
8217
|
+
};
|
|
8218
|
+
continue;
|
|
8219
|
+
}
|
|
8220
|
+
next[k] = v;
|
|
8221
|
+
}
|
|
8222
|
+
return next;
|
|
8223
|
+
}
|
|
8224
|
+
/**
|
|
8225
|
+
* Coerce common unit-of-measurement string variants to a canonical form
|
|
8226
|
+
* so the UI's display templates can rely on stable strings. Pure
|
|
8227
|
+
* passthrough for unknown units — kept conservative on purpose, the goal
|
|
8228
|
+
* is to normalise the long tail of HA `unit_of_measurement` values that
|
|
8229
|
+
* have multiple historical spellings (`'°C'` vs `'C'` vs `'celsius'`).
|
|
8230
|
+
*
|
|
8231
|
+
* Extend the map as we encounter real-world data. Returning the raw
|
|
8232
|
+
* input for unknown values is intentional: providers should never
|
|
8233
|
+
* lose information silently here.
|
|
8234
|
+
*/
|
|
8235
|
+
function normalizeUnit(raw) {
|
|
8236
|
+
if (raw == null) return void 0;
|
|
8237
|
+
const trimmed = raw.trim();
|
|
8238
|
+
if (trimmed === "") return void 0;
|
|
8239
|
+
const lower = trimmed.toLowerCase();
|
|
8240
|
+
if (lower === "°c" || lower === "c" || lower === "celsius") return "°C";
|
|
8241
|
+
if (lower === "°f" || lower === "f" || lower === "fahrenheit") return "°F";
|
|
8242
|
+
if (lower === "k" || lower === "kelvin") return "K";
|
|
8243
|
+
if (lower === "%" || lower === "percent" || lower === "percentage") return "%";
|
|
8244
|
+
if (lower === "lx" || lower === "lux") return "lx";
|
|
8245
|
+
if (lower === "hpa" || lower === "hectopascal") return "hPa";
|
|
8246
|
+
if (lower === "kpa") return "kPa";
|
|
8247
|
+
if (lower === "pa") return "Pa";
|
|
8248
|
+
if (lower === "mbar" || lower === "millibar") return "mbar";
|
|
8249
|
+
if (lower === "w" || lower === "watt") return "W";
|
|
8250
|
+
if (lower === "kw" || lower === "kilowatt") return "kW";
|
|
8251
|
+
if (lower === "wh" || lower === "watt-hour") return "Wh";
|
|
8252
|
+
if (lower === "kwh" || lower === "kilowatt-hour") return "kWh";
|
|
8253
|
+
if (lower === "v" || lower === "volt") return "V";
|
|
8254
|
+
if (lower === "a" || lower === "amp" || lower === "ampere") return "A";
|
|
8255
|
+
if (lower === "ma" || lower === "milliampere") return "mA";
|
|
8256
|
+
if (lower === "va") return "VA";
|
|
8257
|
+
if (lower === "ppm") return "ppm";
|
|
8258
|
+
if (lower === "ppb") return "ppb";
|
|
8259
|
+
if (lower === "µg/m³" || lower === "ug/m3" || lower === "µg/m3") return "µg/m³";
|
|
8260
|
+
if (lower === "km/h" || lower === "kph") return "km/h";
|
|
8261
|
+
if (lower === "mph") return "mph";
|
|
8262
|
+
if (lower === "m/s") return "m/s";
|
|
8263
|
+
if (lower === "m") return "m";
|
|
8264
|
+
if (lower === "m²" || lower === "m2") return "m²";
|
|
8265
|
+
if (lower === "mm") return "mm";
|
|
8266
|
+
if (lower === "cm") return "cm";
|
|
8267
|
+
if (lower === "km") return "km";
|
|
8268
|
+
if (lower === "in" || lower === "inch" || lower === "inches") return "in";
|
|
8269
|
+
if (lower === "ft" || lower === "foot" || lower === "feet") return "ft";
|
|
8270
|
+
if (lower === "kg") return "kg";
|
|
8271
|
+
if (lower === "g") return "g";
|
|
8272
|
+
if (lower === "l" || lower === "liter" || lower === "litre" || lower === "liters" || lower === "litres") return "L";
|
|
8273
|
+
if (lower === "ml") return "mL";
|
|
8274
|
+
if (lower === "gal" || lower === "gallon" || lower === "gallons") return "gal";
|
|
8275
|
+
if (lower === "s" || lower === "sec" || lower === "second" || lower === "seconds") return "s";
|
|
8276
|
+
if (lower === "ms") return "ms";
|
|
8277
|
+
if (lower === "min" || lower === "minute" || lower === "minutes") return "min";
|
|
8278
|
+
if (lower === "h" || lower === "hr" || lower === "hour" || lower === "hours") return "h";
|
|
8279
|
+
if (lower === "d" || lower === "day" || lower === "days") return "d";
|
|
8280
|
+
if (lower === "b" || lower === "byte" || lower === "bytes") return "B";
|
|
8281
|
+
if (lower === "kib") return "KiB";
|
|
8282
|
+
if (lower === "mib") return "MiB";
|
|
8283
|
+
if (lower === "gib") return "GiB";
|
|
8284
|
+
if (lower === "tib") return "TiB";
|
|
8285
|
+
if (lower === "kb") return "kB";
|
|
8286
|
+
if (lower === "mb") return "MB";
|
|
8287
|
+
if (lower === "gb") return "GB";
|
|
8288
|
+
if (lower === "dbm") return "dBm";
|
|
8289
|
+
if (lower === "dbfs") return "dBFS";
|
|
8290
|
+
if (lower === "inhg") return "inHg";
|
|
8291
|
+
if (lower === "mm/h") return "mm/h";
|
|
8292
|
+
if (lower === "w/m²" || lower === "w/m2") return "W/m²";
|
|
8293
|
+
if (lower === "°" || lower === "deg" || lower === "degree" || lower === "degrees") return "°";
|
|
8294
|
+
if (lower === "kbps") return "kbps";
|
|
8295
|
+
if (lower === "fps") return "fps";
|
|
8296
|
+
return trimmed;
|
|
8297
|
+
}
|
|
8298
|
+
/**
|
|
8299
|
+
* Key under which `SourceInfo` lives inside `DeviceMeta.metadata`. The
|
|
8300
|
+
* blob is a free-form `Record<string, unknown>` shared with hardware-
|
|
8301
|
+
* identity fields (`manufacturer`, `model`, `firmware`, …); SourceInfo
|
|
8302
|
+
* lives under a single nested key to keep it composable with those.
|
|
8303
|
+
*/
|
|
8304
|
+
var SOURCE_INFO_METADATA_KEY = "sourceInfo";
|
|
8305
|
+
/**
|
|
8306
|
+
* Extract a SourceInfo from a `DeviceMeta.metadata` blob, validating
|
|
8307
|
+
* with Zod. Returns `null` when the blob is missing or the nested
|
|
8308
|
+
* `sourceInfo` key fails validation — callers fall back to the
|
|
8309
|
+
* synthetic default in that case (see `synthesizeSourceInfo`).
|
|
8310
|
+
*/
|
|
8311
|
+
function extractSourceInfoFromMetadata(metadata) {
|
|
8312
|
+
if (!metadata) return null;
|
|
8313
|
+
const raw = metadata[SOURCE_INFO_METADATA_KEY];
|
|
8314
|
+
if (!raw) return null;
|
|
8315
|
+
const parsed = SourceInfoSchema.safeParse(raw);
|
|
8316
|
+
if (!parsed.success) return null;
|
|
8317
|
+
return parsed.data;
|
|
8318
|
+
}
|
|
8319
|
+
//#endregion
|
|
8320
|
+
//#region src/units/unit-table.ts
|
|
8321
|
+
/**
|
|
8322
|
+
* Frozen unit → spec table. `•` in the doc marks each dimension's canonical
|
|
8323
|
+
* unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
|
|
8324
|
+
* `factor = 5/9`, `offset = -160/9` (kept as exact expressions, not rounded
|
|
8325
|
+
* decimals). K derives from `°C = K − 273.15`.
|
|
8326
|
+
*/
|
|
8327
|
+
var UNIT_TABLE = {
|
|
8328
|
+
"°C": {
|
|
8329
|
+
dimension: "temperature",
|
|
8330
|
+
factor: 1,
|
|
8331
|
+
offset: 0
|
|
8332
|
+
},
|
|
8333
|
+
"°F": {
|
|
8334
|
+
dimension: "temperature",
|
|
8335
|
+
factor: 5 / 9,
|
|
8336
|
+
offset: -160 / 9
|
|
8337
|
+
},
|
|
8338
|
+
K: {
|
|
8339
|
+
dimension: "temperature",
|
|
8340
|
+
factor: 1,
|
|
8341
|
+
offset: -273.15
|
|
8342
|
+
},
|
|
8343
|
+
hPa: {
|
|
8344
|
+
dimension: "pressure",
|
|
8345
|
+
factor: 1,
|
|
8346
|
+
offset: 0
|
|
8347
|
+
},
|
|
8348
|
+
kPa: {
|
|
8349
|
+
dimension: "pressure",
|
|
8350
|
+
factor: 10,
|
|
8351
|
+
offset: 0
|
|
8352
|
+
},
|
|
8353
|
+
Pa: {
|
|
8354
|
+
dimension: "pressure",
|
|
8355
|
+
factor: .01,
|
|
8356
|
+
offset: 0
|
|
8357
|
+
},
|
|
8358
|
+
mbar: {
|
|
8359
|
+
dimension: "pressure",
|
|
8360
|
+
factor: 1,
|
|
8361
|
+
offset: 0
|
|
8362
|
+
},
|
|
8363
|
+
bar: {
|
|
8364
|
+
dimension: "pressure",
|
|
8365
|
+
factor: 1e3,
|
|
8366
|
+
offset: 0
|
|
8367
|
+
},
|
|
8368
|
+
inHg: {
|
|
8369
|
+
dimension: "pressure",
|
|
8370
|
+
factor: 33.8639,
|
|
8371
|
+
offset: 0
|
|
8372
|
+
},
|
|
8373
|
+
mmHg: {
|
|
8374
|
+
dimension: "pressure",
|
|
8375
|
+
factor: 1.33322,
|
|
8376
|
+
offset: 0
|
|
8377
|
+
},
|
|
8378
|
+
psi: {
|
|
8379
|
+
dimension: "pressure",
|
|
8380
|
+
factor: 68.9476,
|
|
8381
|
+
offset: 0
|
|
8382
|
+
},
|
|
8383
|
+
"m/s": {
|
|
8384
|
+
dimension: "speed",
|
|
8385
|
+
factor: 1,
|
|
8386
|
+
offset: 0
|
|
8387
|
+
},
|
|
8388
|
+
"km/h": {
|
|
8389
|
+
dimension: "speed",
|
|
8390
|
+
factor: 1 / 3.6,
|
|
8391
|
+
offset: 0
|
|
8392
|
+
},
|
|
8393
|
+
mph: {
|
|
8394
|
+
dimension: "speed",
|
|
8395
|
+
factor: .44704,
|
|
8396
|
+
offset: 0
|
|
8397
|
+
},
|
|
8398
|
+
kn: {
|
|
8399
|
+
dimension: "speed",
|
|
8400
|
+
factor: .514444,
|
|
8401
|
+
offset: 0
|
|
8402
|
+
},
|
|
8403
|
+
"mm/h": {
|
|
8404
|
+
dimension: "precipitation-rate",
|
|
8405
|
+
factor: 1,
|
|
8406
|
+
offset: 0
|
|
8407
|
+
},
|
|
8408
|
+
"in/h": {
|
|
8409
|
+
dimension: "precipitation-rate",
|
|
8410
|
+
factor: 25.4,
|
|
8411
|
+
offset: 0
|
|
8412
|
+
},
|
|
8413
|
+
m: {
|
|
8414
|
+
dimension: "length",
|
|
8415
|
+
factor: 1,
|
|
8416
|
+
offset: 0
|
|
8417
|
+
},
|
|
8418
|
+
mm: {
|
|
8419
|
+
dimension: "length",
|
|
8420
|
+
factor: .001,
|
|
8421
|
+
offset: 0
|
|
8422
|
+
},
|
|
8423
|
+
cm: {
|
|
8424
|
+
dimension: "length",
|
|
8425
|
+
factor: .01,
|
|
8426
|
+
offset: 0
|
|
8427
|
+
},
|
|
8428
|
+
km: {
|
|
8429
|
+
dimension: "length",
|
|
8430
|
+
factor: 1e3,
|
|
8431
|
+
offset: 0
|
|
8432
|
+
},
|
|
8433
|
+
in: {
|
|
8434
|
+
dimension: "length",
|
|
8435
|
+
factor: .0254,
|
|
8436
|
+
offset: 0
|
|
8437
|
+
},
|
|
8438
|
+
ft: {
|
|
8439
|
+
dimension: "length",
|
|
8440
|
+
factor: .3048,
|
|
8441
|
+
offset: 0
|
|
8442
|
+
},
|
|
8443
|
+
mi: {
|
|
8444
|
+
dimension: "length",
|
|
8445
|
+
factor: 1609.344,
|
|
8446
|
+
offset: 0
|
|
8447
|
+
},
|
|
8448
|
+
"m²": {
|
|
8449
|
+
dimension: "area",
|
|
8450
|
+
factor: 1,
|
|
8451
|
+
offset: 0
|
|
8452
|
+
},
|
|
8453
|
+
lx: {
|
|
8454
|
+
dimension: "illuminance",
|
|
8455
|
+
factor: 1,
|
|
8456
|
+
offset: 0
|
|
8457
|
+
},
|
|
8458
|
+
"W/m²": {
|
|
8459
|
+
dimension: "irradiance",
|
|
8460
|
+
factor: 1,
|
|
8461
|
+
offset: 0
|
|
8462
|
+
},
|
|
8463
|
+
W: {
|
|
8464
|
+
dimension: "power",
|
|
8465
|
+
factor: 1,
|
|
8466
|
+
offset: 0
|
|
8467
|
+
},
|
|
8468
|
+
kW: {
|
|
8469
|
+
dimension: "power",
|
|
8470
|
+
factor: 1e3,
|
|
8471
|
+
offset: 0
|
|
8472
|
+
},
|
|
8473
|
+
VA: {
|
|
8474
|
+
dimension: "apparent-power",
|
|
8475
|
+
factor: 1,
|
|
8476
|
+
offset: 0
|
|
8477
|
+
},
|
|
8478
|
+
Wh: {
|
|
8479
|
+
dimension: "energy",
|
|
8480
|
+
factor: 1,
|
|
8481
|
+
offset: 0
|
|
8482
|
+
},
|
|
8483
|
+
kWh: {
|
|
8484
|
+
dimension: "energy",
|
|
8485
|
+
factor: 1e3,
|
|
8486
|
+
offset: 0
|
|
8487
|
+
},
|
|
8488
|
+
MWh: {
|
|
8489
|
+
dimension: "energy",
|
|
8490
|
+
factor: 1e6,
|
|
8491
|
+
offset: 0
|
|
8492
|
+
},
|
|
8493
|
+
V: {
|
|
8494
|
+
dimension: "voltage",
|
|
8495
|
+
factor: 1,
|
|
8496
|
+
offset: 0
|
|
8497
|
+
},
|
|
8498
|
+
mV: {
|
|
8499
|
+
dimension: "voltage",
|
|
8500
|
+
factor: .001,
|
|
8501
|
+
offset: 0
|
|
8502
|
+
},
|
|
8503
|
+
A: {
|
|
8504
|
+
dimension: "current",
|
|
8505
|
+
factor: 1,
|
|
8506
|
+
offset: 0
|
|
8507
|
+
},
|
|
8508
|
+
mA: {
|
|
8509
|
+
dimension: "current",
|
|
8510
|
+
factor: .001,
|
|
8511
|
+
offset: 0
|
|
8512
|
+
},
|
|
8513
|
+
ppm: {
|
|
8514
|
+
dimension: "concentration-volume",
|
|
8515
|
+
factor: 1,
|
|
8516
|
+
offset: 0
|
|
8517
|
+
},
|
|
8518
|
+
ppb: {
|
|
8519
|
+
dimension: "concentration-volume",
|
|
8520
|
+
factor: .001,
|
|
8521
|
+
offset: 0
|
|
8522
|
+
},
|
|
8523
|
+
"µg/m³": {
|
|
8524
|
+
dimension: "concentration-mass",
|
|
8525
|
+
factor: 1,
|
|
8526
|
+
offset: 0
|
|
8527
|
+
},
|
|
8528
|
+
"mg/m³": {
|
|
8529
|
+
dimension: "concentration-mass",
|
|
8530
|
+
factor: 1e3,
|
|
8531
|
+
offset: 0
|
|
8532
|
+
},
|
|
8533
|
+
kg: {
|
|
8534
|
+
dimension: "mass",
|
|
8535
|
+
factor: 1,
|
|
8536
|
+
offset: 0
|
|
8537
|
+
},
|
|
8538
|
+
g: {
|
|
8539
|
+
dimension: "mass",
|
|
8540
|
+
factor: .001,
|
|
8541
|
+
offset: 0
|
|
8542
|
+
},
|
|
8543
|
+
lb: {
|
|
8544
|
+
dimension: "mass",
|
|
8545
|
+
factor: .453592,
|
|
8546
|
+
offset: 0
|
|
8547
|
+
},
|
|
8548
|
+
oz: {
|
|
8549
|
+
dimension: "mass",
|
|
8550
|
+
factor: .0283495,
|
|
8551
|
+
offset: 0
|
|
8552
|
+
},
|
|
8553
|
+
"%": {
|
|
8554
|
+
dimension: "percentage",
|
|
8555
|
+
factor: 1,
|
|
8556
|
+
offset: 0
|
|
8557
|
+
},
|
|
8558
|
+
L: {
|
|
8559
|
+
dimension: "volume",
|
|
8560
|
+
factor: 1,
|
|
8561
|
+
offset: 0
|
|
8562
|
+
},
|
|
8563
|
+
mL: {
|
|
8564
|
+
dimension: "volume",
|
|
8565
|
+
factor: .001,
|
|
8566
|
+
offset: 0
|
|
8567
|
+
},
|
|
8568
|
+
gal: {
|
|
8569
|
+
dimension: "volume",
|
|
8570
|
+
factor: 3.785411784,
|
|
8571
|
+
offset: 0
|
|
8572
|
+
},
|
|
8573
|
+
s: {
|
|
8574
|
+
dimension: "duration",
|
|
8575
|
+
factor: 1,
|
|
8576
|
+
offset: 0
|
|
8577
|
+
},
|
|
8578
|
+
ms: {
|
|
8579
|
+
dimension: "duration",
|
|
8580
|
+
factor: .001,
|
|
8581
|
+
offset: 0
|
|
8582
|
+
},
|
|
8583
|
+
min: {
|
|
8584
|
+
dimension: "duration",
|
|
8585
|
+
factor: 60,
|
|
8586
|
+
offset: 0
|
|
8587
|
+
},
|
|
8588
|
+
h: {
|
|
8589
|
+
dimension: "duration",
|
|
8590
|
+
factor: 3600,
|
|
8591
|
+
offset: 0
|
|
8592
|
+
},
|
|
8593
|
+
d: {
|
|
8594
|
+
dimension: "duration",
|
|
8595
|
+
factor: 86400,
|
|
8596
|
+
offset: 0
|
|
8597
|
+
},
|
|
8598
|
+
B: {
|
|
8599
|
+
dimension: "information",
|
|
8600
|
+
factor: 1,
|
|
8601
|
+
offset: 0
|
|
8602
|
+
},
|
|
8603
|
+
KiB: {
|
|
8604
|
+
dimension: "information",
|
|
8605
|
+
factor: 1024,
|
|
8606
|
+
offset: 0
|
|
8607
|
+
},
|
|
8608
|
+
MiB: {
|
|
8609
|
+
dimension: "information",
|
|
8610
|
+
factor: 1024 ** 2,
|
|
8611
|
+
offset: 0
|
|
8612
|
+
},
|
|
8613
|
+
GiB: {
|
|
8614
|
+
dimension: "information",
|
|
8615
|
+
factor: 1024 ** 3,
|
|
8616
|
+
offset: 0
|
|
8617
|
+
},
|
|
8618
|
+
TiB: {
|
|
8619
|
+
dimension: "information",
|
|
8620
|
+
factor: 1024 ** 4,
|
|
8621
|
+
offset: 0
|
|
8622
|
+
},
|
|
8623
|
+
kB: {
|
|
8624
|
+
dimension: "information",
|
|
8625
|
+
factor: 1e3,
|
|
8626
|
+
offset: 0
|
|
8627
|
+
},
|
|
8628
|
+
MB: {
|
|
8629
|
+
dimension: "information",
|
|
8630
|
+
factor: 1e6,
|
|
8631
|
+
offset: 0
|
|
8632
|
+
},
|
|
8633
|
+
GB: {
|
|
8634
|
+
dimension: "information",
|
|
8635
|
+
factor: 1e9,
|
|
8636
|
+
offset: 0
|
|
8637
|
+
},
|
|
8638
|
+
"°": {
|
|
8639
|
+
dimension: "angle",
|
|
8640
|
+
factor: 1,
|
|
8641
|
+
offset: 0
|
|
8642
|
+
},
|
|
8643
|
+
dBFS: {
|
|
8644
|
+
dimension: "sound-level",
|
|
8645
|
+
factor: 1,
|
|
8646
|
+
offset: 0
|
|
8647
|
+
},
|
|
8648
|
+
dBm: {
|
|
8649
|
+
dimension: "signal-level",
|
|
8650
|
+
factor: 1,
|
|
8651
|
+
offset: 0
|
|
8652
|
+
},
|
|
8653
|
+
mired: {
|
|
8654
|
+
dimension: "colour-temperature",
|
|
8655
|
+
factor: 1,
|
|
8656
|
+
offset: 0
|
|
8657
|
+
},
|
|
8658
|
+
kbps: {
|
|
8659
|
+
dimension: "bitrate",
|
|
8660
|
+
factor: 1,
|
|
8661
|
+
offset: 0
|
|
8662
|
+
},
|
|
8663
|
+
Mbps: {
|
|
8664
|
+
dimension: "bitrate",
|
|
8665
|
+
factor: 1e3,
|
|
8666
|
+
offset: 0
|
|
8667
|
+
},
|
|
8668
|
+
fps: {
|
|
8669
|
+
dimension: "rate",
|
|
8670
|
+
factor: 1,
|
|
8671
|
+
offset: 0
|
|
8672
|
+
}
|
|
8673
|
+
};
|
|
8674
|
+
//#endregion
|
|
8675
|
+
//#region src/units/convert.ts
|
|
8676
|
+
/**
|
|
8677
|
+
* Pure unit-conversion API over `UNIT_TABLE`. No dependencies, no side effects.
|
|
8678
|
+
*
|
|
8679
|
+
* Conversion is refused (throws `UnitConversionError`, or returns `undefined`
|
|
8680
|
+
* from the `try*` variant) whenever a unit is unknown or the two units belong
|
|
8681
|
+
* to different dimensions — cross-dimension conversion is deliberately
|
|
8682
|
+
* impossible so a render override can never make the value and its unit label
|
|
8683
|
+
* disagree.
|
|
8684
|
+
*
|
|
8685
|
+
* Callers pass units through `normalizeUnit` (`../device/source-info.ts`) BEFORE
|
|
8686
|
+
* calling here — the table keys only canonical spellings.
|
|
8687
|
+
*/
|
|
8688
|
+
/** Thrown by `convertUnit` when a conversion is refused. Carries the offending
|
|
8689
|
+
* units + a machine-readable `reason` for callers that branch on the cause. */
|
|
8690
|
+
var UnitConversionError = class extends Error {
|
|
8691
|
+
from;
|
|
8692
|
+
to;
|
|
8693
|
+
reason;
|
|
8694
|
+
constructor(from, to, reason) {
|
|
8695
|
+
super(`[units] cannot convert '${from}' → '${to}': ${reason}`);
|
|
8696
|
+
this.name = "UnitConversionError";
|
|
8697
|
+
this.from = from;
|
|
8698
|
+
this.to = to;
|
|
8699
|
+
this.reason = reason;
|
|
8700
|
+
}
|
|
8701
|
+
};
|
|
8702
|
+
/** Resolve a unit's `UnitSpec`, or `undefined` when the spelling is unknown. */
|
|
8703
|
+
function specFor(unit) {
|
|
8704
|
+
return Object.hasOwn(UNIT_TABLE, unit) ? UNIT_TABLE[unit] : void 0;
|
|
8705
|
+
}
|
|
8706
|
+
/** The dimension a unit belongs to, or `undefined` for an unknown unit. */
|
|
8707
|
+
function unitDimension(unit) {
|
|
8708
|
+
return specFor(unit)?.dimension;
|
|
8709
|
+
}
|
|
8710
|
+
/** Value in `spec`'s unit → its dimension's canonical unit. */
|
|
8711
|
+
function toCanonical(value, spec) {
|
|
8712
|
+
return value * spec.factor + spec.offset;
|
|
8713
|
+
}
|
|
8714
|
+
/** Canonical-unit value → the unit described by `spec`. */
|
|
8715
|
+
function fromCanonical(canonical, spec) {
|
|
8716
|
+
return (canonical - spec.offset) / spec.factor;
|
|
8717
|
+
}
|
|
8718
|
+
/**
|
|
8719
|
+
* Convert `value` from unit `from` to unit `to`. Identity when `from === to`.
|
|
8720
|
+
* Throws `UnitConversionError` when either unit is unknown or the units belong
|
|
8721
|
+
* to different dimensions.
|
|
8722
|
+
*/
|
|
8723
|
+
function convertUnit(value, from, to) {
|
|
8724
|
+
if (from === to) return value;
|
|
8725
|
+
const fromSpec = specFor(from);
|
|
8726
|
+
if (!fromSpec) throw new UnitConversionError(from, to, "unknown-from");
|
|
8727
|
+
const toSpec = specFor(to);
|
|
8728
|
+
if (!toSpec) throw new UnitConversionError(from, to, "unknown-to");
|
|
8729
|
+
if (fromSpec.dimension !== toSpec.dimension) throw new UnitConversionError(from, to, "cross-dimension");
|
|
8730
|
+
return fromCanonical(toCanonical(value, fromSpec), toSpec);
|
|
8731
|
+
}
|
|
8732
|
+
/**
|
|
8733
|
+
* Graceful variant for the render path: returns the converted value, or
|
|
8734
|
+
* `undefined` when the conversion is refused (unknown unit / cross-dimension).
|
|
8735
|
+
* Never throws — a render caller falls back to the raw value + source unit.
|
|
8736
|
+
*/
|
|
8737
|
+
function tryConvertUnit(value, from, to) {
|
|
8738
|
+
if (from === to) return value;
|
|
8739
|
+
const fromSpec = specFor(from);
|
|
8740
|
+
if (!fromSpec) return void 0;
|
|
8741
|
+
const toSpec = specFor(to);
|
|
8742
|
+
if (!toSpec) return void 0;
|
|
8743
|
+
if (fromSpec.dimension !== toSpec.dimension) return void 0;
|
|
8744
|
+
return fromCanonical(toCanonical(value, fromSpec), toSpec);
|
|
8745
|
+
}
|
|
8746
|
+
/**
|
|
8747
|
+
* Whether `value` can be converted between `from` and `to` (same dimension,
|
|
8748
|
+
* both known). Cheap boolean probe for the UI's same-dimension unit picker and
|
|
8749
|
+
* the resolver's convertibility branch — compute ONCE so a unit label and its
|
|
8750
|
+
* value math can never disagree.
|
|
8751
|
+
*/
|
|
8752
|
+
function canConvertUnit(from, to) {
|
|
8753
|
+
if (from === to) return true;
|
|
8754
|
+
const fromDim = unitDimension(from);
|
|
8755
|
+
if (fromDim === void 0) return false;
|
|
8756
|
+
return fromDim === unitDimension(to);
|
|
8757
|
+
}
|
|
8758
|
+
/**
|
|
8759
|
+
* Every known unit spelling in a dimension (table insertion order — canonical
|
|
8760
|
+
* unit first). Powers the UI's same-dimension unit picker.
|
|
8761
|
+
*/
|
|
8762
|
+
/**
|
|
8763
|
+
* Convert a difference, not a reading. Affine units (°F) shift an absolute
|
|
8764
|
+
* value by their offset; a step of 1°F is 5/9°C, so the offset is cancelled.
|
|
8765
|
+
*/
|
|
8766
|
+
function tryConvertDelta(value, from, to) {
|
|
8767
|
+
if (from === to) return value;
|
|
8768
|
+
const origin = tryConvertUnit(0, from, to);
|
|
8769
|
+
const shifted = tryConvertUnit(value, from, to);
|
|
8770
|
+
if (origin === void 0 || shifted === void 0) return void 0;
|
|
8771
|
+
return shifted - origin;
|
|
8772
|
+
}
|
|
8773
|
+
function unitsForDimension(dimension) {
|
|
8774
|
+
const out = [];
|
|
8775
|
+
for (const [unit, spec] of Object.entries(UNIT_TABLE)) if (spec.dimension === dimension) out.push(unit);
|
|
8776
|
+
return out;
|
|
8777
|
+
}
|
|
8778
|
+
//#endregion
|
|
8779
|
+
//#region src/units/quantity-input.ts
|
|
8780
|
+
/**
|
|
8781
|
+
* A number a person types for a physical quantity — the input side of the
|
|
8782
|
+
* value + unit contract (D972).
|
|
8783
|
+
*
|
|
8784
|
+
* Readings are stored in the base unit of their quantity (D944); a cap method
|
|
8785
|
+
* param is stored in the unit its input schema DECLARES (`paramMeta`). The
|
|
8786
|
+
* wire pair {@link QuantityValue} says "this number is expressed in this
|
|
8787
|
+
* unit"; {@link convertQuantityInput} brings it to the stored unit and refuses,
|
|
8788
|
+
* with a typed {@link QuantityUnitError}, a unit that cannot be that quantity.
|
|
8789
|
+
*/
|
|
8790
|
+
/** A unit that cannot be applied to the number it was given with. */
|
|
8791
|
+
var QuantityUnitError = class extends Error {
|
|
8792
|
+
code;
|
|
8793
|
+
constructor(code, message) {
|
|
8794
|
+
super(`[${code}] ${message}`);
|
|
8795
|
+
this.name = "QuantityUnitError";
|
|
8796
|
+
this.code = code;
|
|
8797
|
+
}
|
|
8798
|
+
};
|
|
8799
|
+
/** The wire pair: `value` is expressed in `unit`. */
|
|
8800
|
+
var QuantityValueSchema = zod.z.object({
|
|
8801
|
+
value: zod.z.number(),
|
|
8802
|
+
unit: zod.z.string().min(1)
|
|
8803
|
+
});
|
|
8804
|
+
function isQuantityValue(candidate) {
|
|
8805
|
+
return QuantityValueSchema.safeParse(candidate).success;
|
|
8806
|
+
}
|
|
8807
|
+
/**
|
|
8808
|
+
* `value` expressed in `unit`, brought to `target`. Throws
|
|
8809
|
+
* {@link QuantityUnitError} for a non-finite value, an unknown unit or a unit
|
|
8810
|
+
* of another dimension — never guesses.
|
|
8811
|
+
*/
|
|
8812
|
+
function convertQuantityInput(input) {
|
|
8813
|
+
if (!Number.isFinite(input.value)) throw new QuantityUnitError("non-finite", `${String(input.value)} is not a finite number`);
|
|
8814
|
+
const unit = normalizeUnit(input.unit);
|
|
8815
|
+
if (unit === void 0 || unitDimension(unit) === void 0) throw new QuantityUnitError("unknown-unit", `unknown unit "${input.unit}"`);
|
|
8816
|
+
const converted = tryConvertUnit(input.value, unit, input.target);
|
|
8817
|
+
if (converted === void 0) throw new QuantityUnitError("cross-dimension", `"${input.unit}" is not a unit of ${input.target}'s quantity`);
|
|
8818
|
+
return Number(converted.toPrecision(12));
|
|
8819
|
+
}
|
|
8820
|
+
/**
|
|
8821
|
+
* Zod `.meta()` bag for a cap METHOD param that is a physical quantity — the
|
|
8822
|
+
* input-side twin of `readingMeta`. The value is carried in `unit` (a gram
|
|
8823
|
+
* portion stays in grams); the unit must belong to the quantity, checked once
|
|
8824
|
+
* when the cap is declared.
|
|
8825
|
+
*/
|
|
8826
|
+
function paramMeta(declared) {
|
|
8827
|
+
const base = require_sleep.baseUnitOf(declared.quantity);
|
|
8828
|
+
if (base === void 0) throw new QuantityUnitError("unknown-unit", `quantity "${declared.quantity}" has no unit`);
|
|
8829
|
+
if (tryConvertUnit(1, declared.unit, base) === void 0) throw new QuantityUnitError("cross-dimension", `"${declared.unit}" is not a unit of ${declared.quantity}`);
|
|
8830
|
+
return {
|
|
8831
|
+
quantity: declared.quantity,
|
|
8832
|
+
unit: declared.unit
|
|
8833
|
+
};
|
|
8834
|
+
}
|
|
8835
|
+
var ParamMetaBagSchema = zod.z.object({
|
|
8836
|
+
quantity: require_sleep.ReadingQuantitySchema,
|
|
8837
|
+
unit: zod.z.string().min(1)
|
|
8838
|
+
});
|
|
8839
|
+
function metaOf(schema) {
|
|
8840
|
+
const parsed = ParamMetaBagSchema.safeParse(zod.z.globalRegistry.get(schema));
|
|
8841
|
+
return parsed.success ? parsed.data : void 0;
|
|
8842
|
+
}
|
|
8843
|
+
/** The `paramMeta` on a method input field (or its unwrapped leaf), if any. */
|
|
8844
|
+
function paramMetaOf(field) {
|
|
8845
|
+
return metaOf(field) ?? metaOf(unwrapSchema(field));
|
|
8846
|
+
}
|
|
8847
|
+
//#endregion
|
|
8063
8848
|
//#region src/automation/recipe.ts
|
|
8064
8849
|
/**
|
|
8065
8850
|
* The automation RECIPE — what a visually-authored automation is, before it
|
|
@@ -8121,8 +8906,10 @@ var AutomationConditionLeafSchema = zod.z.object({
|
|
|
8121
8906
|
zod.z.string(),
|
|
8122
8907
|
zod.z.number(),
|
|
8123
8908
|
zod.z.boolean(),
|
|
8124
|
-
zod.z.array(zod.z.union([zod.z.string(), zod.z.number()]))
|
|
8125
|
-
|
|
8909
|
+
zod.z.array(zod.z.union([zod.z.string(), zod.z.number()])),
|
|
8910
|
+
QuantityValueSchema
|
|
8911
|
+
]),
|
|
8912
|
+
unit: zod.z.string().min(1).optional()
|
|
8126
8913
|
});
|
|
8127
8914
|
var AutomationConditionStationaryPresentSchema = zod.z.object({
|
|
8128
8915
|
kind: zod.z.literal("stationary-present"),
|
|
@@ -8275,7 +9062,13 @@ var AutomationCapStepSchema = zod.z.object({
|
|
|
8275
9062
|
/** Values may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
|
|
8276
9063
|
* SUBSTITUTE and do not evaluate (§3.2.3). Anything beyond substitution is
|
|
8277
9064
|
* the expression leaf. */
|
|
8278
|
-
args: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
|
|
9065
|
+
args: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
|
|
9066
|
+
/**
|
|
9067
|
+
* The unit the person picked per arg (display only). `args` always hold the
|
|
9068
|
+
* value in the unit the method's input DECLARES (`paramMeta`); on a write an
|
|
9069
|
+
* arg may be a {@link QuantityValue}, which the save boundary converts.
|
|
9070
|
+
*/
|
|
9071
|
+
argUnits: zod.z.record(zod.z.string(), zod.z.string().min(1)).optional()
|
|
8279
9072
|
});
|
|
8280
9073
|
/**
|
|
8281
9074
|
* The steps an internal Action may contain: cap and wait, and nothing that can
|
|
@@ -9855,6 +10648,14 @@ function evalNode(cond, path, reader, now, out) {
|
|
|
9855
10648
|
expected: toTraceValue(cond.value),
|
|
9856
10649
|
observed: toTraceValue(observed)
|
|
9857
10650
|
};
|
|
10651
|
+
if (isQuantityValue(cond.value)) {
|
|
10652
|
+
out.push({
|
|
10653
|
+
...base,
|
|
10654
|
+
outcome: "fail",
|
|
10655
|
+
reason: `${cond.fieldPath} expected value's unit was never converted → fail`
|
|
10656
|
+
});
|
|
10657
|
+
return false;
|
|
10658
|
+
}
|
|
9858
10659
|
if (observed === void 0) {
|
|
9859
10660
|
out.push({
|
|
9860
10661
|
...base,
|
|
@@ -10705,6 +11506,242 @@ function buildActionSteps(steps, vars, deps) {
|
|
|
10705
11506
|
});
|
|
10706
11507
|
}
|
|
10707
11508
|
//#endregion
|
|
11509
|
+
//#region src/units/quantity-units.ts
|
|
11510
|
+
/**
|
|
11511
|
+
* Which units a person may pick for a number of a given quantity. The
|
|
11512
|
+
* quantity's stored base unit comes first (D944), then every other unit of the
|
|
11513
|
+
* same dimension in table order. A quantity with no unit (`none`, `count`,
|
|
11514
|
+
* `index`, `ratio`, `device`) offers nothing: the number is just a number.
|
|
11515
|
+
*/
|
|
11516
|
+
/** The unit a reading of `quantity` is stored in, or `undefined` when it has none. */
|
|
11517
|
+
function baseUnitForQuantity(quantity) {
|
|
11518
|
+
return require_sleep.baseUnitOf(quantity);
|
|
11519
|
+
}
|
|
11520
|
+
/**
|
|
11521
|
+
* The units a person can enter a number of `quantity` in — base unit first.
|
|
11522
|
+
* Empty when the quantity carries no unit.
|
|
11523
|
+
*/
|
|
11524
|
+
function unitsForQuantity(quantity) {
|
|
11525
|
+
const base = baseUnitForQuantity(quantity);
|
|
11526
|
+
if (base === void 0) return [];
|
|
11527
|
+
const dimension = unitDimension(base);
|
|
11528
|
+
if (dimension === void 0) return [base];
|
|
11529
|
+
return [base, ...unitsForDimension(dimension).filter((unit) => unit !== base)];
|
|
11530
|
+
}
|
|
11531
|
+
//#endregion
|
|
11532
|
+
//#region src/automation/normalize-units.ts
|
|
11533
|
+
/** A bare number accepted as a base unit — the save succeeded, say so. */
|
|
11534
|
+
var UnitWarningSchema = zod.z.object({
|
|
11535
|
+
/** Where in the saved record, e.g. `conditions.children.0` or `steps.2.args.grams`. */
|
|
11536
|
+
path: zod.z.string(),
|
|
11537
|
+
deviceId: zod.z.number().int().optional(),
|
|
11538
|
+
field: zod.z.string(),
|
|
11539
|
+
value: zod.z.number(),
|
|
11540
|
+
assumedUnit: zod.z.string(),
|
|
11541
|
+
message: zod.z.string()
|
|
11542
|
+
});
|
|
11543
|
+
function objectInput(schema) {
|
|
11544
|
+
const inner = unwrapSchema(schema);
|
|
11545
|
+
return inner instanceof zod.z.ZodObject ? inner : void 0;
|
|
11546
|
+
}
|
|
11547
|
+
/** A resolver over capability definitions (the generated registry, or a fake). */
|
|
11548
|
+
function capUnitResolver(defs) {
|
|
11549
|
+
const byName = new Map(defs.map((def) => [def.name, def]));
|
|
11550
|
+
return {
|
|
11551
|
+
fieldQuantity(cap, fieldPath) {
|
|
11552
|
+
const status = byName.get(cap)?.status;
|
|
11553
|
+
if (status === void 0) return void 0;
|
|
11554
|
+
return [...enumerateSchemaFields(status.schema), ...status.itemArray === void 0 ? [] : enumerateItemArrayFields(status.itemArray)].find((f) => f.path === fieldPath)?.quantity;
|
|
11555
|
+
},
|
|
11556
|
+
paramMeta(cap, method, arg) {
|
|
11557
|
+
const input = byName.get(cap)?.methods[method]?.input;
|
|
11558
|
+
if (input === void 0) return void 0;
|
|
11559
|
+
const field = objectInput(input)?.shape[arg];
|
|
11560
|
+
return field === void 0 ? void 0 : paramMetaOf(field);
|
|
11561
|
+
}
|
|
11562
|
+
};
|
|
11563
|
+
}
|
|
11564
|
+
function pickedUnit(raw) {
|
|
11565
|
+
return normalizeUnit(raw) ?? raw;
|
|
11566
|
+
}
|
|
11567
|
+
function hasUnitChoice(quantity) {
|
|
11568
|
+
return unitsForQuantity(quantity).length > 1;
|
|
11569
|
+
}
|
|
11570
|
+
function bareWarning(input) {
|
|
11571
|
+
return {
|
|
11572
|
+
...input,
|
|
11573
|
+
message: `${input.field}: the bare number ${input.value} was taken as ${input.assumedUnit} — send { value, unit } to state the unit`
|
|
11574
|
+
};
|
|
11575
|
+
}
|
|
11576
|
+
function checkPickedUnit(unit, target) {
|
|
11577
|
+
convertQuantityInput({
|
|
11578
|
+
value: 1,
|
|
11579
|
+
unit,
|
|
11580
|
+
target
|
|
11581
|
+
});
|
|
11582
|
+
}
|
|
11583
|
+
function normalizeLeaf(leaf, resolver, path) {
|
|
11584
|
+
const quantity = resolver.fieldQuantity(leaf.cap, leaf.fieldPath);
|
|
11585
|
+
const base = quantity === void 0 ? void 0 : baseUnitForQuantity(quantity);
|
|
11586
|
+
const wantsUnit = isQuantityValue(leaf.value) || leaf.unit !== void 0;
|
|
11587
|
+
if (base === void 0 || quantity === void 0) {
|
|
11588
|
+
if (wantsUnit) throw new QuantityUnitError("no-quantity", `${leaf.cap}.${leaf.fieldPath} is not a quantity — it takes no unit`);
|
|
11589
|
+
return {
|
|
11590
|
+
leaf,
|
|
11591
|
+
warnings: []
|
|
11592
|
+
};
|
|
11593
|
+
}
|
|
11594
|
+
if (isQuantityValue(leaf.value)) {
|
|
11595
|
+
const converted = convertQuantityInput({
|
|
11596
|
+
value: leaf.value.value,
|
|
11597
|
+
unit: leaf.value.unit,
|
|
11598
|
+
target: base
|
|
11599
|
+
});
|
|
11600
|
+
return {
|
|
11601
|
+
leaf: {
|
|
11602
|
+
...leaf,
|
|
11603
|
+
value: converted,
|
|
11604
|
+
unit: pickedUnit(leaf.value.unit)
|
|
11605
|
+
},
|
|
11606
|
+
warnings: []
|
|
11607
|
+
};
|
|
11608
|
+
}
|
|
11609
|
+
if (typeof leaf.value !== "number") return {
|
|
11610
|
+
leaf,
|
|
11611
|
+
warnings: []
|
|
11612
|
+
};
|
|
11613
|
+
if (leaf.unit !== void 0) {
|
|
11614
|
+
checkPickedUnit(leaf.unit, base);
|
|
11615
|
+
return {
|
|
11616
|
+
leaf,
|
|
11617
|
+
warnings: []
|
|
11618
|
+
};
|
|
11619
|
+
}
|
|
11620
|
+
if (!hasUnitChoice(quantity)) return {
|
|
11621
|
+
leaf,
|
|
11622
|
+
warnings: []
|
|
11623
|
+
};
|
|
11624
|
+
return {
|
|
11625
|
+
leaf,
|
|
11626
|
+
warnings: [bareWarning({
|
|
11627
|
+
path,
|
|
11628
|
+
deviceId: leaf.deviceId,
|
|
11629
|
+
field: leaf.fieldPath,
|
|
11630
|
+
value: leaf.value,
|
|
11631
|
+
assumedUnit: base
|
|
11632
|
+
})]
|
|
11633
|
+
};
|
|
11634
|
+
}
|
|
11635
|
+
/** Normalise every leaf of a condition tree. Throws {@link QuantityUnitError}. */
|
|
11636
|
+
function normalizeConditionUnits(condition, resolver, path = "conditions") {
|
|
11637
|
+
switch (condition.kind) {
|
|
11638
|
+
case "condition": {
|
|
11639
|
+
const { leaf, warnings } = normalizeLeaf(condition, resolver, path);
|
|
11640
|
+
return {
|
|
11641
|
+
value: leaf,
|
|
11642
|
+
warnings
|
|
11643
|
+
};
|
|
11644
|
+
}
|
|
11645
|
+
case "not": {
|
|
11646
|
+
const inner = normalizeConditionUnits(condition.child, resolver, `${path}.child`);
|
|
11647
|
+
return {
|
|
11648
|
+
value: {
|
|
11649
|
+
...condition,
|
|
11650
|
+
child: inner.value
|
|
11651
|
+
},
|
|
11652
|
+
warnings: inner.warnings
|
|
11653
|
+
};
|
|
11654
|
+
}
|
|
11655
|
+
case "all":
|
|
11656
|
+
case "any": {
|
|
11657
|
+
const children = condition.children.map((child, i) => normalizeConditionUnits(child, resolver, `${path}.children.${i}`));
|
|
11658
|
+
return {
|
|
11659
|
+
value: {
|
|
11660
|
+
...condition,
|
|
11661
|
+
children: children.map((c) => c.value)
|
|
11662
|
+
},
|
|
11663
|
+
warnings: children.flatMap((c) => c.warnings)
|
|
11664
|
+
};
|
|
11665
|
+
}
|
|
11666
|
+
default: return {
|
|
11667
|
+
value: condition,
|
|
11668
|
+
warnings: []
|
|
11669
|
+
};
|
|
11670
|
+
}
|
|
11671
|
+
}
|
|
11672
|
+
function normalizeCapStep(step, resolver, path) {
|
|
11673
|
+
const deviceId = typeof step.deviceId === "number" ? step.deviceId : void 0;
|
|
11674
|
+
const args = { ...step.args };
|
|
11675
|
+
const argUnits = { ...step.argUnits };
|
|
11676
|
+
const warnings = [];
|
|
11677
|
+
for (const [arg, picked] of Object.entries(step.argUnits ?? {})) {
|
|
11678
|
+
const meta = resolver.paramMeta(step.cap, step.method, arg);
|
|
11679
|
+
if (meta === void 0) throw new QuantityUnitError("no-quantity", `${step.cap}.${step.method}(${arg}) is not a quantity — it takes no unit`);
|
|
11680
|
+
checkPickedUnit(picked, meta.unit);
|
|
11681
|
+
}
|
|
11682
|
+
for (const [arg, given] of Object.entries(step.args ?? {})) {
|
|
11683
|
+
const meta = resolver.paramMeta(step.cap, step.method, arg);
|
|
11684
|
+
if (meta === void 0) continue;
|
|
11685
|
+
if (isQuantityValue(given)) {
|
|
11686
|
+
args[arg] = convertQuantityInput({
|
|
11687
|
+
value: given.value,
|
|
11688
|
+
unit: given.unit,
|
|
11689
|
+
target: meta.unit
|
|
11690
|
+
});
|
|
11691
|
+
argUnits[arg] = pickedUnit(given.unit);
|
|
11692
|
+
} else if (typeof given === "number" && argUnits[arg] === void 0 && hasUnitChoice(meta.quantity)) warnings.push(bareWarning({
|
|
11693
|
+
path: `${path}.args.${arg}`,
|
|
11694
|
+
...deviceId === void 0 ? {} : { deviceId },
|
|
11695
|
+
field: arg,
|
|
11696
|
+
value: given,
|
|
11697
|
+
assumedUnit: meta.unit
|
|
11698
|
+
}));
|
|
11699
|
+
}
|
|
11700
|
+
const { argUnits: _dropped, ...rest } = step;
|
|
11701
|
+
return {
|
|
11702
|
+
value: {
|
|
11703
|
+
...rest,
|
|
11704
|
+
...step.args === void 0 ? {} : { args },
|
|
11705
|
+
...Object.keys(argUnits).length > 0 ? { argUnits } : {}
|
|
11706
|
+
},
|
|
11707
|
+
warnings
|
|
11708
|
+
};
|
|
11709
|
+
}
|
|
11710
|
+
/**
|
|
11711
|
+
* Normalise the cap steps of an action list (an internal Action's steps, or a
|
|
11712
|
+
* recipe's actions). Other step kinds pass through. Throws {@link QuantityUnitError}.
|
|
11713
|
+
*/
|
|
11714
|
+
function normalizeActionUnits(actions, resolver, path = "steps") {
|
|
11715
|
+
const out = [];
|
|
11716
|
+
const warnings = [];
|
|
11717
|
+
actions.forEach((action, i) => {
|
|
11718
|
+
if (action.kind !== "cap") {
|
|
11719
|
+
out.push(action);
|
|
11720
|
+
return;
|
|
11721
|
+
}
|
|
11722
|
+
const normalized = normalizeCapStep(action, resolver, `${path}.${i}`);
|
|
11723
|
+
out.push(normalized.value);
|
|
11724
|
+
warnings.push(...normalized.warnings);
|
|
11725
|
+
});
|
|
11726
|
+
return {
|
|
11727
|
+
value: out,
|
|
11728
|
+
warnings
|
|
11729
|
+
};
|
|
11730
|
+
}
|
|
11731
|
+
/** Normalise a whole recipe: its condition tree and its actions. */
|
|
11732
|
+
function normalizeRecipeUnits(recipe, resolver) {
|
|
11733
|
+
const conditions = recipe.conditions === void 0 ? void 0 : normalizeConditionUnits(recipe.conditions, resolver, "conditions");
|
|
11734
|
+
const actions = normalizeActionUnits(recipe.actions, resolver, "actions");
|
|
11735
|
+
return {
|
|
11736
|
+
value: {
|
|
11737
|
+
...recipe,
|
|
11738
|
+
...conditions === void 0 ? {} : { conditions: conditions.value },
|
|
11739
|
+
actions: actions.value
|
|
11740
|
+
},
|
|
11741
|
+
warnings: [...conditions?.warnings ?? [], ...actions.warnings]
|
|
11742
|
+
};
|
|
11743
|
+
}
|
|
11744
|
+
//#endregion
|
|
10708
11745
|
//#region src/capabilities/notification-output.cap.ts
|
|
10709
11746
|
/**
|
|
10710
11747
|
* notification-output — canonical, capability-gated notification delivery.
|
|
@@ -15199,77 +16236,6 @@ function kebabToCamel(s) {
|
|
|
15199
16236
|
return s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
15200
16237
|
}
|
|
15201
16238
|
//#endregion
|
|
15202
|
-
//#region src/device/schema-fields.ts
|
|
15203
|
-
/** Unwrap ZodNullable / ZodOptional / ZodDefault wrappers to reach the inner type.
|
|
15204
|
-
* Zod v4 exposes `.unwrap()` on all three wrapper classes. */
|
|
15205
|
-
function unwrapSchema(schema) {
|
|
15206
|
-
let s = schema;
|
|
15207
|
-
while (s instanceof zod.z.ZodNullable || s instanceof zod.z.ZodOptional || s instanceof zod.z.ZodDefault) s = s.unwrap();
|
|
15208
|
-
return s;
|
|
15209
|
-
}
|
|
15210
|
-
function isMetaBag(value) {
|
|
15211
|
-
return typeof value === "object" && value !== null;
|
|
15212
|
-
}
|
|
15213
|
-
function metaQuantity(schema) {
|
|
15214
|
-
const bag = zod.z.globalRegistry.get(schema);
|
|
15215
|
-
if (isMetaBag(bag) && require_sleep.isReadingQuantity(bag.quantity)) return bag.quantity;
|
|
15216
|
-
}
|
|
15217
|
-
/** Quantity declared with `readingMeta` on the field or on the unwrapped leaf. */
|
|
15218
|
-
function quantityOfField(schema) {
|
|
15219
|
-
return metaQuantity(schema) ?? metaQuantity(unwrapSchema(schema));
|
|
15220
|
-
}
|
|
15221
|
-
function leafKind(schema) {
|
|
15222
|
-
const s = unwrapSchema(schema);
|
|
15223
|
-
if (s instanceof zod.z.ZodEnum) return {
|
|
15224
|
-
kind: "enum",
|
|
15225
|
-
enumValues: s.options
|
|
15226
|
-
};
|
|
15227
|
-
if (s instanceof zod.z.ZodNumber) return { kind: "number" };
|
|
15228
|
-
if (s instanceof zod.z.ZodString) return { kind: "string" };
|
|
15229
|
-
if (s instanceof zod.z.ZodBoolean) return { kind: "boolean" };
|
|
15230
|
-
return null;
|
|
15231
|
-
}
|
|
15232
|
-
/** Walk a cap status schema into flat wireable leaf fields (dotted paths).
|
|
15233
|
-
* Recurses into nested ZodObject (unwrapping nullable/optional/default first),
|
|
15234
|
-
* so fields with null live values are still offered. Arrays / unknown shapes
|
|
15235
|
-
* are skipped — never throws. */
|
|
15236
|
-
function enumerateSchemaFields(schema, prefix = "") {
|
|
15237
|
-
const root = unwrapSchema(schema);
|
|
15238
|
-
if (!(root instanceof zod.z.ZodObject)) return [];
|
|
15239
|
-
const out = [];
|
|
15240
|
-
const shape = root.shape;
|
|
15241
|
-
for (const [key, field] of Object.entries(shape)) {
|
|
15242
|
-
const path = prefix ? `${prefix}.${key}` : key;
|
|
15243
|
-
const inner = unwrapSchema(field);
|
|
15244
|
-
if (inner instanceof zod.z.ZodObject) {
|
|
15245
|
-
out.push(...enumerateSchemaFields(inner, path));
|
|
15246
|
-
continue;
|
|
15247
|
-
}
|
|
15248
|
-
const leaf = leafKind(field);
|
|
15249
|
-
if (leaf) {
|
|
15250
|
-
const quantity = quantityOfField(field);
|
|
15251
|
-
out.push({
|
|
15252
|
-
path,
|
|
15253
|
-
kind: leaf.kind,
|
|
15254
|
-
...leaf.enumValues ? { enumValues: leaf.enumValues } : {},
|
|
15255
|
-
...quantity !== void 0 ? { quantity } : {}
|
|
15256
|
-
});
|
|
15257
|
-
}
|
|
15258
|
-
}
|
|
15259
|
-
return out;
|
|
15260
|
-
}
|
|
15261
|
-
/** Enumerate the per-item wireable fields of an item-array cap (see
|
|
15262
|
-
* `CapabilityStatusItemArray`): the item schema's leaf fields, minus the
|
|
15263
|
-
* `keyField` (the key comes from the link's `itemKey`, never from a wired
|
|
15264
|
-
* source), each tagged `item: true` so the authoring UI collects an
|
|
15265
|
-
* `itemKey` alongside the field. Never throws. */
|
|
15266
|
-
function enumerateItemArrayFields(itemArray) {
|
|
15267
|
-
return enumerateSchemaFields(itemArray.itemSchema).filter((f) => f.path !== itemArray.keyField).map((f) => ({
|
|
15268
|
-
...f,
|
|
15269
|
-
item: true
|
|
15270
|
-
}));
|
|
15271
|
-
}
|
|
15272
|
-
//#endregion
|
|
15273
16239
|
//#region src/composition/state-fields.ts
|
|
15274
16240
|
/**
|
|
15275
16241
|
* What a capability's state field IS: kind, nullability, whether required. The
|
|
@@ -21163,192 +22129,6 @@ function parseAdminBase(baseUrl) {
|
|
|
21163
22129
|
};
|
|
21164
22130
|
}
|
|
21165
22131
|
//#endregion
|
|
21166
|
-
//#region src/device/source-info.ts
|
|
21167
|
-
/**
|
|
21168
|
-
* Identity envelope for a device's upstream-system metadata.
|
|
21169
|
-
*
|
|
21170
|
-
* Two jobs:
|
|
21171
|
-
*
|
|
21172
|
-
* 1. **Dispatch key.** `id` is the natural identifier the SOURCE system
|
|
21173
|
-
* uses to address this device (HA `entity_id`, Reolink MAC, ONVIF
|
|
21174
|
-
* WS-Discovery endpoint UUID, …). Provider code keeps a
|
|
21175
|
-
* `Map<sourceInfo.id, IDevice>` to route inbound push events in O(1)
|
|
21176
|
-
* without round-tripping through `stableId` / `id` mappings.
|
|
21177
|
-
*
|
|
21178
|
-
* 2. **Stability bridge.** `uniqueId` is the *immutable* upstream id when
|
|
21179
|
-
* one exists (HA `entity.unique_id`, Reolink MAC again — same as `id`
|
|
21180
|
-
* for vendors where MAC is the natural key). For systems where the
|
|
21181
|
-
* live dispatch key can be renamed (HA `entity_id` can be edited),
|
|
21182
|
-
* providers detect renames by matching `uniqueId` and patch `id`
|
|
21183
|
-
* in-place so dispatch keeps working.
|
|
21184
|
-
*
|
|
21185
|
-
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
21186
|
-
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
21187
|
-
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
21188
|
-
* neither is repeated on each sample. The `device_class` tag is an
|
|
21189
|
-
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
21190
|
-
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
21191
|
-
*
|
|
21192
|
-
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
21193
|
-
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
21194
|
-
* details, …). Providers control what lands here.
|
|
21195
|
-
*/
|
|
21196
|
-
var SourceInfoSchema = zod.z.object({
|
|
21197
|
-
/** Live dispatch key — mutable when the source system allows rename. */
|
|
21198
|
-
id: zod.z.string(),
|
|
21199
|
-
/** Source system tag — e.g. 'homeassistant' | 'reolink' | 'onvif'. */
|
|
21200
|
-
system: zod.z.string(),
|
|
21201
|
-
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
21202
|
-
* Used to detect rename when `id` changes. */
|
|
21203
|
-
uniqueId: zod.z.string().optional(),
|
|
21204
|
-
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
21205
|
-
quantity: require_sleep.ReadingQuantitySchema.optional(),
|
|
21206
|
-
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
21207
|
-
dateTimeShape: zod.z.enum([
|
|
21208
|
-
"date",
|
|
21209
|
-
"time",
|
|
21210
|
-
"datetime"
|
|
21211
|
-
]).optional(),
|
|
21212
|
-
/** Provider-specific extras that don't fit the structured slots.
|
|
21213
|
-
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
21214
|
-
* attribute blobs (would explode the meta JSON column). */
|
|
21215
|
-
raw: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
|
|
21216
|
-
});
|
|
21217
|
-
/**
|
|
21218
|
-
* Build the synthetic SourceInfo every existing provider falls back to
|
|
21219
|
-
* when no upstream value has been persisted. Keeps non-migrated providers
|
|
21220
|
-
* (Reolink / Hikvision / ONVIF / RTSP) functional without code
|
|
21221
|
-
* changes — `id` reuses the CamStack stableId, `system` reuses the addon
|
|
21222
|
-
* id. Real upstream identity replaces this once a provider migrates and
|
|
21223
|
-
* calls `updateSourceInfo()` with concrete values.
|
|
21224
|
-
*/
|
|
21225
|
-
function synthesizeSourceInfo(input) {
|
|
21226
|
-
return {
|
|
21227
|
-
id: input.stableId,
|
|
21228
|
-
system: input.addonId
|
|
21229
|
-
};
|
|
21230
|
-
}
|
|
21231
|
-
/**
|
|
21232
|
-
* Shallow-merge a partial patch over a prior SourceInfo. `undefined`
|
|
21233
|
-
* patch values are ignored (no field clobber); to clear a field
|
|
21234
|
-
* explicitly, providers omit it from the patch and rebuild from scratch
|
|
21235
|
-
* via `updateSourceInfo({})` cycles — uncommon enough that we don't
|
|
21236
|
-
* bother with a `null`-means-delete sentinel.
|
|
21237
|
-
*
|
|
21238
|
-
* The `raw` field is also shallow-merged: passing `raw: { foo: 1 }`
|
|
21239
|
-
* merges over existing `raw` keys instead of replacing the whole bag.
|
|
21240
|
-
*/
|
|
21241
|
-
function mergeSourceInfo(prev, patch) {
|
|
21242
|
-
const next = { ...prev };
|
|
21243
|
-
for (const [k, v] of Object.entries(patch)) {
|
|
21244
|
-
if (v === void 0) continue;
|
|
21245
|
-
if (k === "raw" && typeof v === "object" && v !== null) {
|
|
21246
|
-
next.raw = {
|
|
21247
|
-
...prev.raw,
|
|
21248
|
-
...v
|
|
21249
|
-
};
|
|
21250
|
-
continue;
|
|
21251
|
-
}
|
|
21252
|
-
next[k] = v;
|
|
21253
|
-
}
|
|
21254
|
-
return next;
|
|
21255
|
-
}
|
|
21256
|
-
/**
|
|
21257
|
-
* Coerce common unit-of-measurement string variants to a canonical form
|
|
21258
|
-
* so the UI's display templates can rely on stable strings. Pure
|
|
21259
|
-
* passthrough for unknown units — kept conservative on purpose, the goal
|
|
21260
|
-
* is to normalise the long tail of HA `unit_of_measurement` values that
|
|
21261
|
-
* have multiple historical spellings (`'°C'` vs `'C'` vs `'celsius'`).
|
|
21262
|
-
*
|
|
21263
|
-
* Extend the map as we encounter real-world data. Returning the raw
|
|
21264
|
-
* input for unknown values is intentional: providers should never
|
|
21265
|
-
* lose information silently here.
|
|
21266
|
-
*/
|
|
21267
|
-
function normalizeUnit(raw) {
|
|
21268
|
-
if (raw == null) return void 0;
|
|
21269
|
-
const trimmed = raw.trim();
|
|
21270
|
-
if (trimmed === "") return void 0;
|
|
21271
|
-
const lower = trimmed.toLowerCase();
|
|
21272
|
-
if (lower === "°c" || lower === "c" || lower === "celsius") return "°C";
|
|
21273
|
-
if (lower === "°f" || lower === "f" || lower === "fahrenheit") return "°F";
|
|
21274
|
-
if (lower === "k" || lower === "kelvin") return "K";
|
|
21275
|
-
if (lower === "%" || lower === "percent" || lower === "percentage") return "%";
|
|
21276
|
-
if (lower === "lx" || lower === "lux") return "lx";
|
|
21277
|
-
if (lower === "hpa" || lower === "hectopascal") return "hPa";
|
|
21278
|
-
if (lower === "kpa") return "kPa";
|
|
21279
|
-
if (lower === "pa") return "Pa";
|
|
21280
|
-
if (lower === "mbar" || lower === "millibar") return "mbar";
|
|
21281
|
-
if (lower === "w" || lower === "watt") return "W";
|
|
21282
|
-
if (lower === "kw" || lower === "kilowatt") return "kW";
|
|
21283
|
-
if (lower === "wh" || lower === "watt-hour") return "Wh";
|
|
21284
|
-
if (lower === "kwh" || lower === "kilowatt-hour") return "kWh";
|
|
21285
|
-
if (lower === "v" || lower === "volt") return "V";
|
|
21286
|
-
if (lower === "a" || lower === "amp" || lower === "ampere") return "A";
|
|
21287
|
-
if (lower === "ma" || lower === "milliampere") return "mA";
|
|
21288
|
-
if (lower === "va") return "VA";
|
|
21289
|
-
if (lower === "ppm") return "ppm";
|
|
21290
|
-
if (lower === "ppb") return "ppb";
|
|
21291
|
-
if (lower === "µg/m³" || lower === "ug/m3" || lower === "µg/m3") return "µg/m³";
|
|
21292
|
-
if (lower === "km/h" || lower === "kph") return "km/h";
|
|
21293
|
-
if (lower === "mph") return "mph";
|
|
21294
|
-
if (lower === "m/s") return "m/s";
|
|
21295
|
-
if (lower === "m") return "m";
|
|
21296
|
-
if (lower === "m²" || lower === "m2") return "m²";
|
|
21297
|
-
if (lower === "mm") return "mm";
|
|
21298
|
-
if (lower === "cm") return "cm";
|
|
21299
|
-
if (lower === "km") return "km";
|
|
21300
|
-
if (lower === "in" || lower === "inch" || lower === "inches") return "in";
|
|
21301
|
-
if (lower === "ft" || lower === "foot" || lower === "feet") return "ft";
|
|
21302
|
-
if (lower === "kg") return "kg";
|
|
21303
|
-
if (lower === "g") return "g";
|
|
21304
|
-
if (lower === "l" || lower === "liter" || lower === "litre" || lower === "liters" || lower === "litres") return "L";
|
|
21305
|
-
if (lower === "ml") return "mL";
|
|
21306
|
-
if (lower === "gal" || lower === "gallon" || lower === "gallons") return "gal";
|
|
21307
|
-
if (lower === "s" || lower === "sec" || lower === "second" || lower === "seconds") return "s";
|
|
21308
|
-
if (lower === "ms") return "ms";
|
|
21309
|
-
if (lower === "min" || lower === "minute" || lower === "minutes") return "min";
|
|
21310
|
-
if (lower === "h" || lower === "hr" || lower === "hour" || lower === "hours") return "h";
|
|
21311
|
-
if (lower === "d" || lower === "day" || lower === "days") return "d";
|
|
21312
|
-
if (lower === "b" || lower === "byte" || lower === "bytes") return "B";
|
|
21313
|
-
if (lower === "kib") return "KiB";
|
|
21314
|
-
if (lower === "mib") return "MiB";
|
|
21315
|
-
if (lower === "gib") return "GiB";
|
|
21316
|
-
if (lower === "tib") return "TiB";
|
|
21317
|
-
if (lower === "kb") return "kB";
|
|
21318
|
-
if (lower === "mb") return "MB";
|
|
21319
|
-
if (lower === "gb") return "GB";
|
|
21320
|
-
if (lower === "dbm") return "dBm";
|
|
21321
|
-
if (lower === "dbfs") return "dBFS";
|
|
21322
|
-
if (lower === "inhg") return "inHg";
|
|
21323
|
-
if (lower === "mm/h") return "mm/h";
|
|
21324
|
-
if (lower === "w/m²" || lower === "w/m2") return "W/m²";
|
|
21325
|
-
if (lower === "°" || lower === "deg" || lower === "degree" || lower === "degrees") return "°";
|
|
21326
|
-
if (lower === "kbps") return "kbps";
|
|
21327
|
-
if (lower === "fps") return "fps";
|
|
21328
|
-
return trimmed;
|
|
21329
|
-
}
|
|
21330
|
-
/**
|
|
21331
|
-
* Key under which `SourceInfo` lives inside `DeviceMeta.metadata`. The
|
|
21332
|
-
* blob is a free-form `Record<string, unknown>` shared with hardware-
|
|
21333
|
-
* identity fields (`manufacturer`, `model`, `firmware`, …); SourceInfo
|
|
21334
|
-
* lives under a single nested key to keep it composable with those.
|
|
21335
|
-
*/
|
|
21336
|
-
var SOURCE_INFO_METADATA_KEY = "sourceInfo";
|
|
21337
|
-
/**
|
|
21338
|
-
* Extract a SourceInfo from a `DeviceMeta.metadata` blob, validating
|
|
21339
|
-
* with Zod. Returns `null` when the blob is missing or the nested
|
|
21340
|
-
* `sourceInfo` key fails validation — callers fall back to the
|
|
21341
|
-
* synthetic default in that case (see `synthesizeSourceInfo`).
|
|
21342
|
-
*/
|
|
21343
|
-
function extractSourceInfoFromMetadata(metadata) {
|
|
21344
|
-
if (!metadata) return null;
|
|
21345
|
-
const raw = metadata[SOURCE_INFO_METADATA_KEY];
|
|
21346
|
-
if (!raw) return null;
|
|
21347
|
-
const parsed = SourceInfoSchema.safeParse(raw);
|
|
21348
|
-
if (!parsed.success) return null;
|
|
21349
|
-
return parsed.data;
|
|
21350
|
-
}
|
|
21351
|
-
//#endregion
|
|
21352
22132
|
//#region src/capabilities/device-discovery.cap.ts
|
|
21353
22133
|
/**
|
|
21354
22134
|
* device-discovery — device-scoped capability for parents that host /
|
|
@@ -65158,15 +65938,29 @@ var actionsCapability = {
|
|
|
65158
65938
|
auth: "admin"
|
|
65159
65939
|
}),
|
|
65160
65940
|
getTraces: require_sleep.method(ActionIdInput, zod.z.object({ traces: zod.z.array(AutomationRunTraceSchema) }), { auth: "admin" }),
|
|
65161
|
-
/**
|
|
65162
|
-
|
|
65941
|
+
/**
|
|
65942
|
+
* Internal actions only; a read-only (addon) entry is refused with `[read-only]`.
|
|
65943
|
+
* Create an internal action. A cap step arg that is a physical quantity may
|
|
65944
|
+
* be sent as `{ value, unit }` ("value expressed in unit"); the server
|
|
65945
|
+
* converts it to the unit the method's input declares, stores the bare
|
|
65946
|
+
* number plus the picked unit in `argUnits`, and refuses a unit of another
|
|
65947
|
+
* dimension (`[invalid-steps]`). A bare number is taken as the declared
|
|
65948
|
+
* unit and answered as a `warnings` entry (D972).
|
|
65949
|
+
*/
|
|
65950
|
+
create: require_sleep.method(zod.z.object({ action: ActionInputSchema }), zod.z.object({
|
|
65951
|
+
action: ActionEntrySchema,
|
|
65952
|
+
warnings: zod.z.array(UnitWarningSchema).optional()
|
|
65953
|
+
}), {
|
|
65163
65954
|
kind: "mutation",
|
|
65164
65955
|
auth: "admin"
|
|
65165
65956
|
}),
|
|
65166
65957
|
update: require_sleep.method(zod.z.object({
|
|
65167
65958
|
actionId: zod.z.string().min(1),
|
|
65168
65959
|
action: ActionInputSchema.partial()
|
|
65169
|
-
}), zod.z.object({
|
|
65960
|
+
}), zod.z.object({
|
|
65961
|
+
action: ActionEntrySchema,
|
|
65962
|
+
warnings: zod.z.array(UnitWarningSchema).optional()
|
|
65963
|
+
}), {
|
|
65170
65964
|
kind: "mutation",
|
|
65171
65965
|
auth: "admin"
|
|
65172
65966
|
}),
|
|
@@ -65813,6 +66607,39 @@ var EMPTY_REMOTE_ASSUMED_STATE = {
|
|
|
65813
66607
|
muted: null
|
|
65814
66608
|
};
|
|
65815
66609
|
var MAX_LAYOUT_SPAN = 24;
|
|
66610
|
+
var MAX_LAYOUT_GROUPS = 50;
|
|
66611
|
+
/**
|
|
66612
|
+
* Closed vocabularies the UI knows how to DRAW (D973). A layout names a shape,
|
|
66613
|
+
* a tone or a frame; it never carries a style. An addon that contributes a
|
|
66614
|
+
* component picks from these lists — it ships no UI code.
|
|
66615
|
+
*/
|
|
66616
|
+
var REMOTE_BUTTON_SHAPES = [
|
|
66617
|
+
"rect",
|
|
66618
|
+
"rounded",
|
|
66619
|
+
"round",
|
|
66620
|
+
"pill"
|
|
66621
|
+
];
|
|
66622
|
+
var RemoteButtonShapeSchema = zod.z.enum(REMOTE_BUTTON_SHAPES);
|
|
66623
|
+
var REMOTE_BUTTON_TONES = [
|
|
66624
|
+
"neutral",
|
|
66625
|
+
"accent",
|
|
66626
|
+
"danger",
|
|
66627
|
+
"red",
|
|
66628
|
+
"green",
|
|
66629
|
+
"yellow",
|
|
66630
|
+
"blue"
|
|
66631
|
+
];
|
|
66632
|
+
var RemoteButtonToneSchema = zod.z.enum(REMOTE_BUTTON_TONES);
|
|
66633
|
+
var REMOTE_GROUP_FRAMES = [
|
|
66634
|
+
"none",
|
|
66635
|
+
"panel",
|
|
66636
|
+
"divider",
|
|
66637
|
+
"dpad",
|
|
66638
|
+
"rocker-v",
|
|
66639
|
+
"rocker-h",
|
|
66640
|
+
"keypad"
|
|
66641
|
+
];
|
|
66642
|
+
var RemoteGroupFrameSchema = zod.z.enum(REMOTE_GROUP_FRAMES);
|
|
65816
66643
|
var RemoteLayoutButtonSchema = zod.z.object({
|
|
65817
66644
|
id: zod.z.string().min(1).max(40),
|
|
65818
66645
|
/** 0-based grid position. */
|
|
@@ -65822,12 +66649,94 @@ var RemoteLayoutButtonSchema = zod.z.object({
|
|
|
65822
66649
|
colSpan: zod.z.number().int().min(1).max(24),
|
|
65823
66650
|
icon: zod.z.string().min(1).max(60).optional(),
|
|
65824
66651
|
label: zod.z.string().min(1).max(40).optional(),
|
|
65825
|
-
role: RemoteRoleSchema
|
|
66652
|
+
role: RemoteRoleSchema,
|
|
66653
|
+
/** Absent = the plain rendering every layout had before shapes existed. */
|
|
66654
|
+
shape: RemoteButtonShapeSchema.optional(),
|
|
66655
|
+
tone: RemoteButtonToneSchema.optional(),
|
|
66656
|
+
/** The group this button belongs to; it must lie inside that group's rectangle. */
|
|
66657
|
+
groupId: zod.z.string().min(1).max(40).optional()
|
|
65826
66658
|
});
|
|
66659
|
+
/**
|
|
66660
|
+
* A rectangle of the grid that moves as ONE thing and is drawn with a frame: a
|
|
66661
|
+
* titled panel, a section divider, a D-pad ring. `componentId` names the palette
|
|
66662
|
+
* entry it came from (informational: the layout is self-contained).
|
|
66663
|
+
*/
|
|
66664
|
+
var RemoteLayoutGroupSchema = zod.z.object({
|
|
66665
|
+
id: zod.z.string().min(1).max(40),
|
|
66666
|
+
componentId: zod.z.string().min(1).max(80),
|
|
66667
|
+
frame: RemoteGroupFrameSchema,
|
|
66668
|
+
row: zod.z.number().int().min(0).max(24),
|
|
66669
|
+
col: zod.z.number().int().min(0).max(24),
|
|
66670
|
+
rowSpan: zod.z.number().int().min(1).max(24),
|
|
66671
|
+
colSpan: zod.z.number().int().min(1).max(24),
|
|
66672
|
+
title: zod.z.string().min(1).max(40).optional()
|
|
66673
|
+
});
|
|
66674
|
+
function rectsOverlap(a, b) {
|
|
66675
|
+
return a.row < b.row + b.rowSpan && b.row < a.row + a.rowSpan && a.col < b.col + b.colSpan && b.col < a.col + a.colSpan;
|
|
66676
|
+
}
|
|
66677
|
+
function rectContains(outer, inner) {
|
|
66678
|
+
return inner.row >= outer.row && inner.col >= outer.col && inner.row + inner.rowSpan <= outer.row + outer.rowSpan && inner.col + inner.colSpan <= outer.col + outer.colSpan;
|
|
66679
|
+
}
|
|
66680
|
+
/**
|
|
66681
|
+
* The group rules of a layout: inside the grid, no two groups overlap, a
|
|
66682
|
+
* member lies inside its group, a divider holds nothing, and a button that is
|
|
66683
|
+
* not a member never sits inside someone else's rectangle (a group moves as
|
|
66684
|
+
* one thing, so a stray key under it would be left behind).
|
|
66685
|
+
*/
|
|
66686
|
+
function refineGroups(grid, ctx) {
|
|
66687
|
+
const groups = grid.groups ?? [];
|
|
66688
|
+
const byId = /* @__PURE__ */ new Map();
|
|
66689
|
+
const fail = (message, path) => {
|
|
66690
|
+
ctx.addIssue({
|
|
66691
|
+
code: "custom",
|
|
66692
|
+
message,
|
|
66693
|
+
path
|
|
66694
|
+
});
|
|
66695
|
+
};
|
|
66696
|
+
groups.forEach((group, index) => {
|
|
66697
|
+
if (byId.has(group.id)) fail(`group id "${group.id}" is used twice`, [
|
|
66698
|
+
"groups",
|
|
66699
|
+
index,
|
|
66700
|
+
"id"
|
|
66701
|
+
]);
|
|
66702
|
+
byId.set(group.id, group);
|
|
66703
|
+
if (group.row + group.rowSpan > grid.rows || group.col + group.colSpan > grid.columns) fail(`group "${group.id}" leaves the grid`, ["groups", index]);
|
|
66704
|
+
for (let other = 0; other < index; other += 1) {
|
|
66705
|
+
const earlier = groups[other];
|
|
66706
|
+
if (earlier !== void 0 && rectsOverlap(earlier, group)) {
|
|
66707
|
+
fail(`groups "${earlier.id}" and "${group.id}" overlap`, ["groups", index]);
|
|
66708
|
+
return;
|
|
66709
|
+
}
|
|
66710
|
+
}
|
|
66711
|
+
});
|
|
66712
|
+
grid.buttons.forEach((button, index) => {
|
|
66713
|
+
if (button.groupId !== void 0) {
|
|
66714
|
+
const group = byId.get(button.groupId);
|
|
66715
|
+
if (group === void 0) {
|
|
66716
|
+
fail(`button "${button.id}" names the unknown group "${button.groupId}"`, [
|
|
66717
|
+
"buttons",
|
|
66718
|
+
index,
|
|
66719
|
+
"groupId"
|
|
66720
|
+
]);
|
|
66721
|
+
return;
|
|
66722
|
+
}
|
|
66723
|
+
if (group.frame === "divider") fail(`a divider group ("${group.id}") holds no buttons`, [
|
|
66724
|
+
"buttons",
|
|
66725
|
+
index,
|
|
66726
|
+
"groupId"
|
|
66727
|
+
]);
|
|
66728
|
+
if (!rectContains(group, button)) fail(`button "${button.id}" lies outside its group "${group.id}"`, ["buttons", index]);
|
|
66729
|
+
return;
|
|
66730
|
+
}
|
|
66731
|
+
const foreign = groups.find((group) => rectsOverlap(group, button));
|
|
66732
|
+
if (foreign !== void 0) fail(`button "${button.id}" lies inside group "${foreign.id}" but is not a member`, ["buttons", index]);
|
|
66733
|
+
});
|
|
66734
|
+
}
|
|
65827
66735
|
var RemoteLayoutPayloadSchema = zod.z.object({
|
|
65828
66736
|
columns: zod.z.number().int().min(1).max(24),
|
|
65829
66737
|
rows: zod.z.number().int().min(1).max(24),
|
|
65830
|
-
buttons: zod.z.array(RemoteLayoutButtonSchema).max(200)
|
|
66738
|
+
buttons: zod.z.array(RemoteLayoutButtonSchema).max(200),
|
|
66739
|
+
groups: zod.z.array(RemoteLayoutGroupSchema).max(50).optional()
|
|
65831
66740
|
}).superRefine((grid, ctx) => {
|
|
65832
66741
|
const ids = /* @__PURE__ */ new Set();
|
|
65833
66742
|
const taken = /* @__PURE__ */ new Map();
|
|
@@ -65864,6 +66773,7 @@ var RemoteLayoutPayloadSchema = zod.z.object({
|
|
|
65864
66773
|
taken.set(cell, button.id);
|
|
65865
66774
|
}
|
|
65866
66775
|
});
|
|
66776
|
+
refineGroups(grid, ctx);
|
|
65867
66777
|
});
|
|
65868
66778
|
//#endregion
|
|
65869
66779
|
//#region src/capabilities/remote.cap.ts
|
|
@@ -66093,6 +67003,121 @@ var templateCapability = {
|
|
|
66093
67003
|
}
|
|
66094
67004
|
};
|
|
66095
67005
|
//#endregion
|
|
67006
|
+
//#region src/remote/remote-components.ts
|
|
67007
|
+
/**
|
|
67008
|
+
* A remote layout COMPONENT (D973): a reusable, named chunk of a remote — a
|
|
67009
|
+
* D-pad, a keypad, a section divider — offered in the template editor's
|
|
67010
|
+
* "Add component" palette. Pure data: the buttons are placed RELATIVE to the
|
|
67011
|
+
* component, and the frame, shape and tone are names from the closed
|
|
67012
|
+
* vocabularies the UI draws. An addon contributes components through the
|
|
67013
|
+
* `remote-layout-components` cap and ships no UI code.
|
|
67014
|
+
*/
|
|
67015
|
+
var REMOTE_COMPONENT_CATEGORIES = [
|
|
67016
|
+
"power",
|
|
67017
|
+
"navigation",
|
|
67018
|
+
"volume",
|
|
67019
|
+
"numbers",
|
|
67020
|
+
"media",
|
|
67021
|
+
"colour",
|
|
67022
|
+
"apps",
|
|
67023
|
+
"layout"
|
|
67024
|
+
];
|
|
67025
|
+
var RemoteComponentCategorySchema = zod.z.enum(REMOTE_COMPONENT_CATEGORIES);
|
|
67026
|
+
var MAX_COMPONENT_BUTTONS = 40;
|
|
67027
|
+
/** `<namespace>:<name>`, both lowercase slugs — `core:dpad`, `<addonId>:<name>`. */
|
|
67028
|
+
var COMPONENT_ID_RE = /^[a-z0-9][a-z0-9_.-]*:[a-z0-9][a-z0-9_-]*$/;
|
|
67029
|
+
var RemoteComponentButtonSchema = zod.z.object({
|
|
67030
|
+
/** Joined to the instance id when the component is inserted. */
|
|
67031
|
+
idSuffix: zod.z.string().regex(/^[a-z0-9][a-z0-9_-]{0,19}$/, { message: "a short lowercase slug" }),
|
|
67032
|
+
row: zod.z.number().int().min(0).max(24),
|
|
67033
|
+
col: zod.z.number().int().min(0).max(24),
|
|
67034
|
+
rowSpan: zod.z.number().int().min(1).max(24),
|
|
67035
|
+
colSpan: zod.z.number().int().min(1).max(24),
|
|
67036
|
+
role: RemoteRoleSchema,
|
|
67037
|
+
icon: zod.z.string().min(1).max(60).optional(),
|
|
67038
|
+
label: zod.z.string().min(1).max(40).optional(),
|
|
67039
|
+
shape: RemoteButtonShapeSchema.optional(),
|
|
67040
|
+
tone: RemoteButtonToneSchema.optional()
|
|
67041
|
+
});
|
|
67042
|
+
var RemoteLayoutComponentSchema = zod.z.object({
|
|
67043
|
+
id: zod.z.string().max(80).regex(COMPONENT_ID_RE, { message: "<namespace>:<name>, lowercase" }),
|
|
67044
|
+
name: zod.z.string().min(1).max(60),
|
|
67045
|
+
nameI18n: zod.z.object({
|
|
67046
|
+
en: zod.z.string().min(1).max(60),
|
|
67047
|
+
it: zod.z.string().min(1).max(60)
|
|
67048
|
+
}).optional(),
|
|
67049
|
+
/** A display icon key, resolved by the UI like a button icon. */
|
|
67050
|
+
icon: zod.z.string().min(1).max(60),
|
|
67051
|
+
category: RemoteComponentCategorySchema,
|
|
67052
|
+
size: zod.z.object({
|
|
67053
|
+
rows: zod.z.number().int().min(1).max(24),
|
|
67054
|
+
cols: zod.z.number().int().min(1).max(24)
|
|
67055
|
+
}),
|
|
67056
|
+
/** The frame drawn around the whole component, or null for loose buttons. */
|
|
67057
|
+
group: zod.z.object({
|
|
67058
|
+
frame: RemoteGroupFrameSchema,
|
|
67059
|
+
title: zod.z.string().min(1).max(40).optional()
|
|
67060
|
+
}).nullable(),
|
|
67061
|
+
buttons: zod.z.array(RemoteComponentButtonSchema).max(40)
|
|
67062
|
+
}).superRefine((component, ctx) => {
|
|
67063
|
+
const suffixes = /* @__PURE__ */ new Set();
|
|
67064
|
+
component.buttons.forEach((button, index) => {
|
|
67065
|
+
if (suffixes.has(button.idSuffix)) ctx.addIssue({
|
|
67066
|
+
code: "custom",
|
|
67067
|
+
message: `button "${button.idSuffix}" is listed twice`,
|
|
67068
|
+
path: [
|
|
67069
|
+
"buttons",
|
|
67070
|
+
index,
|
|
67071
|
+
"idSuffix"
|
|
67072
|
+
]
|
|
67073
|
+
});
|
|
67074
|
+
suffixes.add(button.idSuffix);
|
|
67075
|
+
if (button.row + button.rowSpan > component.size.rows || button.col + button.colSpan > component.size.cols) {
|
|
67076
|
+
ctx.addIssue({
|
|
67077
|
+
code: "custom",
|
|
67078
|
+
message: `button "${button.idSuffix}" leaves the component`,
|
|
67079
|
+
path: ["buttons", index]
|
|
67080
|
+
});
|
|
67081
|
+
return;
|
|
67082
|
+
}
|
|
67083
|
+
for (let other = 0; other < index; other += 1) {
|
|
67084
|
+
const earlier = component.buttons[other];
|
|
67085
|
+
if (earlier !== void 0 && rectsOverlap(earlier, button)) {
|
|
67086
|
+
ctx.addIssue({
|
|
67087
|
+
code: "custom",
|
|
67088
|
+
message: `buttons "${earlier.idSuffix}" and "${button.idSuffix}" overlap`,
|
|
67089
|
+
path: ["buttons", index]
|
|
67090
|
+
});
|
|
67091
|
+
return;
|
|
67092
|
+
}
|
|
67093
|
+
}
|
|
67094
|
+
});
|
|
67095
|
+
if (component.group?.frame === "divider" && component.buttons.length > 0) ctx.addIssue({
|
|
67096
|
+
code: "custom",
|
|
67097
|
+
message: "a divider component holds no buttons",
|
|
67098
|
+
path: ["buttons"]
|
|
67099
|
+
});
|
|
67100
|
+
});
|
|
67101
|
+
//#endregion
|
|
67102
|
+
//#region src/capabilities/remote-layout-components.cap.ts
|
|
67103
|
+
/**
|
|
67104
|
+
* remote-layout-components — the palette of the remote template editor's "Add
|
|
67105
|
+
* component" (D973). A provider DECLARES components as data (buttons placed
|
|
67106
|
+
* relative to the component, a frame, shapes and tones from closed
|
|
67107
|
+
* vocabularies the UI draws); it ships no UI code.
|
|
67108
|
+
*
|
|
67109
|
+
* Collection: `listComponents` returns an array, so the generated mount
|
|
67110
|
+
* concat-fans it across every enabled provider. The core-blocks builtin
|
|
67111
|
+
* provides the built-in set (`core:*`); an addon adds its own under
|
|
67112
|
+
* `<addonId>:<name>`. The caller dedupes by id, built-ins first.
|
|
67113
|
+
*/
|
|
67114
|
+
var remoteLayoutComponentsCapability = {
|
|
67115
|
+
name: "remote-layout-components",
|
|
67116
|
+
scope: "system",
|
|
67117
|
+
mode: "collection",
|
|
67118
|
+
methods: { listComponents: require_sleep.method(zod.z.object({}), zod.z.array(RemoteLayoutComponentSchema), { auth: "protected" }) }
|
|
67119
|
+
};
|
|
67120
|
+
//#endregion
|
|
66096
67121
|
//#region src/capabilities/button.cap.ts
|
|
66097
67122
|
/**
|
|
66098
67123
|
* button — device-scoped capability for HA `button.*` / `input_button.*`
|
|
@@ -73343,6 +74368,14 @@ var PetFeederDeviceStatusSchema = zod.z.enum([
|
|
|
73343
74368
|
"on_batteries"
|
|
73344
74369
|
]);
|
|
73345
74370
|
var gramsPortion = zod.z.number().int().min(4).max(200);
|
|
74371
|
+
/** A portion REQUESTED of the feeder is a mass the method takes in GRAMS (the
|
|
74372
|
+
* hardware's own unit). The bounds are grams; a caller entering another unit
|
|
74373
|
+
* converts to grams first (`paramMeta`, D972). The STATUS fields above stay
|
|
74374
|
+
* plain grams — they are not readings in the kilogram base. */
|
|
74375
|
+
var gramsParam = gramsPortion.meta(paramMeta({
|
|
74376
|
+
quantity: "mass",
|
|
74377
|
+
unit: "g"
|
|
74378
|
+
}));
|
|
73346
74379
|
var PetFeederStatusSchema = zod.z.object({
|
|
73347
74380
|
/** Food in the TANK (hopper), as the feeder's own sensor reports it
|
|
73348
74381
|
* (`state.food`). A coarse level code, not grams — `0` is empty. The
|
|
@@ -73431,9 +74464,9 @@ var petFeederCapability = {
|
|
|
73431
74464
|
*/
|
|
73432
74465
|
feed: require_sleep.method(zod.z.object({
|
|
73433
74466
|
deviceId: zod.z.number().int().nonnegative(),
|
|
73434
|
-
grams:
|
|
73435
|
-
hopper1:
|
|
73436
|
-
hopper2:
|
|
74467
|
+
grams: gramsParam.optional(),
|
|
74468
|
+
hopper1: gramsParam.optional(),
|
|
74469
|
+
hopper2: gramsParam.optional()
|
|
73437
74470
|
}), zod.z.void(), {
|
|
73438
74471
|
kind: "mutation",
|
|
73439
74472
|
auth: "protected"
|
|
@@ -82154,6 +83187,430 @@ var PIPELINE_OWNER_CAPABILITY_NAMES = [
|
|
|
82154
83187
|
"pipeline-runner"
|
|
82155
83188
|
];
|
|
82156
83189
|
//#endregion
|
|
83190
|
+
//#region src/remote/remote-layout-ops.ts
|
|
83191
|
+
var LAYOUT_EDIT_REFUSALS = [
|
|
83192
|
+
"outside",
|
|
83193
|
+
"overlap",
|
|
83194
|
+
"unknown-group",
|
|
83195
|
+
"too-many"
|
|
83196
|
+
];
|
|
83197
|
+
var refuse = (reason) => ({
|
|
83198
|
+
ok: false,
|
|
83199
|
+
reason
|
|
83200
|
+
});
|
|
83201
|
+
function withGroups(layout, groups) {
|
|
83202
|
+
const { groups: _previous, ...rest } = layout;
|
|
83203
|
+
return groups.length === 0 ? rest : {
|
|
83204
|
+
...rest,
|
|
83205
|
+
groups: [...groups]
|
|
83206
|
+
};
|
|
83207
|
+
}
|
|
83208
|
+
function fitsGrid(layout, rect) {
|
|
83209
|
+
return rect.row >= 0 && rect.col >= 0 && rect.row + rect.rowSpan <= layout.rows && rect.col + rect.colSpan <= layout.columns;
|
|
83210
|
+
}
|
|
83211
|
+
/** The columns a component must be scaled by to span the whole grid width, or null when it does not divide. */
|
|
83212
|
+
function fillWidthScale(layout, component) {
|
|
83213
|
+
const factor = layout.columns / component.size.cols;
|
|
83214
|
+
return Number.isInteger(factor) && factor >= 1 ? factor : null;
|
|
83215
|
+
}
|
|
83216
|
+
function titleOf(title) {
|
|
83217
|
+
return title === void 0 ? {} : { title };
|
|
83218
|
+
}
|
|
83219
|
+
function slug$1(value) {
|
|
83220
|
+
return (value.includes(":") ? value.slice(value.indexOf(":") + 1) : value).replace(/[^a-z0-9_-]/g, "-").slice(0, 16);
|
|
83221
|
+
}
|
|
83222
|
+
function uniqueId(base, taken) {
|
|
83223
|
+
if (!taken.has(base)) return base;
|
|
83224
|
+
for (let n = 2;; n += 1) {
|
|
83225
|
+
const candidate = `${base}-${n}`;
|
|
83226
|
+
if (!taken.has(candidate)) return candidate;
|
|
83227
|
+
}
|
|
83228
|
+
}
|
|
83229
|
+
function freePrefix(base, placed, taken) {
|
|
83230
|
+
for (let n = 1;; n += 1) {
|
|
83231
|
+
const candidate = n === 1 ? base : `${base}-${n}`;
|
|
83232
|
+
if (!placed.some((p) => taken.has(`${candidate}-${p.spec.idSuffix}`))) return candidate;
|
|
83233
|
+
}
|
|
83234
|
+
}
|
|
83235
|
+
/**
|
|
83236
|
+
* Put `component` on the layout with its top-left cell at `at`. A component
|
|
83237
|
+
* with a group becomes one group whose rectangle is the whole component and
|
|
83238
|
+
* whose members are its buttons; one without is a set of loose buttons. The
|
|
83239
|
+
* grid does not grow: a component that does not fit is refused `outside`, one
|
|
83240
|
+
* that would sit on an existing key or group `overlap`.
|
|
83241
|
+
*/
|
|
83242
|
+
function insertComponent(layout, component, at, options = {}) {
|
|
83243
|
+
const rowScale = options.scale?.rows ?? 1;
|
|
83244
|
+
const colScale = options.scale?.cols ?? 1;
|
|
83245
|
+
const bounds = {
|
|
83246
|
+
row: at.row,
|
|
83247
|
+
col: at.col,
|
|
83248
|
+
rowSpan: component.size.rows * rowScale,
|
|
83249
|
+
colSpan: component.size.cols * colScale
|
|
83250
|
+
};
|
|
83251
|
+
if (!fitsGrid(layout, bounds)) return refuse("outside");
|
|
83252
|
+
const specs = [...component.buttons, ...options.extras ?? []];
|
|
83253
|
+
const placed = specs.map((spec) => ({
|
|
83254
|
+
spec,
|
|
83255
|
+
rect: {
|
|
83256
|
+
row: at.row + spec.row * rowScale,
|
|
83257
|
+
col: at.col + spec.col * colScale,
|
|
83258
|
+
rowSpan: spec.rowSpan * rowScale,
|
|
83259
|
+
colSpan: spec.colSpan * colScale
|
|
83260
|
+
}
|
|
83261
|
+
}));
|
|
83262
|
+
const groups = layout.groups ?? [];
|
|
83263
|
+
if ((component.group === null ? placed.map((p) => p.rect) : [bounds]).some((rect) => layout.buttons.some((b) => rectsOverlap(b, rect)) || groups.some((g) => rectsOverlap(g, rect)))) return refuse("overlap");
|
|
83264
|
+
if (layout.buttons.length + specs.length > 200 || groups.length + (component.group === null ? 0 : 1) > 50) return refuse("too-many");
|
|
83265
|
+
const base = slug$1(component.id);
|
|
83266
|
+
const takenButtons = new Set(layout.buttons.map((b) => b.id));
|
|
83267
|
+
const takenGroups = new Set(groups.map((g) => g.id));
|
|
83268
|
+
const groupId = component.group === null ? null : uniqueId(base, takenGroups);
|
|
83269
|
+
const prefix = groupId ?? freePrefix(base, placed, takenButtons);
|
|
83270
|
+
const buttons = placed.map(({ spec, rect }) => ({
|
|
83271
|
+
id: `${prefix}-${spec.idSuffix}`,
|
|
83272
|
+
...rect,
|
|
83273
|
+
role: spec.role,
|
|
83274
|
+
...spec.icon === void 0 ? {} : { icon: spec.icon },
|
|
83275
|
+
...spec.label === void 0 ? {} : { label: spec.label },
|
|
83276
|
+
...spec.shape === void 0 ? {} : { shape: spec.shape },
|
|
83277
|
+
...spec.tone === void 0 ? {} : { tone: spec.tone },
|
|
83278
|
+
...groupId === null ? {} : { groupId }
|
|
83279
|
+
}));
|
|
83280
|
+
const group = component.group === null || groupId === null ? [] : [{
|
|
83281
|
+
id: groupId,
|
|
83282
|
+
componentId: component.id,
|
|
83283
|
+
frame: component.group.frame,
|
|
83284
|
+
...bounds,
|
|
83285
|
+
...titleOf(options.title ?? component.group.title)
|
|
83286
|
+
}];
|
|
83287
|
+
return {
|
|
83288
|
+
ok: true,
|
|
83289
|
+
layout: withGroups({
|
|
83290
|
+
...layout,
|
|
83291
|
+
buttons: [...layout.buttons, ...buttons]
|
|
83292
|
+
}, [...groups, ...group]),
|
|
83293
|
+
groupId,
|
|
83294
|
+
buttonIds: buttons.map((b) => b.id)
|
|
83295
|
+
};
|
|
83296
|
+
}
|
|
83297
|
+
/** Move a group and every member by the same offset, atomically. */
|
|
83298
|
+
function moveGroup(layout, groupId, to) {
|
|
83299
|
+
const groups = layout.groups ?? [];
|
|
83300
|
+
const group = groups.find((g) => g.id === groupId);
|
|
83301
|
+
if (group === void 0) return refuse("unknown-group");
|
|
83302
|
+
const moved = {
|
|
83303
|
+
...group,
|
|
83304
|
+
row: to.row,
|
|
83305
|
+
col: to.col
|
|
83306
|
+
};
|
|
83307
|
+
if (!fitsGrid(layout, moved)) return refuse("outside");
|
|
83308
|
+
const dRow = to.row - group.row;
|
|
83309
|
+
const dCol = to.col - group.col;
|
|
83310
|
+
const isMember = (b) => b.groupId === groupId;
|
|
83311
|
+
if (groups.some((g) => g.id !== groupId && rectsOverlap(g, moved)) || layout.buttons.some((b) => !isMember(b) && rectsOverlap(b, moved))) return refuse("overlap");
|
|
83312
|
+
return {
|
|
83313
|
+
ok: true,
|
|
83314
|
+
layout: {
|
|
83315
|
+
...layout,
|
|
83316
|
+
buttons: layout.buttons.map((b) => isMember(b) ? {
|
|
83317
|
+
...b,
|
|
83318
|
+
row: b.row + dRow,
|
|
83319
|
+
col: b.col + dCol
|
|
83320
|
+
} : b),
|
|
83321
|
+
groups: groups.map((g) => g.id === groupId ? moved : g)
|
|
83322
|
+
}
|
|
83323
|
+
};
|
|
83324
|
+
}
|
|
83325
|
+
/**
|
|
83326
|
+
* Delete a group. With `keepButtons` its members stay where they are as loose
|
|
83327
|
+
* keys; without, they go with it.
|
|
83328
|
+
*/
|
|
83329
|
+
function removeGroup(layout, groupId, options) {
|
|
83330
|
+
const groups = layout.groups ?? [];
|
|
83331
|
+
if (!groups.some((g) => g.id === groupId)) return refuse("unknown-group");
|
|
83332
|
+
const buttons = options.keepButtons ? layout.buttons.map((b) => {
|
|
83333
|
+
if (b.groupId !== groupId) return b;
|
|
83334
|
+
const { groupId: _gone, ...rest } = b;
|
|
83335
|
+
return rest;
|
|
83336
|
+
}) : layout.buttons.filter((b) => b.groupId !== groupId);
|
|
83337
|
+
return {
|
|
83338
|
+
ok: true,
|
|
83339
|
+
layout: withGroups({
|
|
83340
|
+
...layout,
|
|
83341
|
+
buttons
|
|
83342
|
+
}, groups.filter((g) => g.id !== groupId))
|
|
83343
|
+
};
|
|
83344
|
+
}
|
|
83345
|
+
/** Dissolve a group, keeping its buttons in place. */
|
|
83346
|
+
function ungroup(layout, groupId) {
|
|
83347
|
+
return removeGroup(layout, groupId, { keepButtons: true });
|
|
83348
|
+
}
|
|
83349
|
+
//#endregion
|
|
83350
|
+
//#region src/remote/remote-builtin-components.ts
|
|
83351
|
+
var btn = (idSuffix, row, col, init) => ({
|
|
83352
|
+
idSuffix,
|
|
83353
|
+
row,
|
|
83354
|
+
col,
|
|
83355
|
+
rowSpan: 1,
|
|
83356
|
+
colSpan: 1,
|
|
83357
|
+
...init
|
|
83358
|
+
});
|
|
83359
|
+
function rocker(id, name, it, frame, title, buttons, size) {
|
|
83360
|
+
return {
|
|
83361
|
+
id,
|
|
83362
|
+
name,
|
|
83363
|
+
nameI18n: {
|
|
83364
|
+
en: name,
|
|
83365
|
+
it
|
|
83366
|
+
},
|
|
83367
|
+
icon: frame === "rocker-v" ? "chevrons-up-down" : "chevrons-left-right",
|
|
83368
|
+
category: id.includes("channel") || id.includes("volume") ? "volume" : "navigation",
|
|
83369
|
+
size,
|
|
83370
|
+
group: title === null ? { frame } : {
|
|
83371
|
+
frame,
|
|
83372
|
+
title
|
|
83373
|
+
},
|
|
83374
|
+
buttons
|
|
83375
|
+
};
|
|
83376
|
+
}
|
|
83377
|
+
var BUILTIN_REMOTE_COMPONENTS = [
|
|
83378
|
+
{
|
|
83379
|
+
id: "core:power",
|
|
83380
|
+
name: "Power",
|
|
83381
|
+
nameI18n: {
|
|
83382
|
+
en: "Power",
|
|
83383
|
+
it: "Accensione"
|
|
83384
|
+
},
|
|
83385
|
+
icon: "power",
|
|
83386
|
+
category: "power",
|
|
83387
|
+
size: {
|
|
83388
|
+
rows: 1,
|
|
83389
|
+
cols: 1
|
|
83390
|
+
},
|
|
83391
|
+
group: null,
|
|
83392
|
+
buttons: [btn("power", 0, 0, {
|
|
83393
|
+
role: "power",
|
|
83394
|
+
shape: "round",
|
|
83395
|
+
tone: "danger"
|
|
83396
|
+
})]
|
|
83397
|
+
},
|
|
83398
|
+
{
|
|
83399
|
+
id: "core:dpad",
|
|
83400
|
+
name: "D-pad with OK",
|
|
83401
|
+
nameI18n: {
|
|
83402
|
+
en: "D-pad with OK",
|
|
83403
|
+
it: "Croce direzionale con OK"
|
|
83404
|
+
},
|
|
83405
|
+
icon: "gamepad-2",
|
|
83406
|
+
category: "navigation",
|
|
83407
|
+
size: {
|
|
83408
|
+
rows: 3,
|
|
83409
|
+
cols: 3
|
|
83410
|
+
},
|
|
83411
|
+
group: { frame: "dpad" },
|
|
83412
|
+
buttons: [
|
|
83413
|
+
btn("up", 0, 1, { role: "up" }),
|
|
83414
|
+
btn("left", 1, 0, { role: "left" }),
|
|
83415
|
+
btn("ok", 1, 1, {
|
|
83416
|
+
role: "ok",
|
|
83417
|
+
shape: "round",
|
|
83418
|
+
tone: "accent"
|
|
83419
|
+
}),
|
|
83420
|
+
btn("right", 1, 2, { role: "right" }),
|
|
83421
|
+
btn("down", 2, 1, { role: "down" })
|
|
83422
|
+
]
|
|
83423
|
+
},
|
|
83424
|
+
rocker("core:rocker-volume-v", "Volume rocker", "Bilanciere volume", "rocker-v", "VOL", [btn("up", 0, 0, {
|
|
83425
|
+
role: "volume_up",
|
|
83426
|
+
shape: "pill"
|
|
83427
|
+
}), btn("down", 1, 0, {
|
|
83428
|
+
role: "volume_down",
|
|
83429
|
+
shape: "pill"
|
|
83430
|
+
})], {
|
|
83431
|
+
rows: 2,
|
|
83432
|
+
cols: 1
|
|
83433
|
+
}),
|
|
83434
|
+
rocker("core:rocker-channel-v", "Channel rocker", "Bilanciere canali", "rocker-v", "CH", [btn("up", 0, 0, {
|
|
83435
|
+
role: "channel_up",
|
|
83436
|
+
shape: "pill"
|
|
83437
|
+
}), btn("down", 1, 0, {
|
|
83438
|
+
role: "channel_down",
|
|
83439
|
+
shape: "pill"
|
|
83440
|
+
})], {
|
|
83441
|
+
rows: 2,
|
|
83442
|
+
cols: 1
|
|
83443
|
+
}),
|
|
83444
|
+
rocker("core:rocker-h", "Minus / plus rocker", "Bilanciere meno / più", "rocker-h", null, [btn("minus", 0, 0, {
|
|
83445
|
+
role: "custom:minus",
|
|
83446
|
+
label: "−",
|
|
83447
|
+
shape: "pill"
|
|
83448
|
+
}), btn("plus", 0, 1, {
|
|
83449
|
+
role: "custom:plus",
|
|
83450
|
+
label: "+",
|
|
83451
|
+
shape: "pill"
|
|
83452
|
+
})], {
|
|
83453
|
+
rows: 1,
|
|
83454
|
+
cols: 2
|
|
83455
|
+
}),
|
|
83456
|
+
{
|
|
83457
|
+
id: "core:keypad",
|
|
83458
|
+
name: "Numeric keypad",
|
|
83459
|
+
nameI18n: {
|
|
83460
|
+
en: "Numeric keypad",
|
|
83461
|
+
it: "Tastierino numerico"
|
|
83462
|
+
},
|
|
83463
|
+
icon: "grid-3x3",
|
|
83464
|
+
category: "numbers",
|
|
83465
|
+
size: {
|
|
83466
|
+
rows: 4,
|
|
83467
|
+
cols: 3
|
|
83468
|
+
},
|
|
83469
|
+
group: { frame: "keypad" },
|
|
83470
|
+
buttons: [...Array.from({ length: 9 }, (_, i) => btn(`d${i + 1}`, Math.floor(i / 3), i % 3, { role: `digit_${i + 1}` })), btn("d0", 3, 1, { role: "digit_0" })]
|
|
83471
|
+
},
|
|
83472
|
+
{
|
|
83473
|
+
id: "core:colour-keys",
|
|
83474
|
+
name: "Colour keys",
|
|
83475
|
+
nameI18n: {
|
|
83476
|
+
en: "Colour keys",
|
|
83477
|
+
it: "Tasti colorati"
|
|
83478
|
+
},
|
|
83479
|
+
icon: "palette",
|
|
83480
|
+
category: "colour",
|
|
83481
|
+
size: {
|
|
83482
|
+
rows: 1,
|
|
83483
|
+
cols: 4
|
|
83484
|
+
},
|
|
83485
|
+
group: null,
|
|
83486
|
+
buttons: [
|
|
83487
|
+
btn("red", 0, 0, {
|
|
83488
|
+
role: "custom:color_red",
|
|
83489
|
+
tone: "red"
|
|
83490
|
+
}),
|
|
83491
|
+
btn("green", 0, 1, {
|
|
83492
|
+
role: "custom:color_green",
|
|
83493
|
+
tone: "green"
|
|
83494
|
+
}),
|
|
83495
|
+
btn("yellow", 0, 2, {
|
|
83496
|
+
role: "custom:color_yellow",
|
|
83497
|
+
tone: "yellow"
|
|
83498
|
+
}),
|
|
83499
|
+
btn("blue", 0, 3, {
|
|
83500
|
+
role: "custom:color_blue",
|
|
83501
|
+
tone: "blue"
|
|
83502
|
+
})
|
|
83503
|
+
]
|
|
83504
|
+
},
|
|
83505
|
+
{
|
|
83506
|
+
id: "core:media-transport",
|
|
83507
|
+
name: "Media transport",
|
|
83508
|
+
nameI18n: {
|
|
83509
|
+
en: "Media transport",
|
|
83510
|
+
it: "Controlli multimediali"
|
|
83511
|
+
},
|
|
83512
|
+
icon: "play",
|
|
83513
|
+
category: "media",
|
|
83514
|
+
size: {
|
|
83515
|
+
rows: 1,
|
|
83516
|
+
cols: 5
|
|
83517
|
+
},
|
|
83518
|
+
group: null,
|
|
83519
|
+
buttons: [
|
|
83520
|
+
btn("rewind", 0, 0, { role: "rewind" }),
|
|
83521
|
+
btn("play", 0, 1, { role: "play" }),
|
|
83522
|
+
btn("pause", 0, 2, { role: "pause" }),
|
|
83523
|
+
btn("forward", 0, 3, { role: "fast_forward" }),
|
|
83524
|
+
btn("stop", 0, 4, { role: "stop" })
|
|
83525
|
+
]
|
|
83526
|
+
},
|
|
83527
|
+
{
|
|
83528
|
+
id: "core:apps-row",
|
|
83529
|
+
name: "App row",
|
|
83530
|
+
nameI18n: {
|
|
83531
|
+
en: "App row",
|
|
83532
|
+
it: "Riga di app"
|
|
83533
|
+
},
|
|
83534
|
+
icon: "app-window",
|
|
83535
|
+
category: "apps",
|
|
83536
|
+
size: {
|
|
83537
|
+
rows: 1,
|
|
83538
|
+
cols: 4
|
|
83539
|
+
},
|
|
83540
|
+
group: null,
|
|
83541
|
+
buttons: [
|
|
83542
|
+
1,
|
|
83543
|
+
2,
|
|
83544
|
+
3,
|
|
83545
|
+
4
|
|
83546
|
+
].map((n) => btn(`app${n}`, 0, n - 1, { role: `custom:app_slot_${n}` }))
|
|
83547
|
+
},
|
|
83548
|
+
{
|
|
83549
|
+
id: "core:back-home-menu",
|
|
83550
|
+
name: "Back, Home, Menu",
|
|
83551
|
+
nameI18n: {
|
|
83552
|
+
en: "Back, Home, Menu",
|
|
83553
|
+
it: "Indietro, Home, Menu"
|
|
83554
|
+
},
|
|
83555
|
+
icon: "house",
|
|
83556
|
+
category: "navigation",
|
|
83557
|
+
size: {
|
|
83558
|
+
rows: 1,
|
|
83559
|
+
cols: 3
|
|
83560
|
+
},
|
|
83561
|
+
group: null,
|
|
83562
|
+
buttons: [
|
|
83563
|
+
btn("back", 0, 0, { role: "back" }),
|
|
83564
|
+
btn("home", 0, 1, { role: "home" }),
|
|
83565
|
+
btn("menu", 0, 2, { role: "menu" })
|
|
83566
|
+
]
|
|
83567
|
+
},
|
|
83568
|
+
{
|
|
83569
|
+
id: "core:section-divider",
|
|
83570
|
+
name: "Section divider",
|
|
83571
|
+
nameI18n: {
|
|
83572
|
+
en: "Section divider",
|
|
83573
|
+
it: "Divisore di sezione"
|
|
83574
|
+
},
|
|
83575
|
+
icon: "separator-horizontal",
|
|
83576
|
+
category: "layout",
|
|
83577
|
+
size: {
|
|
83578
|
+
rows: 1,
|
|
83579
|
+
cols: 1
|
|
83580
|
+
},
|
|
83581
|
+
group: {
|
|
83582
|
+
frame: "divider",
|
|
83583
|
+
title: "Section"
|
|
83584
|
+
},
|
|
83585
|
+
buttons: []
|
|
83586
|
+
},
|
|
83587
|
+
{
|
|
83588
|
+
id: "core:panel",
|
|
83589
|
+
name: "Titled panel",
|
|
83590
|
+
nameI18n: {
|
|
83591
|
+
en: "Titled panel",
|
|
83592
|
+
it: "Pannello con titolo"
|
|
83593
|
+
},
|
|
83594
|
+
icon: "panel-top",
|
|
83595
|
+
category: "layout",
|
|
83596
|
+
size: {
|
|
83597
|
+
rows: 2,
|
|
83598
|
+
cols: 3
|
|
83599
|
+
},
|
|
83600
|
+
group: {
|
|
83601
|
+
frame: "panel",
|
|
83602
|
+
title: "Panel"
|
|
83603
|
+
},
|
|
83604
|
+
buttons: []
|
|
83605
|
+
}
|
|
83606
|
+
];
|
|
83607
|
+
/** A built-in component by id (the presets compose from these). */
|
|
83608
|
+
function builtinRemoteComponent(id) {
|
|
83609
|
+
const found = BUILTIN_REMOTE_COMPONENTS.find((component) => component.id === id);
|
|
83610
|
+
if (found === void 0) throw new Error(`no built-in remote component "${id}"`);
|
|
83611
|
+
return found;
|
|
83612
|
+
}
|
|
83613
|
+
//#endregion
|
|
82157
83614
|
//#region src/ir/ir-error.ts
|
|
82158
83615
|
var IrCodecError = class extends Error {
|
|
82159
83616
|
code;
|
|
@@ -82891,465 +84348,6 @@ function numericAccept() {
|
|
|
82891
84348
|
return historyAccept("statistic").filter((field) => field.valueKind === "number");
|
|
82892
84349
|
}
|
|
82893
84350
|
//#endregion
|
|
82894
|
-
//#region src/units/unit-table.ts
|
|
82895
|
-
/**
|
|
82896
|
-
* Frozen unit → spec table. `•` in the doc marks each dimension's canonical
|
|
82897
|
-
* unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
|
|
82898
|
-
* `factor = 5/9`, `offset = -160/9` (kept as exact expressions, not rounded
|
|
82899
|
-
* decimals). K derives from `°C = K − 273.15`.
|
|
82900
|
-
*/
|
|
82901
|
-
var UNIT_TABLE = {
|
|
82902
|
-
"°C": {
|
|
82903
|
-
dimension: "temperature",
|
|
82904
|
-
factor: 1,
|
|
82905
|
-
offset: 0
|
|
82906
|
-
},
|
|
82907
|
-
"°F": {
|
|
82908
|
-
dimension: "temperature",
|
|
82909
|
-
factor: 5 / 9,
|
|
82910
|
-
offset: -160 / 9
|
|
82911
|
-
},
|
|
82912
|
-
K: {
|
|
82913
|
-
dimension: "temperature",
|
|
82914
|
-
factor: 1,
|
|
82915
|
-
offset: -273.15
|
|
82916
|
-
},
|
|
82917
|
-
hPa: {
|
|
82918
|
-
dimension: "pressure",
|
|
82919
|
-
factor: 1,
|
|
82920
|
-
offset: 0
|
|
82921
|
-
},
|
|
82922
|
-
kPa: {
|
|
82923
|
-
dimension: "pressure",
|
|
82924
|
-
factor: 10,
|
|
82925
|
-
offset: 0
|
|
82926
|
-
},
|
|
82927
|
-
Pa: {
|
|
82928
|
-
dimension: "pressure",
|
|
82929
|
-
factor: .01,
|
|
82930
|
-
offset: 0
|
|
82931
|
-
},
|
|
82932
|
-
mbar: {
|
|
82933
|
-
dimension: "pressure",
|
|
82934
|
-
factor: 1,
|
|
82935
|
-
offset: 0
|
|
82936
|
-
},
|
|
82937
|
-
bar: {
|
|
82938
|
-
dimension: "pressure",
|
|
82939
|
-
factor: 1e3,
|
|
82940
|
-
offset: 0
|
|
82941
|
-
},
|
|
82942
|
-
inHg: {
|
|
82943
|
-
dimension: "pressure",
|
|
82944
|
-
factor: 33.8639,
|
|
82945
|
-
offset: 0
|
|
82946
|
-
},
|
|
82947
|
-
mmHg: {
|
|
82948
|
-
dimension: "pressure",
|
|
82949
|
-
factor: 1.33322,
|
|
82950
|
-
offset: 0
|
|
82951
|
-
},
|
|
82952
|
-
psi: {
|
|
82953
|
-
dimension: "pressure",
|
|
82954
|
-
factor: 68.9476,
|
|
82955
|
-
offset: 0
|
|
82956
|
-
},
|
|
82957
|
-
"m/s": {
|
|
82958
|
-
dimension: "speed",
|
|
82959
|
-
factor: 1,
|
|
82960
|
-
offset: 0
|
|
82961
|
-
},
|
|
82962
|
-
"km/h": {
|
|
82963
|
-
dimension: "speed",
|
|
82964
|
-
factor: 1 / 3.6,
|
|
82965
|
-
offset: 0
|
|
82966
|
-
},
|
|
82967
|
-
mph: {
|
|
82968
|
-
dimension: "speed",
|
|
82969
|
-
factor: .44704,
|
|
82970
|
-
offset: 0
|
|
82971
|
-
},
|
|
82972
|
-
kn: {
|
|
82973
|
-
dimension: "speed",
|
|
82974
|
-
factor: .514444,
|
|
82975
|
-
offset: 0
|
|
82976
|
-
},
|
|
82977
|
-
"mm/h": {
|
|
82978
|
-
dimension: "precipitation-rate",
|
|
82979
|
-
factor: 1,
|
|
82980
|
-
offset: 0
|
|
82981
|
-
},
|
|
82982
|
-
"in/h": {
|
|
82983
|
-
dimension: "precipitation-rate",
|
|
82984
|
-
factor: 25.4,
|
|
82985
|
-
offset: 0
|
|
82986
|
-
},
|
|
82987
|
-
m: {
|
|
82988
|
-
dimension: "length",
|
|
82989
|
-
factor: 1,
|
|
82990
|
-
offset: 0
|
|
82991
|
-
},
|
|
82992
|
-
mm: {
|
|
82993
|
-
dimension: "length",
|
|
82994
|
-
factor: .001,
|
|
82995
|
-
offset: 0
|
|
82996
|
-
},
|
|
82997
|
-
cm: {
|
|
82998
|
-
dimension: "length",
|
|
82999
|
-
factor: .01,
|
|
83000
|
-
offset: 0
|
|
83001
|
-
},
|
|
83002
|
-
km: {
|
|
83003
|
-
dimension: "length",
|
|
83004
|
-
factor: 1e3,
|
|
83005
|
-
offset: 0
|
|
83006
|
-
},
|
|
83007
|
-
in: {
|
|
83008
|
-
dimension: "length",
|
|
83009
|
-
factor: .0254,
|
|
83010
|
-
offset: 0
|
|
83011
|
-
},
|
|
83012
|
-
ft: {
|
|
83013
|
-
dimension: "length",
|
|
83014
|
-
factor: .3048,
|
|
83015
|
-
offset: 0
|
|
83016
|
-
},
|
|
83017
|
-
mi: {
|
|
83018
|
-
dimension: "length",
|
|
83019
|
-
factor: 1609.344,
|
|
83020
|
-
offset: 0
|
|
83021
|
-
},
|
|
83022
|
-
"m²": {
|
|
83023
|
-
dimension: "area",
|
|
83024
|
-
factor: 1,
|
|
83025
|
-
offset: 0
|
|
83026
|
-
},
|
|
83027
|
-
lx: {
|
|
83028
|
-
dimension: "illuminance",
|
|
83029
|
-
factor: 1,
|
|
83030
|
-
offset: 0
|
|
83031
|
-
},
|
|
83032
|
-
"W/m²": {
|
|
83033
|
-
dimension: "irradiance",
|
|
83034
|
-
factor: 1,
|
|
83035
|
-
offset: 0
|
|
83036
|
-
},
|
|
83037
|
-
W: {
|
|
83038
|
-
dimension: "power",
|
|
83039
|
-
factor: 1,
|
|
83040
|
-
offset: 0
|
|
83041
|
-
},
|
|
83042
|
-
kW: {
|
|
83043
|
-
dimension: "power",
|
|
83044
|
-
factor: 1e3,
|
|
83045
|
-
offset: 0
|
|
83046
|
-
},
|
|
83047
|
-
VA: {
|
|
83048
|
-
dimension: "apparent-power",
|
|
83049
|
-
factor: 1,
|
|
83050
|
-
offset: 0
|
|
83051
|
-
},
|
|
83052
|
-
Wh: {
|
|
83053
|
-
dimension: "energy",
|
|
83054
|
-
factor: 1,
|
|
83055
|
-
offset: 0
|
|
83056
|
-
},
|
|
83057
|
-
kWh: {
|
|
83058
|
-
dimension: "energy",
|
|
83059
|
-
factor: 1e3,
|
|
83060
|
-
offset: 0
|
|
83061
|
-
},
|
|
83062
|
-
MWh: {
|
|
83063
|
-
dimension: "energy",
|
|
83064
|
-
factor: 1e6,
|
|
83065
|
-
offset: 0
|
|
83066
|
-
},
|
|
83067
|
-
V: {
|
|
83068
|
-
dimension: "voltage",
|
|
83069
|
-
factor: 1,
|
|
83070
|
-
offset: 0
|
|
83071
|
-
},
|
|
83072
|
-
mV: {
|
|
83073
|
-
dimension: "voltage",
|
|
83074
|
-
factor: .001,
|
|
83075
|
-
offset: 0
|
|
83076
|
-
},
|
|
83077
|
-
A: {
|
|
83078
|
-
dimension: "current",
|
|
83079
|
-
factor: 1,
|
|
83080
|
-
offset: 0
|
|
83081
|
-
},
|
|
83082
|
-
mA: {
|
|
83083
|
-
dimension: "current",
|
|
83084
|
-
factor: .001,
|
|
83085
|
-
offset: 0
|
|
83086
|
-
},
|
|
83087
|
-
ppm: {
|
|
83088
|
-
dimension: "concentration-volume",
|
|
83089
|
-
factor: 1,
|
|
83090
|
-
offset: 0
|
|
83091
|
-
},
|
|
83092
|
-
ppb: {
|
|
83093
|
-
dimension: "concentration-volume",
|
|
83094
|
-
factor: .001,
|
|
83095
|
-
offset: 0
|
|
83096
|
-
},
|
|
83097
|
-
"µg/m³": {
|
|
83098
|
-
dimension: "concentration-mass",
|
|
83099
|
-
factor: 1,
|
|
83100
|
-
offset: 0
|
|
83101
|
-
},
|
|
83102
|
-
"mg/m³": {
|
|
83103
|
-
dimension: "concentration-mass",
|
|
83104
|
-
factor: 1e3,
|
|
83105
|
-
offset: 0
|
|
83106
|
-
},
|
|
83107
|
-
kg: {
|
|
83108
|
-
dimension: "mass",
|
|
83109
|
-
factor: 1,
|
|
83110
|
-
offset: 0
|
|
83111
|
-
},
|
|
83112
|
-
g: {
|
|
83113
|
-
dimension: "mass",
|
|
83114
|
-
factor: .001,
|
|
83115
|
-
offset: 0
|
|
83116
|
-
},
|
|
83117
|
-
lb: {
|
|
83118
|
-
dimension: "mass",
|
|
83119
|
-
factor: .453592,
|
|
83120
|
-
offset: 0
|
|
83121
|
-
},
|
|
83122
|
-
oz: {
|
|
83123
|
-
dimension: "mass",
|
|
83124
|
-
factor: .0283495,
|
|
83125
|
-
offset: 0
|
|
83126
|
-
},
|
|
83127
|
-
"%": {
|
|
83128
|
-
dimension: "percentage",
|
|
83129
|
-
factor: 1,
|
|
83130
|
-
offset: 0
|
|
83131
|
-
},
|
|
83132
|
-
L: {
|
|
83133
|
-
dimension: "volume",
|
|
83134
|
-
factor: 1,
|
|
83135
|
-
offset: 0
|
|
83136
|
-
},
|
|
83137
|
-
mL: {
|
|
83138
|
-
dimension: "volume",
|
|
83139
|
-
factor: .001,
|
|
83140
|
-
offset: 0
|
|
83141
|
-
},
|
|
83142
|
-
gal: {
|
|
83143
|
-
dimension: "volume",
|
|
83144
|
-
factor: 3.785411784,
|
|
83145
|
-
offset: 0
|
|
83146
|
-
},
|
|
83147
|
-
s: {
|
|
83148
|
-
dimension: "duration",
|
|
83149
|
-
factor: 1,
|
|
83150
|
-
offset: 0
|
|
83151
|
-
},
|
|
83152
|
-
ms: {
|
|
83153
|
-
dimension: "duration",
|
|
83154
|
-
factor: .001,
|
|
83155
|
-
offset: 0
|
|
83156
|
-
},
|
|
83157
|
-
min: {
|
|
83158
|
-
dimension: "duration",
|
|
83159
|
-
factor: 60,
|
|
83160
|
-
offset: 0
|
|
83161
|
-
},
|
|
83162
|
-
h: {
|
|
83163
|
-
dimension: "duration",
|
|
83164
|
-
factor: 3600,
|
|
83165
|
-
offset: 0
|
|
83166
|
-
},
|
|
83167
|
-
d: {
|
|
83168
|
-
dimension: "duration",
|
|
83169
|
-
factor: 86400,
|
|
83170
|
-
offset: 0
|
|
83171
|
-
},
|
|
83172
|
-
B: {
|
|
83173
|
-
dimension: "information",
|
|
83174
|
-
factor: 1,
|
|
83175
|
-
offset: 0
|
|
83176
|
-
},
|
|
83177
|
-
KiB: {
|
|
83178
|
-
dimension: "information",
|
|
83179
|
-
factor: 1024,
|
|
83180
|
-
offset: 0
|
|
83181
|
-
},
|
|
83182
|
-
MiB: {
|
|
83183
|
-
dimension: "information",
|
|
83184
|
-
factor: 1024 ** 2,
|
|
83185
|
-
offset: 0
|
|
83186
|
-
},
|
|
83187
|
-
GiB: {
|
|
83188
|
-
dimension: "information",
|
|
83189
|
-
factor: 1024 ** 3,
|
|
83190
|
-
offset: 0
|
|
83191
|
-
},
|
|
83192
|
-
TiB: {
|
|
83193
|
-
dimension: "information",
|
|
83194
|
-
factor: 1024 ** 4,
|
|
83195
|
-
offset: 0
|
|
83196
|
-
},
|
|
83197
|
-
kB: {
|
|
83198
|
-
dimension: "information",
|
|
83199
|
-
factor: 1e3,
|
|
83200
|
-
offset: 0
|
|
83201
|
-
},
|
|
83202
|
-
MB: {
|
|
83203
|
-
dimension: "information",
|
|
83204
|
-
factor: 1e6,
|
|
83205
|
-
offset: 0
|
|
83206
|
-
},
|
|
83207
|
-
GB: {
|
|
83208
|
-
dimension: "information",
|
|
83209
|
-
factor: 1e9,
|
|
83210
|
-
offset: 0
|
|
83211
|
-
},
|
|
83212
|
-
"°": {
|
|
83213
|
-
dimension: "angle",
|
|
83214
|
-
factor: 1,
|
|
83215
|
-
offset: 0
|
|
83216
|
-
},
|
|
83217
|
-
dBFS: {
|
|
83218
|
-
dimension: "sound-level",
|
|
83219
|
-
factor: 1,
|
|
83220
|
-
offset: 0
|
|
83221
|
-
},
|
|
83222
|
-
dBm: {
|
|
83223
|
-
dimension: "signal-level",
|
|
83224
|
-
factor: 1,
|
|
83225
|
-
offset: 0
|
|
83226
|
-
},
|
|
83227
|
-
mired: {
|
|
83228
|
-
dimension: "colour-temperature",
|
|
83229
|
-
factor: 1,
|
|
83230
|
-
offset: 0
|
|
83231
|
-
},
|
|
83232
|
-
kbps: {
|
|
83233
|
-
dimension: "bitrate",
|
|
83234
|
-
factor: 1,
|
|
83235
|
-
offset: 0
|
|
83236
|
-
},
|
|
83237
|
-
Mbps: {
|
|
83238
|
-
dimension: "bitrate",
|
|
83239
|
-
factor: 1e3,
|
|
83240
|
-
offset: 0
|
|
83241
|
-
},
|
|
83242
|
-
fps: {
|
|
83243
|
-
dimension: "rate",
|
|
83244
|
-
factor: 1,
|
|
83245
|
-
offset: 0
|
|
83246
|
-
}
|
|
83247
|
-
};
|
|
83248
|
-
//#endregion
|
|
83249
|
-
//#region src/units/convert.ts
|
|
83250
|
-
/**
|
|
83251
|
-
* Pure unit-conversion API over `UNIT_TABLE`. No dependencies, no side effects.
|
|
83252
|
-
*
|
|
83253
|
-
* Conversion is refused (throws `UnitConversionError`, or returns `undefined`
|
|
83254
|
-
* from the `try*` variant) whenever a unit is unknown or the two units belong
|
|
83255
|
-
* to different dimensions — cross-dimension conversion is deliberately
|
|
83256
|
-
* impossible so a render override can never make the value and its unit label
|
|
83257
|
-
* disagree.
|
|
83258
|
-
*
|
|
83259
|
-
* Callers pass units through `normalizeUnit` (`../device/source-info.ts`) BEFORE
|
|
83260
|
-
* calling here — the table keys only canonical spellings.
|
|
83261
|
-
*/
|
|
83262
|
-
/** Thrown by `convertUnit` when a conversion is refused. Carries the offending
|
|
83263
|
-
* units + a machine-readable `reason` for callers that branch on the cause. */
|
|
83264
|
-
var UnitConversionError = class extends Error {
|
|
83265
|
-
from;
|
|
83266
|
-
to;
|
|
83267
|
-
reason;
|
|
83268
|
-
constructor(from, to, reason) {
|
|
83269
|
-
super(`[units] cannot convert '${from}' → '${to}': ${reason}`);
|
|
83270
|
-
this.name = "UnitConversionError";
|
|
83271
|
-
this.from = from;
|
|
83272
|
-
this.to = to;
|
|
83273
|
-
this.reason = reason;
|
|
83274
|
-
}
|
|
83275
|
-
};
|
|
83276
|
-
/** Resolve a unit's `UnitSpec`, or `undefined` when the spelling is unknown. */
|
|
83277
|
-
function specFor(unit) {
|
|
83278
|
-
return Object.hasOwn(UNIT_TABLE, unit) ? UNIT_TABLE[unit] : void 0;
|
|
83279
|
-
}
|
|
83280
|
-
/** The dimension a unit belongs to, or `undefined` for an unknown unit. */
|
|
83281
|
-
function unitDimension(unit) {
|
|
83282
|
-
return specFor(unit)?.dimension;
|
|
83283
|
-
}
|
|
83284
|
-
/** Value in `spec`'s unit → its dimension's canonical unit. */
|
|
83285
|
-
function toCanonical(value, spec) {
|
|
83286
|
-
return value * spec.factor + spec.offset;
|
|
83287
|
-
}
|
|
83288
|
-
/** Canonical-unit value → the unit described by `spec`. */
|
|
83289
|
-
function fromCanonical(canonical, spec) {
|
|
83290
|
-
return (canonical - spec.offset) / spec.factor;
|
|
83291
|
-
}
|
|
83292
|
-
/**
|
|
83293
|
-
* Convert `value` from unit `from` to unit `to`. Identity when `from === to`.
|
|
83294
|
-
* Throws `UnitConversionError` when either unit is unknown or the units belong
|
|
83295
|
-
* to different dimensions.
|
|
83296
|
-
*/
|
|
83297
|
-
function convertUnit(value, from, to) {
|
|
83298
|
-
if (from === to) return value;
|
|
83299
|
-
const fromSpec = specFor(from);
|
|
83300
|
-
if (!fromSpec) throw new UnitConversionError(from, to, "unknown-from");
|
|
83301
|
-
const toSpec = specFor(to);
|
|
83302
|
-
if (!toSpec) throw new UnitConversionError(from, to, "unknown-to");
|
|
83303
|
-
if (fromSpec.dimension !== toSpec.dimension) throw new UnitConversionError(from, to, "cross-dimension");
|
|
83304
|
-
return fromCanonical(toCanonical(value, fromSpec), toSpec);
|
|
83305
|
-
}
|
|
83306
|
-
/**
|
|
83307
|
-
* Graceful variant for the render path: returns the converted value, or
|
|
83308
|
-
* `undefined` when the conversion is refused (unknown unit / cross-dimension).
|
|
83309
|
-
* Never throws — a render caller falls back to the raw value + source unit.
|
|
83310
|
-
*/
|
|
83311
|
-
function tryConvertUnit(value, from, to) {
|
|
83312
|
-
if (from === to) return value;
|
|
83313
|
-
const fromSpec = specFor(from);
|
|
83314
|
-
if (!fromSpec) return void 0;
|
|
83315
|
-
const toSpec = specFor(to);
|
|
83316
|
-
if (!toSpec) return void 0;
|
|
83317
|
-
if (fromSpec.dimension !== toSpec.dimension) return void 0;
|
|
83318
|
-
return fromCanonical(toCanonical(value, fromSpec), toSpec);
|
|
83319
|
-
}
|
|
83320
|
-
/**
|
|
83321
|
-
* Whether `value` can be converted between `from` and `to` (same dimension,
|
|
83322
|
-
* both known). Cheap boolean probe for the UI's same-dimension unit picker and
|
|
83323
|
-
* the resolver's convertibility branch — compute ONCE so a unit label and its
|
|
83324
|
-
* value math can never disagree.
|
|
83325
|
-
*/
|
|
83326
|
-
function canConvertUnit(from, to) {
|
|
83327
|
-
if (from === to) return true;
|
|
83328
|
-
const fromDim = unitDimension(from);
|
|
83329
|
-
if (fromDim === void 0) return false;
|
|
83330
|
-
return fromDim === unitDimension(to);
|
|
83331
|
-
}
|
|
83332
|
-
/**
|
|
83333
|
-
* Every known unit spelling in a dimension (table insertion order — canonical
|
|
83334
|
-
* unit first). Powers the UI's same-dimension unit picker.
|
|
83335
|
-
*/
|
|
83336
|
-
/**
|
|
83337
|
-
* Convert a difference, not a reading. Affine units (°F) shift an absolute
|
|
83338
|
-
* value by their offset; a step of 1°F is 5/9°C, so the offset is cancelled.
|
|
83339
|
-
*/
|
|
83340
|
-
function tryConvertDelta(value, from, to) {
|
|
83341
|
-
if (from === to) return value;
|
|
83342
|
-
const origin = tryConvertUnit(0, from, to);
|
|
83343
|
-
const shifted = tryConvertUnit(value, from, to);
|
|
83344
|
-
if (origin === void 0 || shifted === void 0) return void 0;
|
|
83345
|
-
return shifted - origin;
|
|
83346
|
-
}
|
|
83347
|
-
function unitsForDimension(dimension) {
|
|
83348
|
-
const out = [];
|
|
83349
|
-
for (const [unit, spec] of Object.entries(UNIT_TABLE)) if (spec.dimension === dimension) out.push(unit);
|
|
83350
|
-
return out;
|
|
83351
|
-
}
|
|
83352
|
-
//#endregion
|
|
83353
84351
|
//#region src/composition/evaluate-field.ts
|
|
83354
84352
|
/**
|
|
83355
84353
|
* One composed field, evaluated from what its sources say NOW (D659).
|
|
@@ -96616,6 +97614,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
96616
97614
|
access: "create",
|
|
96617
97615
|
role: "admin"
|
|
96618
97616
|
},
|
|
97617
|
+
"remoteLayoutComponents.listComponents": {
|
|
97618
|
+
capName: "remote-layout-components",
|
|
97619
|
+
capScope: "system",
|
|
97620
|
+
addonId: null,
|
|
97621
|
+
access: "view",
|
|
97622
|
+
role: "admin"
|
|
97623
|
+
},
|
|
96619
97624
|
"runningState.getStatus": {
|
|
96620
97625
|
capName: "running-state",
|
|
96621
97626
|
capScope: "device",
|
|
@@ -98979,6 +99984,7 @@ var KNOWN_CAP_NAMES = [
|
|
|
98979
99984
|
"recording-signal",
|
|
98980
99985
|
"records",
|
|
98981
99986
|
"remote",
|
|
99987
|
+
"remote-layout-components",
|
|
98982
99988
|
"running-state",
|
|
98983
99989
|
"scene-monitor",
|
|
98984
99990
|
"script-runner",
|
|
@@ -99199,6 +100205,7 @@ var SYSTEM_CAP_NAMES = [
|
|
|
99199
100205
|
"recording-export",
|
|
99200
100206
|
"records",
|
|
99201
100207
|
"remote",
|
|
100208
|
+
"remote-layout-components",
|
|
99202
100209
|
"server-management",
|
|
99203
100210
|
"settings-store",
|
|
99204
100211
|
"smtp-provider",
|
|
@@ -101058,7 +102065,8 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
101058
102065
|
min: 4,
|
|
101059
102066
|
max: 200,
|
|
101060
102067
|
step: 1,
|
|
101061
|
-
unit: "g"
|
|
102068
|
+
unit: "g",
|
|
102069
|
+
quantity: "mass"
|
|
101062
102070
|
},
|
|
101063
102071
|
optional: true
|
|
101064
102072
|
}]
|
|
@@ -101077,7 +102085,8 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
101077
102085
|
min: 4,
|
|
101078
102086
|
max: 200,
|
|
101079
102087
|
step: 1,
|
|
101080
|
-
unit: "g"
|
|
102088
|
+
unit: "g",
|
|
102089
|
+
quantity: "mass"
|
|
101081
102090
|
},
|
|
101082
102091
|
optional: true
|
|
101083
102092
|
}, {
|
|
@@ -101088,7 +102097,8 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
101088
102097
|
min: 4,
|
|
101089
102098
|
max: 200,
|
|
101090
102099
|
step: 1,
|
|
101091
|
-
unit: "g"
|
|
102100
|
+
unit: "g",
|
|
102101
|
+
quantity: "mass"
|
|
101092
102102
|
},
|
|
101093
102103
|
optional: true
|
|
101094
102104
|
}]
|
|
@@ -103194,6 +104204,7 @@ var SYSTEM_CAP_VOCABULARY = {
|
|
|
103194
104204
|
"recording-export": system("recording exports — requested from the timeline, not an automation step"),
|
|
103195
104205
|
records: system(INTERNAL),
|
|
103196
104206
|
remote: system("the per-device remote setup — authored in the Customize remote editor, sent through the remote UI"),
|
|
104207
|
+
"remote-layout-components": system("the palette of the remote template editor — read-only data, never actuated"),
|
|
103197
104208
|
"server-management": system(CLUSTER),
|
|
103198
104209
|
"settings-store": system(INTERNAL),
|
|
103199
104210
|
"smtp-provider": system(INTERNAL),
|
|
@@ -105181,6 +106192,7 @@ var CAPABILITY_NAMES = {
|
|
|
105181
106192
|
recordingSignal: "recording-signal",
|
|
105182
106193
|
records: "records",
|
|
105183
106194
|
remote: "remote",
|
|
106195
|
+
remoteLayoutComponents: "remote-layout-components",
|
|
105184
106196
|
runningState: "running-state",
|
|
105185
106197
|
sceneMonitor: "scene-monitor",
|
|
105186
106198
|
scriptRunner: "script-runner",
|
|
@@ -105820,6 +106832,10 @@ var CAPABILITY_ROUTER_KEYS = [
|
|
|
105820
106832
|
key: "remote",
|
|
105821
106833
|
name: "remote"
|
|
105822
106834
|
},
|
|
106835
|
+
{
|
|
106836
|
+
key: "remoteLayoutComponents",
|
|
106837
|
+
name: "remote-layout-components"
|
|
106838
|
+
},
|
|
105823
106839
|
{
|
|
105824
106840
|
key: "runningState",
|
|
105825
106841
|
name: "running-state"
|
|
@@ -106155,6 +107171,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
|
|
|
106155
107171
|
recordingSignalCapability,
|
|
106156
107172
|
recordsCapability,
|
|
106157
107173
|
remoteCapability,
|
|
107174
|
+
remoteLayoutComponentsCapability,
|
|
106158
107175
|
runningStateCapability,
|
|
106159
107176
|
sceneMonitorCapability,
|
|
106160
107177
|
scriptRunnerCapability,
|
|
@@ -110945,6 +111962,7 @@ function createSystemProxy(api) {
|
|
|
110945
111962
|
sendCommand: (input) => dispatch("remote", "sendCommand", "mutation", input),
|
|
110946
111963
|
sendMediaCommand: (input) => dispatch("remote", "sendMediaCommand", "mutation", input)
|
|
110947
111964
|
},
|
|
111965
|
+
remoteLayoutComponents: { listComponents: (input) => dispatch("remoteLayoutComponents", "listComponents", "query", input) },
|
|
110948
111966
|
serverManagement: {
|
|
110949
111967
|
getServerPackageStatus: (input) => dispatch("serverManagement", "getServerPackageStatus", "query", input),
|
|
110950
111968
|
checkServerUpdate: (input) => dispatch("serverManagement", "checkServerUpdate", "mutation", input),
|
|
@@ -115180,8 +116198,6 @@ var NC_TEMPLATE_VARS = [
|
|
|
115180
116198
|
* delete it from here then, and the served catalog names it again.
|
|
115181
116199
|
*/
|
|
115182
116200
|
var NC_TEMPLATE_HELD_BACK_SYSTEM_EVENT_KINDS = [
|
|
115183
|
-
"node-restarting",
|
|
115184
|
-
"node-updating",
|
|
115185
116201
|
"alert-critical",
|
|
115186
116202
|
"alert-error",
|
|
115187
116203
|
"alert-critical-resolved",
|
|
@@ -122025,6 +123041,7 @@ exports.BENCH_ROOT_STEP_ID = BENCH_ROOT_STEP_ID;
|
|
|
122025
123041
|
exports.BINARY_AGGREGATES = require_composition.BINARY_AGGREGATES;
|
|
122026
123042
|
exports.BIRTH_DECISION_DEFAULT_LIMIT = BIRTH_DECISION_DEFAULT_LIMIT;
|
|
122027
123043
|
exports.BOOT_RECOVERY_BACKOFF_MS = require_sleep.BOOT_RECOVERY_BACKOFF_MS;
|
|
123044
|
+
exports.BUILTIN_REMOTE_COMPONENTS = BUILTIN_REMOTE_COMPONENTS;
|
|
122028
123045
|
exports.BUILTIN_RESULT_KINDS = BUILTIN_RESULT_KINDS;
|
|
122029
123046
|
exports.BackgroundRunRegistry = BackgroundRunRegistry;
|
|
122030
123047
|
exports.BacklightModeSchema = BacklightModeSchema;
|
|
@@ -122753,6 +123770,7 @@ exports.KeychainWriteRefusedError = require_sleep.KeychainWriteRefusedError;
|
|
|
122753
123770
|
exports.LABEL_SUPPLY_MACRO = LABEL_SUPPLY_MACRO;
|
|
122754
123771
|
exports.LABEL_SUPPLY_STEP_IDS = LABEL_SUPPLY_STEP_IDS;
|
|
122755
123772
|
exports.LABEL_SUPPLY_VOCABULARIES = LABEL_SUPPLY_VOCABULARIES;
|
|
123773
|
+
exports.LAYOUT_EDIT_REFUSALS = LAYOUT_EDIT_REFUSALS;
|
|
122756
123774
|
exports.LEGACY_READ_ONLY_CONFIG_KEY = LEGACY_READ_ONLY_CONFIG_KEY;
|
|
122757
123775
|
exports.LIGHT_SHARED_CAPS = LIGHT_SHARED_CAPS;
|
|
122758
123776
|
exports.LINKED_DEVICES_SLOT = LINKED_DEVICES_SLOT;
|
|
@@ -122859,6 +123877,7 @@ exports.MAX_BIRTH_LATENCY_PROXY_MS = MAX_BIRTH_LATENCY_PROXY_MS;
|
|
|
122859
123877
|
exports.MAX_CAMERA_SENSORS = MAX_CAMERA_SENSORS;
|
|
122860
123878
|
exports.MAX_CLIP_EVENT_IDS = MAX_CLIP_EVENT_IDS;
|
|
122861
123879
|
exports.MAX_CLIP_LABELS = MAX_CLIP_LABELS;
|
|
123880
|
+
exports.MAX_COMPONENT_BUTTONS = MAX_COMPONENT_BUTTONS;
|
|
122862
123881
|
exports.MAX_COMPOSITION_CODE_LENGTH = require_composition.MAX_COMPOSITION_CODE_LENGTH;
|
|
122863
123882
|
exports.MAX_COMPOSITION_FEATURES = require_composition.MAX_COMPOSITION_FEATURES;
|
|
122864
123883
|
exports.MAX_COMPOSITION_FIELDS_PER_FEATURE = require_composition.MAX_COMPOSITION_FIELDS_PER_FEATURE;
|
|
@@ -122872,6 +123891,7 @@ exports.MAX_EXPRESSION_EVAL_STEPS = require_composition.MAX_EXPRESSION_EVAL_STEP
|
|
|
122872
123891
|
exports.MAX_EXPRESSION_SOURCE_LENGTH = require_composition.MAX_EXPRESSION_SOURCE_LENGTH;
|
|
122873
123892
|
exports.MAX_HELPER_MEMBERS = require_composition.MAX_HELPER_MEMBERS;
|
|
122874
123893
|
exports.MAX_KEYS = MAX_KEYS;
|
|
123894
|
+
exports.MAX_LAYOUT_GROUPS = MAX_LAYOUT_GROUPS;
|
|
122875
123895
|
exports.MAX_LAYOUT_SPAN = MAX_LAYOUT_SPAN;
|
|
122876
123896
|
exports.MAX_REASONS_PER_KEY = MAX_REASONS_PER_KEY;
|
|
122877
123897
|
exports.MAX_REMOTE_BINDINGS = MAX_REMOTE_BINDINGS;
|
|
@@ -123395,6 +124415,8 @@ exports.PtzPresetFunctionSchema = PtzPresetFunctionSchema;
|
|
|
123395
124415
|
exports.PtzPresetSchema = PtzPresetSchema;
|
|
123396
124416
|
exports.PtzStatusSchema = PtzStatusSchema;
|
|
123397
124417
|
exports.QUANTITY_BASE = require_sleep.QUANTITY_BASE;
|
|
124418
|
+
exports.QuantityUnitError = QuantityUnitError;
|
|
124419
|
+
exports.QuantityValueSchema = QuantityValueSchema;
|
|
123398
124420
|
exports.QueryFilterSchema = QueryFilterSchema;
|
|
123399
124421
|
exports.RATE_CONTROL_RELAXED = RATE_CONTROL_RELAXED;
|
|
123400
124422
|
exports.RATE_CONTROL_TIGHT = RATE_CONTROL_TIGHT;
|
|
@@ -123438,8 +124460,12 @@ exports.RECOVERY_VIEW_PX = RECOVERY_VIEW_PX;
|
|
|
123438
124460
|
exports.REDACTED_SECRET = require_sleep.REDACTED_SECRET;
|
|
123439
124461
|
exports.REFERENCE_COMPUTE = REFERENCE_COMPUTE;
|
|
123440
124462
|
exports.REFERENCE_MATCH_FRACTION = REFERENCE_MATCH_FRACTION;
|
|
124463
|
+
exports.REMOTE_BUTTON_SHAPES = REMOTE_BUTTON_SHAPES;
|
|
124464
|
+
exports.REMOTE_BUTTON_TONES = REMOTE_BUTTON_TONES;
|
|
124465
|
+
exports.REMOTE_COMPONENT_CATEGORIES = REMOTE_COMPONENT_CATEGORIES;
|
|
123441
124466
|
exports.REMOTE_CONFIG_REFUSALS = REMOTE_CONFIG_REFUSALS;
|
|
123442
124467
|
exports.REMOTE_CUSTOM_ROLE_PREFIX = REMOTE_CUSTOM_ROLE_PREFIX;
|
|
124468
|
+
exports.REMOTE_GROUP_FRAMES = REMOTE_GROUP_FRAMES;
|
|
123443
124469
|
exports.REMOTE_KNOWN_ROLES = REMOTE_KNOWN_ROLES;
|
|
123444
124470
|
exports.REMOTE_MAX_REPEAT = REMOTE_MAX_REPEAT;
|
|
123445
124471
|
exports.REMOTE_MEDIA_COMMANDS = REMOTE_MEDIA_COMMANDS;
|
|
@@ -123558,10 +124584,17 @@ exports.RemoteAssumedStateSchema = RemoteAssumedStateSchema;
|
|
|
123558
124584
|
exports.RemoteBindingActionSchema = RemoteBindingActionSchema;
|
|
123559
124585
|
exports.RemoteBindingSchema = RemoteBindingSchema;
|
|
123560
124586
|
exports.RemoteBoundCommandSchema = RemoteBoundCommandSchema;
|
|
124587
|
+
exports.RemoteButtonShapeSchema = RemoteButtonShapeSchema;
|
|
124588
|
+
exports.RemoteButtonToneSchema = RemoteButtonToneSchema;
|
|
123561
124589
|
exports.RemoteCommandListSchema = RemoteCommandListSchema;
|
|
124590
|
+
exports.RemoteComponentButtonSchema = RemoteComponentButtonSchema;
|
|
124591
|
+
exports.RemoteComponentCategorySchema = RemoteComponentCategorySchema;
|
|
123562
124592
|
exports.RemoteConfigSchema = RemoteConfigSchema;
|
|
123563
124593
|
exports.RemoteCustomButtonSchema = RemoteCustomButtonSchema;
|
|
124594
|
+
exports.RemoteGroupFrameSchema = RemoteGroupFrameSchema;
|
|
123564
124595
|
exports.RemoteLayoutButtonSchema = RemoteLayoutButtonSchema;
|
|
124596
|
+
exports.RemoteLayoutComponentSchema = RemoteLayoutComponentSchema;
|
|
124597
|
+
exports.RemoteLayoutGroupSchema = RemoteLayoutGroupSchema;
|
|
123565
124598
|
exports.RemoteLayoutPayloadSchema = RemoteLayoutPayloadSchema;
|
|
123566
124599
|
exports.RemoteMediaCommandResultSchema = RemoteMediaCommandResultSchema;
|
|
123567
124600
|
exports.RemoteMediaCommandSchema = RemoteMediaCommandSchema;
|
|
@@ -123937,6 +124970,7 @@ exports.UninstallNodeOutcomeSchema = UninstallNodeOutcomeSchema;
|
|
|
123937
124970
|
exports.UninstallNodeResultSchema = UninstallNodeResultSchema;
|
|
123938
124971
|
exports.UninstallPackageResultSchema = UninstallPackageResultSchema;
|
|
123939
124972
|
exports.UnitConversionError = UnitConversionError;
|
|
124973
|
+
exports.UnitWarningSchema = UnitWarningSchema;
|
|
123940
124974
|
exports.UnknownRecordKindError = require_sleep.UnknownRecordKindError;
|
|
123941
124975
|
exports.UnreleasedClaimSchema = UnreleasedClaimSchema;
|
|
123942
124976
|
exports.UnstampedEventMediaCountSchema = UnstampedEventMediaCountSchema;
|
|
@@ -124100,6 +125134,7 @@ exports.autoAssignProfiles = autoAssignProfiles;
|
|
|
124100
125134
|
exports.automationControlCapability = automationControlCapability;
|
|
124101
125135
|
exports.backupCapability = backupCapability;
|
|
124102
125136
|
exports.bareAddonId = bareAddonId;
|
|
125137
|
+
exports.baseUnitForQuantity = baseUnitForQuantity;
|
|
124103
125138
|
exports.baseUnitOf = require_sleep.baseUnitOf;
|
|
124104
125139
|
exports.batteryCapability = batteryCapability;
|
|
124105
125140
|
exports.bestLocationMatch = bestLocationMatch;
|
|
@@ -124131,6 +125166,7 @@ exports.buildTriggerTrace = buildTriggerTrace;
|
|
|
124131
125166
|
exports.buildVideoArgs = require_composition.buildVideoArgs;
|
|
124132
125167
|
exports.buildViewerLink = buildViewerLink;
|
|
124133
125168
|
exports.builtCapabilityBlockers = builtCapabilityBlockers;
|
|
125169
|
+
exports.builtinRemoteComponent = builtinRemoteComponent;
|
|
124134
125170
|
exports.bundledCamstack = bundledCamstack;
|
|
124135
125171
|
exports.buttonCapability = buttonCapability;
|
|
124136
125172
|
exports.calendarEventLocalSpan = calendarEventLocalSpan;
|
|
@@ -124148,6 +125184,7 @@ exports.canConvertUnit = canConvertUnit;
|
|
|
124148
125184
|
exports.canonicalEgressPlan = canonicalEgressPlan;
|
|
124149
125185
|
exports.canonicalIconKey = canonicalIconKey;
|
|
124150
125186
|
exports.canonicalizeAppCallback = canonicalizeAppCallback;
|
|
125187
|
+
exports.capUnitResolver = capUnitResolver;
|
|
124151
125188
|
exports.capabilityScopesOf = capabilityScopesOf;
|
|
124152
125189
|
exports.capacityForModel = capacityForModel;
|
|
124153
125190
|
exports.capacitySessionsOf = capacitySessionsOf;
|
|
@@ -124230,6 +125267,7 @@ exports.contactCapability = contactCapability;
|
|
|
124230
125267
|
exports.containingParentIndex = containingParentIndex;
|
|
124231
125268
|
exports.controlCapability = controlCapability;
|
|
124232
125269
|
exports.convertPresetFeature = convertPresetFeature;
|
|
125270
|
+
exports.convertQuantityInput = convertQuantityInput;
|
|
124233
125271
|
exports.convertUnit = convertUnit;
|
|
124234
125272
|
exports.convertUnitTargets = convertUnitTargets;
|
|
124235
125273
|
exports.coralUsableUnits = coralUsableUnits;
|
|
@@ -124418,6 +125456,7 @@ exports.fieldReads = require_composition.fieldReads;
|
|
|
124418
125456
|
exports.fieldUnitKeys = fieldUnitKeys;
|
|
124419
125457
|
exports.fieldsPinnedAtValueBelow = fieldsPinnedAtValueBelow;
|
|
124420
125458
|
exports.filesystemBrowseCapability = filesystemBrowseCapability;
|
|
125459
|
+
exports.fillWidthScale = fillWidthScale;
|
|
124421
125460
|
exports.findCandidateCycles = findCandidateCycles;
|
|
124422
125461
|
exports.findCompositionCycles = findCompositionCycles;
|
|
124423
125462
|
exports.findTimezone = findTimezone;
|
|
@@ -124482,6 +125521,7 @@ exports.inferExpressionKinds = inferExpressionKinds;
|
|
|
124482
125521
|
exports.inferModelProvider = inferModelProvider;
|
|
124483
125522
|
exports.ingestReading = ingestReading;
|
|
124484
125523
|
exports.initialPoolMemoryState = initialPoolMemoryState;
|
|
125524
|
+
exports.insertComponent = insertComponent;
|
|
124485
125525
|
exports.integralCadenceMs = require_composition.integralCadenceMs;
|
|
124486
125526
|
exports.integralDraft = integralDraft;
|
|
124487
125527
|
exports.integrateReading = require_composition.integrateReading;
|
|
@@ -124545,6 +125585,7 @@ exports.isObjectInput = isObjectInput;
|
|
|
124545
125585
|
exports.isOccupancyRule = isOccupancyRule;
|
|
124546
125586
|
exports.isOwnerOnlyEventCategory = require_event_category.isOwnerOnlyEventCategory;
|
|
124547
125587
|
exports.isPlugApplianceType = isPlugApplianceType;
|
|
125588
|
+
exports.isQuantityValue = isQuantityValue;
|
|
124548
125589
|
exports.isReadingQuantity = require_sleep.isReadingQuantity;
|
|
124549
125590
|
exports.isRemoteCustomKey = isRemoteCustomKey;
|
|
124550
125591
|
exports.isRemoteKnownRole = isRemoteKnownRole;
|
|
@@ -124660,6 +125701,7 @@ exports.motionDetectionCapability = motionDetectionCapability;
|
|
|
124660
125701
|
exports.motionSourceLabel = motionSourceLabel;
|
|
124661
125702
|
exports.motionTriggerCapability = motionTriggerCapability;
|
|
124662
125703
|
exports.motionZonesCapability = motionZonesCapability;
|
|
125704
|
+
exports.moveGroup = moveGroup;
|
|
124663
125705
|
exports.mqttBrokerCapability = mqttBrokerCapability;
|
|
124664
125706
|
exports.nativeObjectDetectionCapability = nativeObjectDetectionCapability;
|
|
124665
125707
|
exports.navigationCapability = navigationCapability;
|
|
@@ -124675,12 +125717,15 @@ exports.nodePickerItems = nodePickerItems;
|
|
|
124675
125717
|
exports.nodePin = require_sleep.nodePin;
|
|
124676
125718
|
exports.nodeRemovalHookCapability = nodeRemovalHookCapability;
|
|
124677
125719
|
exports.nodesCapability = nodesCapability;
|
|
125720
|
+
exports.normalizeActionUnits = normalizeActionUnits;
|
|
124678
125721
|
exports.normalizeAddonInitResult = require_sleep.normalizeAddonInitResult;
|
|
124679
125722
|
exports.normalizeAudioLabel = normalizeAudioLabel;
|
|
125723
|
+
exports.normalizeConditionUnits = normalizeConditionUnits;
|
|
124680
125724
|
exports.normalizeCoreBlockWrite = normalizeCoreBlockWrite;
|
|
124681
125725
|
exports.normalizeNcMediaPolicy = normalizeNcMediaPolicy;
|
|
124682
125726
|
exports.normalizeNodeId = require_sleep.normalizeNodeId;
|
|
124683
125727
|
exports.normalizeOrigin = normalizeOrigin;
|
|
125728
|
+
exports.normalizeRecipeUnits = normalizeRecipeUnits;
|
|
124684
125729
|
exports.normalizeSecretOwner = require_sleep.normalizeSecretOwner;
|
|
124685
125730
|
exports.normalizeTokenScopes = normalizeTokenScopes;
|
|
124686
125731
|
exports.normalizeUnit = normalizeUnit;
|
|
@@ -124712,6 +125757,8 @@ exports.paletteFromStored = paletteFromStored;
|
|
|
124712
125757
|
exports.paletteLegend = paletteLegend;
|
|
124713
125758
|
exports.paletteResultSchema = paletteResultSchema;
|
|
124714
125759
|
exports.paletteSwatchSchema = paletteSwatchSchema;
|
|
125760
|
+
exports.paramMeta = paramMeta;
|
|
125761
|
+
exports.paramMetaOf = paramMetaOf;
|
|
124715
125762
|
exports.parseAcceleratorFactsJson = parseAcceleratorFactsJson;
|
|
124716
125763
|
exports.parseAdminBase = parseAdminBase;
|
|
124717
125764
|
exports.parseAlertEpisodePayload = parseAlertEpisodePayload;
|
|
@@ -124833,12 +125880,16 @@ exports.recordingOnboardCapability = recordingOnboardCapability;
|
|
|
124833
125880
|
exports.recordingSignalCapability = recordingSignalCapability;
|
|
124834
125881
|
exports.recordsCapability = recordsCapability;
|
|
124835
125882
|
exports.recordsErrorFromMessage = require_sleep.recordsErrorFromMessage;
|
|
125883
|
+
exports.rectContains = rectContains;
|
|
125884
|
+
exports.rectsOverlap = rectsOverlap;
|
|
124836
125885
|
exports.rectsToCells = rectsToCells;
|
|
124837
125886
|
exports.reducePoints = reducePoints;
|
|
124838
125887
|
exports.reducerForActive = reducerForActive;
|
|
124839
125888
|
exports.registerKnownSecret = require_sleep.registerKnownSecret;
|
|
124840
125889
|
exports.remapCropDetections = remapCropDetections;
|
|
124841
125890
|
exports.remoteCapability = remoteCapability;
|
|
125891
|
+
exports.remoteLayoutComponentsCapability = remoteLayoutComponentsCapability;
|
|
125892
|
+
exports.removeGroup = removeGroup;
|
|
124842
125893
|
exports.removeScalarTarget = removeScalarTarget;
|
|
124843
125894
|
exports.renameAlarmProfile = renameAlarmProfile;
|
|
124844
125895
|
exports.renderVocabPhrase = renderVocabPhrase;
|
|
@@ -125094,9 +126145,11 @@ exports.transformSecretWrite = require_sleep.transformSecretWrite;
|
|
|
125094
126145
|
exports.tryConvertDelta = tryConvertDelta;
|
|
125095
126146
|
exports.tryConvertUnit = tryConvertUnit;
|
|
125096
126147
|
exports.turnProviderCapability = turnProviderCapability;
|
|
126148
|
+
exports.ungroup = ungroup;
|
|
125097
126149
|
exports.unitCompanionField = unitCompanionField;
|
|
125098
126150
|
exports.unitDimension = unitDimension;
|
|
125099
126151
|
exports.unitsForDimension = unitsForDimension;
|
|
126152
|
+
exports.unitsForQuantity = unitsForQuantity;
|
|
125100
126153
|
exports.unreachableExtensionSlotRow = unreachableExtensionSlotRow;
|
|
125101
126154
|
exports.unwrapSchema = unwrapSchema;
|
|
125102
126155
|
exports.updateCapability = updateCapability;
|