@camstack/types 1.2.445 → 1.2.447
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 +12 -0
- 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 +1 -1
- package/dist/capabilities/remote.cap.d.ts +2 -0
- package/dist/capabilities/server-management.cap.d.ts +97 -6
- package/dist/client.js +1 -0
- package/dist/client.mjs +1 -0
- package/dist/device/cap-vocabulary/types.d.ts +9 -1
- package/dist/generated/addon-api.d.ts +7 -0
- package/dist/generated/method-access-map.d.ts +1 -1
- package/dist/generated/system-proxy.d.ts +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1167 -734
- package/dist/index.mjs +1152 -735
- package/dist/remote/remote-config.d.ts +3 -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
|
@@ -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 /
|
|
@@ -60184,11 +60964,13 @@ var WrapperEvidenceSchema = zod.z.object({
|
|
|
60184
60964
|
* The shell verdict (see {@link WrapperKindSchema}) with the proofs that
|
|
60185
60965
|
* produced it.
|
|
60186
60966
|
*
|
|
60187
|
-
* There is deliberately NO `canSelfUpdate`
|
|
60188
|
-
*
|
|
60189
|
-
*
|
|
60190
|
-
*
|
|
60191
|
-
*
|
|
60967
|
+
* There is deliberately NO `canSelfUpdate` boolean: a wrapper update is an
|
|
60968
|
+
* ANNOUNCEMENT. The notification body carries the exact command for a `docker`
|
|
60969
|
+
* shell and says the app restarts into the new build for `electron`, and that
|
|
60970
|
+
* sentence is chosen from `kind` alone — a boolean nothing reads is the defect
|
|
60971
|
+
* this repo keeps paying for. The one shell that CAN be acted on is the
|
|
60972
|
+
* Electron app, and only through `installDesktopUpdate` (see
|
|
60973
|
+
* {@link DesktopAppStatusSchema} for what the node reads from the app first).
|
|
60192
60974
|
*/
|
|
60193
60975
|
var WrapperIdentitySchema = zod.z.object({
|
|
60194
60976
|
kind: WrapperKindSchema,
|
|
@@ -60212,6 +60994,49 @@ var ServerRollbackInfoSchema = zod.z.object({
|
|
|
60212
60994
|
reason: zod.z.string()
|
|
60213
60995
|
});
|
|
60214
60996
|
/**
|
|
60997
|
+
* What the native desktop app (Electron) that hosts this node says about
|
|
60998
|
+
* itself, read from `<dataDir>/server-root/desktop-app-state.json` (ADR-0971).
|
|
60999
|
+
* Absent on the status = no desktop app, or it never wrote the file.
|
|
61000
|
+
*
|
|
61001
|
+
* `stale` is the honest answer to an app that stopped writing (closed, hung,
|
|
61002
|
+
* crashed): the update facts are then the LAST ones known, not current ones,
|
|
61003
|
+
* and a consumer must not read `update.available: false` from a stale record
|
|
61004
|
+
* as "no update". `stateAtMs` is when the app last wrote.
|
|
61005
|
+
*/
|
|
61006
|
+
var DesktopAppStatusSchema = zod.z.object({
|
|
61007
|
+
/** The Electron app's own version (not the node closure's). */
|
|
61008
|
+
version: zod.z.string(),
|
|
61009
|
+
update: zod.z.object({
|
|
61010
|
+
available: zod.z.boolean(),
|
|
61011
|
+
/** The new build is downloaded and `installDesktopUpdate` can apply it. */
|
|
61012
|
+
downloaded: zod.z.boolean(),
|
|
61013
|
+
version: zod.z.string().nullable(),
|
|
61014
|
+
checking: zod.z.boolean(),
|
|
61015
|
+
/** Why the app's last update check produced no answer; `null` when it did. */
|
|
61016
|
+
error: zod.z.string().nullable()
|
|
61017
|
+
}),
|
|
61018
|
+
stateAtMs: zod.z.number(),
|
|
61019
|
+
stale: zod.z.boolean()
|
|
61020
|
+
});
|
|
61021
|
+
/**
|
|
61022
|
+
* Why `installDesktopUpdate` did nothing. Stable names a UI maps to a sentence:
|
|
61023
|
+
* - `not-electron` — this node does not run inside the desktop app.
|
|
61024
|
+
* - `no-app-state` — the app never published its state (or the file is unreadable).
|
|
61025
|
+
* - `app-state-stale` — the app stopped writing; it is probably not running.
|
|
61026
|
+
* - `not-downloaded` — no update is downloaded yet; nothing to install.
|
|
61027
|
+
*/
|
|
61028
|
+
var InstallDesktopUpdateReasonSchema = zod.z.enum([
|
|
61029
|
+
"not-electron",
|
|
61030
|
+
"no-app-state",
|
|
61031
|
+
"app-state-stale",
|
|
61032
|
+
"not-downloaded"
|
|
61033
|
+
]);
|
|
61034
|
+
var InstallDesktopUpdateResultSchema = zod.z.object({
|
|
61035
|
+
accepted: zod.z.boolean(),
|
|
61036
|
+
/** Non-null exactly when `accepted` is false. */
|
|
61037
|
+
reason: InstallDesktopUpdateReasonSchema.nullable()
|
|
61038
|
+
});
|
|
61039
|
+
/**
|
|
60215
61040
|
* The runner boot check (D877): the runners this node PLANNED (hub: one per
|
|
60216
61041
|
* `resolveRunnerId` over its forked addons; agent: the runners its process
|
|
60217
61042
|
* service holds, because only the hub plans) against the states the process
|
|
@@ -60315,7 +61140,12 @@ var ServerPackageStatusSchema = zod.z.object({
|
|
|
60315
61140
|
* on a provider that predates it. Absent is "not checked yet", never "all
|
|
60316
61141
|
* well": a consumer that needs the answer treats it as pending.
|
|
60317
61142
|
*/
|
|
60318
|
-
runners: RunnerBootCheckSchema.optional()
|
|
61143
|
+
runners: RunnerBootCheckSchema.optional(),
|
|
61144
|
+
/**
|
|
61145
|
+
* The desktop app hosting this node (see {@link DesktopAppStatusSchema}).
|
|
61146
|
+
* Optional for version skew AND because most nodes have no desktop app.
|
|
61147
|
+
*/
|
|
61148
|
+
desktopApp: DesktopAppStatusSchema.optional()
|
|
60319
61149
|
});
|
|
60320
61150
|
var ServerUpdateCheckResultSchema = zod.z.object({
|
|
60321
61151
|
packageName: zod.z.string(),
|
|
@@ -60428,6 +61258,19 @@ var serverManagementCapability = {
|
|
|
60428
61258
|
auth: "admin",
|
|
60429
61259
|
timeoutMs: 16 * 6e4
|
|
60430
61260
|
}),
|
|
61261
|
+
/**
|
|
61262
|
+
* Ask the desktop app hosting this node to install its DOWNLOADED update
|
|
61263
|
+
* and restart. The request is a file in the node's data dir (the node may
|
|
61264
|
+
* be a Windows service, not Electron's child); the app consumes it once.
|
|
61265
|
+
* `accepted: true` means the request was WRITTEN — the app restarting is
|
|
61266
|
+
* observed afterwards on `desktopApp.version`, not promised here. Refused
|
|
61267
|
+
* with a named `reason` when not an electron shell, the app's state is
|
|
61268
|
+
* absent or stale, or nothing is downloaded.
|
|
61269
|
+
*/
|
|
61270
|
+
installDesktopUpdate: require_sleep.method(zod.z.void(), InstallDesktopUpdateResultSchema, {
|
|
61271
|
+
kind: "mutation",
|
|
61272
|
+
auth: "admin"
|
|
61273
|
+
}),
|
|
60431
61274
|
rollbackServerUpdate: require_sleep.method(zod.z.void(), ServerUpdateActionResultSchema, {
|
|
60432
61275
|
kind: "mutation",
|
|
60433
61276
|
auth: "admin"
|
|
@@ -65095,15 +65938,29 @@ var actionsCapability = {
|
|
|
65095
65938
|
auth: "admin"
|
|
65096
65939
|
}),
|
|
65097
65940
|
getTraces: require_sleep.method(ActionIdInput, zod.z.object({ traces: zod.z.array(AutomationRunTraceSchema) }), { auth: "admin" }),
|
|
65098
|
-
/**
|
|
65099
|
-
|
|
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
|
+
}), {
|
|
65100
65954
|
kind: "mutation",
|
|
65101
65955
|
auth: "admin"
|
|
65102
65956
|
}),
|
|
65103
65957
|
update: require_sleep.method(zod.z.object({
|
|
65104
65958
|
actionId: zod.z.string().min(1),
|
|
65105
65959
|
action: ActionInputSchema.partial()
|
|
65106
|
-
}), zod.z.object({
|
|
65960
|
+
}), zod.z.object({
|
|
65961
|
+
action: ActionEntrySchema,
|
|
65962
|
+
warnings: zod.z.array(UnitWarningSchema).optional()
|
|
65963
|
+
}), {
|
|
65107
65964
|
kind: "mutation",
|
|
65108
65965
|
auth: "admin"
|
|
65109
65966
|
}),
|
|
@@ -73280,6 +74137,14 @@ var PetFeederDeviceStatusSchema = zod.z.enum([
|
|
|
73280
74137
|
"on_batteries"
|
|
73281
74138
|
]);
|
|
73282
74139
|
var gramsPortion = zod.z.number().int().min(4).max(200);
|
|
74140
|
+
/** A portion REQUESTED of the feeder is a mass the method takes in GRAMS (the
|
|
74141
|
+
* hardware's own unit). The bounds are grams; a caller entering another unit
|
|
74142
|
+
* converts to grams first (`paramMeta`, D972). The STATUS fields above stay
|
|
74143
|
+
* plain grams — they are not readings in the kilogram base. */
|
|
74144
|
+
var gramsParam = gramsPortion.meta(paramMeta({
|
|
74145
|
+
quantity: "mass",
|
|
74146
|
+
unit: "g"
|
|
74147
|
+
}));
|
|
73283
74148
|
var PetFeederStatusSchema = zod.z.object({
|
|
73284
74149
|
/** Food in the TANK (hopper), as the feeder's own sensor reports it
|
|
73285
74150
|
* (`state.food`). A coarse level code, not grams — `0` is empty. The
|
|
@@ -73368,9 +74233,9 @@ var petFeederCapability = {
|
|
|
73368
74233
|
*/
|
|
73369
74234
|
feed: require_sleep.method(zod.z.object({
|
|
73370
74235
|
deviceId: zod.z.number().int().nonnegative(),
|
|
73371
|
-
grams:
|
|
73372
|
-
hopper1:
|
|
73373
|
-
hopper2:
|
|
74236
|
+
grams: gramsParam.optional(),
|
|
74237
|
+
hopper1: gramsParam.optional(),
|
|
74238
|
+
hopper2: gramsParam.optional()
|
|
73374
74239
|
}), zod.z.void(), {
|
|
73375
74240
|
kind: "mutation",
|
|
73376
74241
|
auth: "protected"
|
|
@@ -82828,465 +83693,6 @@ function numericAccept() {
|
|
|
82828
83693
|
return historyAccept("statistic").filter((field) => field.valueKind === "number");
|
|
82829
83694
|
}
|
|
82830
83695
|
//#endregion
|
|
82831
|
-
//#region src/units/unit-table.ts
|
|
82832
|
-
/**
|
|
82833
|
-
* Frozen unit → spec table. `•` in the doc marks each dimension's canonical
|
|
82834
|
-
* unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
|
|
82835
|
-
* `factor = 5/9`, `offset = -160/9` (kept as exact expressions, not rounded
|
|
82836
|
-
* decimals). K derives from `°C = K − 273.15`.
|
|
82837
|
-
*/
|
|
82838
|
-
var UNIT_TABLE = {
|
|
82839
|
-
"°C": {
|
|
82840
|
-
dimension: "temperature",
|
|
82841
|
-
factor: 1,
|
|
82842
|
-
offset: 0
|
|
82843
|
-
},
|
|
82844
|
-
"°F": {
|
|
82845
|
-
dimension: "temperature",
|
|
82846
|
-
factor: 5 / 9,
|
|
82847
|
-
offset: -160 / 9
|
|
82848
|
-
},
|
|
82849
|
-
K: {
|
|
82850
|
-
dimension: "temperature",
|
|
82851
|
-
factor: 1,
|
|
82852
|
-
offset: -273.15
|
|
82853
|
-
},
|
|
82854
|
-
hPa: {
|
|
82855
|
-
dimension: "pressure",
|
|
82856
|
-
factor: 1,
|
|
82857
|
-
offset: 0
|
|
82858
|
-
},
|
|
82859
|
-
kPa: {
|
|
82860
|
-
dimension: "pressure",
|
|
82861
|
-
factor: 10,
|
|
82862
|
-
offset: 0
|
|
82863
|
-
},
|
|
82864
|
-
Pa: {
|
|
82865
|
-
dimension: "pressure",
|
|
82866
|
-
factor: .01,
|
|
82867
|
-
offset: 0
|
|
82868
|
-
},
|
|
82869
|
-
mbar: {
|
|
82870
|
-
dimension: "pressure",
|
|
82871
|
-
factor: 1,
|
|
82872
|
-
offset: 0
|
|
82873
|
-
},
|
|
82874
|
-
bar: {
|
|
82875
|
-
dimension: "pressure",
|
|
82876
|
-
factor: 1e3,
|
|
82877
|
-
offset: 0
|
|
82878
|
-
},
|
|
82879
|
-
inHg: {
|
|
82880
|
-
dimension: "pressure",
|
|
82881
|
-
factor: 33.8639,
|
|
82882
|
-
offset: 0
|
|
82883
|
-
},
|
|
82884
|
-
mmHg: {
|
|
82885
|
-
dimension: "pressure",
|
|
82886
|
-
factor: 1.33322,
|
|
82887
|
-
offset: 0
|
|
82888
|
-
},
|
|
82889
|
-
psi: {
|
|
82890
|
-
dimension: "pressure",
|
|
82891
|
-
factor: 68.9476,
|
|
82892
|
-
offset: 0
|
|
82893
|
-
},
|
|
82894
|
-
"m/s": {
|
|
82895
|
-
dimension: "speed",
|
|
82896
|
-
factor: 1,
|
|
82897
|
-
offset: 0
|
|
82898
|
-
},
|
|
82899
|
-
"km/h": {
|
|
82900
|
-
dimension: "speed",
|
|
82901
|
-
factor: 1 / 3.6,
|
|
82902
|
-
offset: 0
|
|
82903
|
-
},
|
|
82904
|
-
mph: {
|
|
82905
|
-
dimension: "speed",
|
|
82906
|
-
factor: .44704,
|
|
82907
|
-
offset: 0
|
|
82908
|
-
},
|
|
82909
|
-
kn: {
|
|
82910
|
-
dimension: "speed",
|
|
82911
|
-
factor: .514444,
|
|
82912
|
-
offset: 0
|
|
82913
|
-
},
|
|
82914
|
-
"mm/h": {
|
|
82915
|
-
dimension: "precipitation-rate",
|
|
82916
|
-
factor: 1,
|
|
82917
|
-
offset: 0
|
|
82918
|
-
},
|
|
82919
|
-
"in/h": {
|
|
82920
|
-
dimension: "precipitation-rate",
|
|
82921
|
-
factor: 25.4,
|
|
82922
|
-
offset: 0
|
|
82923
|
-
},
|
|
82924
|
-
m: {
|
|
82925
|
-
dimension: "length",
|
|
82926
|
-
factor: 1,
|
|
82927
|
-
offset: 0
|
|
82928
|
-
},
|
|
82929
|
-
mm: {
|
|
82930
|
-
dimension: "length",
|
|
82931
|
-
factor: .001,
|
|
82932
|
-
offset: 0
|
|
82933
|
-
},
|
|
82934
|
-
cm: {
|
|
82935
|
-
dimension: "length",
|
|
82936
|
-
factor: .01,
|
|
82937
|
-
offset: 0
|
|
82938
|
-
},
|
|
82939
|
-
km: {
|
|
82940
|
-
dimension: "length",
|
|
82941
|
-
factor: 1e3,
|
|
82942
|
-
offset: 0
|
|
82943
|
-
},
|
|
82944
|
-
in: {
|
|
82945
|
-
dimension: "length",
|
|
82946
|
-
factor: .0254,
|
|
82947
|
-
offset: 0
|
|
82948
|
-
},
|
|
82949
|
-
ft: {
|
|
82950
|
-
dimension: "length",
|
|
82951
|
-
factor: .3048,
|
|
82952
|
-
offset: 0
|
|
82953
|
-
},
|
|
82954
|
-
mi: {
|
|
82955
|
-
dimension: "length",
|
|
82956
|
-
factor: 1609.344,
|
|
82957
|
-
offset: 0
|
|
82958
|
-
},
|
|
82959
|
-
"m²": {
|
|
82960
|
-
dimension: "area",
|
|
82961
|
-
factor: 1,
|
|
82962
|
-
offset: 0
|
|
82963
|
-
},
|
|
82964
|
-
lx: {
|
|
82965
|
-
dimension: "illuminance",
|
|
82966
|
-
factor: 1,
|
|
82967
|
-
offset: 0
|
|
82968
|
-
},
|
|
82969
|
-
"W/m²": {
|
|
82970
|
-
dimension: "irradiance",
|
|
82971
|
-
factor: 1,
|
|
82972
|
-
offset: 0
|
|
82973
|
-
},
|
|
82974
|
-
W: {
|
|
82975
|
-
dimension: "power",
|
|
82976
|
-
factor: 1,
|
|
82977
|
-
offset: 0
|
|
82978
|
-
},
|
|
82979
|
-
kW: {
|
|
82980
|
-
dimension: "power",
|
|
82981
|
-
factor: 1e3,
|
|
82982
|
-
offset: 0
|
|
82983
|
-
},
|
|
82984
|
-
VA: {
|
|
82985
|
-
dimension: "apparent-power",
|
|
82986
|
-
factor: 1,
|
|
82987
|
-
offset: 0
|
|
82988
|
-
},
|
|
82989
|
-
Wh: {
|
|
82990
|
-
dimension: "energy",
|
|
82991
|
-
factor: 1,
|
|
82992
|
-
offset: 0
|
|
82993
|
-
},
|
|
82994
|
-
kWh: {
|
|
82995
|
-
dimension: "energy",
|
|
82996
|
-
factor: 1e3,
|
|
82997
|
-
offset: 0
|
|
82998
|
-
},
|
|
82999
|
-
MWh: {
|
|
83000
|
-
dimension: "energy",
|
|
83001
|
-
factor: 1e6,
|
|
83002
|
-
offset: 0
|
|
83003
|
-
},
|
|
83004
|
-
V: {
|
|
83005
|
-
dimension: "voltage",
|
|
83006
|
-
factor: 1,
|
|
83007
|
-
offset: 0
|
|
83008
|
-
},
|
|
83009
|
-
mV: {
|
|
83010
|
-
dimension: "voltage",
|
|
83011
|
-
factor: .001,
|
|
83012
|
-
offset: 0
|
|
83013
|
-
},
|
|
83014
|
-
A: {
|
|
83015
|
-
dimension: "current",
|
|
83016
|
-
factor: 1,
|
|
83017
|
-
offset: 0
|
|
83018
|
-
},
|
|
83019
|
-
mA: {
|
|
83020
|
-
dimension: "current",
|
|
83021
|
-
factor: .001,
|
|
83022
|
-
offset: 0
|
|
83023
|
-
},
|
|
83024
|
-
ppm: {
|
|
83025
|
-
dimension: "concentration-volume",
|
|
83026
|
-
factor: 1,
|
|
83027
|
-
offset: 0
|
|
83028
|
-
},
|
|
83029
|
-
ppb: {
|
|
83030
|
-
dimension: "concentration-volume",
|
|
83031
|
-
factor: .001,
|
|
83032
|
-
offset: 0
|
|
83033
|
-
},
|
|
83034
|
-
"µg/m³": {
|
|
83035
|
-
dimension: "concentration-mass",
|
|
83036
|
-
factor: 1,
|
|
83037
|
-
offset: 0
|
|
83038
|
-
},
|
|
83039
|
-
"mg/m³": {
|
|
83040
|
-
dimension: "concentration-mass",
|
|
83041
|
-
factor: 1e3,
|
|
83042
|
-
offset: 0
|
|
83043
|
-
},
|
|
83044
|
-
kg: {
|
|
83045
|
-
dimension: "mass",
|
|
83046
|
-
factor: 1,
|
|
83047
|
-
offset: 0
|
|
83048
|
-
},
|
|
83049
|
-
g: {
|
|
83050
|
-
dimension: "mass",
|
|
83051
|
-
factor: .001,
|
|
83052
|
-
offset: 0
|
|
83053
|
-
},
|
|
83054
|
-
lb: {
|
|
83055
|
-
dimension: "mass",
|
|
83056
|
-
factor: .453592,
|
|
83057
|
-
offset: 0
|
|
83058
|
-
},
|
|
83059
|
-
oz: {
|
|
83060
|
-
dimension: "mass",
|
|
83061
|
-
factor: .0283495,
|
|
83062
|
-
offset: 0
|
|
83063
|
-
},
|
|
83064
|
-
"%": {
|
|
83065
|
-
dimension: "percentage",
|
|
83066
|
-
factor: 1,
|
|
83067
|
-
offset: 0
|
|
83068
|
-
},
|
|
83069
|
-
L: {
|
|
83070
|
-
dimension: "volume",
|
|
83071
|
-
factor: 1,
|
|
83072
|
-
offset: 0
|
|
83073
|
-
},
|
|
83074
|
-
mL: {
|
|
83075
|
-
dimension: "volume",
|
|
83076
|
-
factor: .001,
|
|
83077
|
-
offset: 0
|
|
83078
|
-
},
|
|
83079
|
-
gal: {
|
|
83080
|
-
dimension: "volume",
|
|
83081
|
-
factor: 3.785411784,
|
|
83082
|
-
offset: 0
|
|
83083
|
-
},
|
|
83084
|
-
s: {
|
|
83085
|
-
dimension: "duration",
|
|
83086
|
-
factor: 1,
|
|
83087
|
-
offset: 0
|
|
83088
|
-
},
|
|
83089
|
-
ms: {
|
|
83090
|
-
dimension: "duration",
|
|
83091
|
-
factor: .001,
|
|
83092
|
-
offset: 0
|
|
83093
|
-
},
|
|
83094
|
-
min: {
|
|
83095
|
-
dimension: "duration",
|
|
83096
|
-
factor: 60,
|
|
83097
|
-
offset: 0
|
|
83098
|
-
},
|
|
83099
|
-
h: {
|
|
83100
|
-
dimension: "duration",
|
|
83101
|
-
factor: 3600,
|
|
83102
|
-
offset: 0
|
|
83103
|
-
},
|
|
83104
|
-
d: {
|
|
83105
|
-
dimension: "duration",
|
|
83106
|
-
factor: 86400,
|
|
83107
|
-
offset: 0
|
|
83108
|
-
},
|
|
83109
|
-
B: {
|
|
83110
|
-
dimension: "information",
|
|
83111
|
-
factor: 1,
|
|
83112
|
-
offset: 0
|
|
83113
|
-
},
|
|
83114
|
-
KiB: {
|
|
83115
|
-
dimension: "information",
|
|
83116
|
-
factor: 1024,
|
|
83117
|
-
offset: 0
|
|
83118
|
-
},
|
|
83119
|
-
MiB: {
|
|
83120
|
-
dimension: "information",
|
|
83121
|
-
factor: 1024 ** 2,
|
|
83122
|
-
offset: 0
|
|
83123
|
-
},
|
|
83124
|
-
GiB: {
|
|
83125
|
-
dimension: "information",
|
|
83126
|
-
factor: 1024 ** 3,
|
|
83127
|
-
offset: 0
|
|
83128
|
-
},
|
|
83129
|
-
TiB: {
|
|
83130
|
-
dimension: "information",
|
|
83131
|
-
factor: 1024 ** 4,
|
|
83132
|
-
offset: 0
|
|
83133
|
-
},
|
|
83134
|
-
kB: {
|
|
83135
|
-
dimension: "information",
|
|
83136
|
-
factor: 1e3,
|
|
83137
|
-
offset: 0
|
|
83138
|
-
},
|
|
83139
|
-
MB: {
|
|
83140
|
-
dimension: "information",
|
|
83141
|
-
factor: 1e6,
|
|
83142
|
-
offset: 0
|
|
83143
|
-
},
|
|
83144
|
-
GB: {
|
|
83145
|
-
dimension: "information",
|
|
83146
|
-
factor: 1e9,
|
|
83147
|
-
offset: 0
|
|
83148
|
-
},
|
|
83149
|
-
"°": {
|
|
83150
|
-
dimension: "angle",
|
|
83151
|
-
factor: 1,
|
|
83152
|
-
offset: 0
|
|
83153
|
-
},
|
|
83154
|
-
dBFS: {
|
|
83155
|
-
dimension: "sound-level",
|
|
83156
|
-
factor: 1,
|
|
83157
|
-
offset: 0
|
|
83158
|
-
},
|
|
83159
|
-
dBm: {
|
|
83160
|
-
dimension: "signal-level",
|
|
83161
|
-
factor: 1,
|
|
83162
|
-
offset: 0
|
|
83163
|
-
},
|
|
83164
|
-
mired: {
|
|
83165
|
-
dimension: "colour-temperature",
|
|
83166
|
-
factor: 1,
|
|
83167
|
-
offset: 0
|
|
83168
|
-
},
|
|
83169
|
-
kbps: {
|
|
83170
|
-
dimension: "bitrate",
|
|
83171
|
-
factor: 1,
|
|
83172
|
-
offset: 0
|
|
83173
|
-
},
|
|
83174
|
-
Mbps: {
|
|
83175
|
-
dimension: "bitrate",
|
|
83176
|
-
factor: 1e3,
|
|
83177
|
-
offset: 0
|
|
83178
|
-
},
|
|
83179
|
-
fps: {
|
|
83180
|
-
dimension: "rate",
|
|
83181
|
-
factor: 1,
|
|
83182
|
-
offset: 0
|
|
83183
|
-
}
|
|
83184
|
-
};
|
|
83185
|
-
//#endregion
|
|
83186
|
-
//#region src/units/convert.ts
|
|
83187
|
-
/**
|
|
83188
|
-
* Pure unit-conversion API over `UNIT_TABLE`. No dependencies, no side effects.
|
|
83189
|
-
*
|
|
83190
|
-
* Conversion is refused (throws `UnitConversionError`, or returns `undefined`
|
|
83191
|
-
* from the `try*` variant) whenever a unit is unknown or the two units belong
|
|
83192
|
-
* to different dimensions — cross-dimension conversion is deliberately
|
|
83193
|
-
* impossible so a render override can never make the value and its unit label
|
|
83194
|
-
* disagree.
|
|
83195
|
-
*
|
|
83196
|
-
* Callers pass units through `normalizeUnit` (`../device/source-info.ts`) BEFORE
|
|
83197
|
-
* calling here — the table keys only canonical spellings.
|
|
83198
|
-
*/
|
|
83199
|
-
/** Thrown by `convertUnit` when a conversion is refused. Carries the offending
|
|
83200
|
-
* units + a machine-readable `reason` for callers that branch on the cause. */
|
|
83201
|
-
var UnitConversionError = class extends Error {
|
|
83202
|
-
from;
|
|
83203
|
-
to;
|
|
83204
|
-
reason;
|
|
83205
|
-
constructor(from, to, reason) {
|
|
83206
|
-
super(`[units] cannot convert '${from}' → '${to}': ${reason}`);
|
|
83207
|
-
this.name = "UnitConversionError";
|
|
83208
|
-
this.from = from;
|
|
83209
|
-
this.to = to;
|
|
83210
|
-
this.reason = reason;
|
|
83211
|
-
}
|
|
83212
|
-
};
|
|
83213
|
-
/** Resolve a unit's `UnitSpec`, or `undefined` when the spelling is unknown. */
|
|
83214
|
-
function specFor(unit) {
|
|
83215
|
-
return Object.hasOwn(UNIT_TABLE, unit) ? UNIT_TABLE[unit] : void 0;
|
|
83216
|
-
}
|
|
83217
|
-
/** The dimension a unit belongs to, or `undefined` for an unknown unit. */
|
|
83218
|
-
function unitDimension(unit) {
|
|
83219
|
-
return specFor(unit)?.dimension;
|
|
83220
|
-
}
|
|
83221
|
-
/** Value in `spec`'s unit → its dimension's canonical unit. */
|
|
83222
|
-
function toCanonical(value, spec) {
|
|
83223
|
-
return value * spec.factor + spec.offset;
|
|
83224
|
-
}
|
|
83225
|
-
/** Canonical-unit value → the unit described by `spec`. */
|
|
83226
|
-
function fromCanonical(canonical, spec) {
|
|
83227
|
-
return (canonical - spec.offset) / spec.factor;
|
|
83228
|
-
}
|
|
83229
|
-
/**
|
|
83230
|
-
* Convert `value` from unit `from` to unit `to`. Identity when `from === to`.
|
|
83231
|
-
* Throws `UnitConversionError` when either unit is unknown or the units belong
|
|
83232
|
-
* to different dimensions.
|
|
83233
|
-
*/
|
|
83234
|
-
function convertUnit(value, from, to) {
|
|
83235
|
-
if (from === to) return value;
|
|
83236
|
-
const fromSpec = specFor(from);
|
|
83237
|
-
if (!fromSpec) throw new UnitConversionError(from, to, "unknown-from");
|
|
83238
|
-
const toSpec = specFor(to);
|
|
83239
|
-
if (!toSpec) throw new UnitConversionError(from, to, "unknown-to");
|
|
83240
|
-
if (fromSpec.dimension !== toSpec.dimension) throw new UnitConversionError(from, to, "cross-dimension");
|
|
83241
|
-
return fromCanonical(toCanonical(value, fromSpec), toSpec);
|
|
83242
|
-
}
|
|
83243
|
-
/**
|
|
83244
|
-
* Graceful variant for the render path: returns the converted value, or
|
|
83245
|
-
* `undefined` when the conversion is refused (unknown unit / cross-dimension).
|
|
83246
|
-
* Never throws — a render caller falls back to the raw value + source unit.
|
|
83247
|
-
*/
|
|
83248
|
-
function tryConvertUnit(value, from, to) {
|
|
83249
|
-
if (from === to) return value;
|
|
83250
|
-
const fromSpec = specFor(from);
|
|
83251
|
-
if (!fromSpec) return void 0;
|
|
83252
|
-
const toSpec = specFor(to);
|
|
83253
|
-
if (!toSpec) return void 0;
|
|
83254
|
-
if (fromSpec.dimension !== toSpec.dimension) return void 0;
|
|
83255
|
-
return fromCanonical(toCanonical(value, fromSpec), toSpec);
|
|
83256
|
-
}
|
|
83257
|
-
/**
|
|
83258
|
-
* Whether `value` can be converted between `from` and `to` (same dimension,
|
|
83259
|
-
* both known). Cheap boolean probe for the UI's same-dimension unit picker and
|
|
83260
|
-
* the resolver's convertibility branch — compute ONCE so a unit label and its
|
|
83261
|
-
* value math can never disagree.
|
|
83262
|
-
*/
|
|
83263
|
-
function canConvertUnit(from, to) {
|
|
83264
|
-
if (from === to) return true;
|
|
83265
|
-
const fromDim = unitDimension(from);
|
|
83266
|
-
if (fromDim === void 0) return false;
|
|
83267
|
-
return fromDim === unitDimension(to);
|
|
83268
|
-
}
|
|
83269
|
-
/**
|
|
83270
|
-
* Every known unit spelling in a dimension (table insertion order — canonical
|
|
83271
|
-
* unit first). Powers the UI's same-dimension unit picker.
|
|
83272
|
-
*/
|
|
83273
|
-
/**
|
|
83274
|
-
* Convert a difference, not a reading. Affine units (°F) shift an absolute
|
|
83275
|
-
* value by their offset; a step of 1°F is 5/9°C, so the offset is cancelled.
|
|
83276
|
-
*/
|
|
83277
|
-
function tryConvertDelta(value, from, to) {
|
|
83278
|
-
if (from === to) return value;
|
|
83279
|
-
const origin = tryConvertUnit(0, from, to);
|
|
83280
|
-
const shifted = tryConvertUnit(value, from, to);
|
|
83281
|
-
if (origin === void 0 || shifted === void 0) return void 0;
|
|
83282
|
-
return shifted - origin;
|
|
83283
|
-
}
|
|
83284
|
-
function unitsForDimension(dimension) {
|
|
83285
|
-
const out = [];
|
|
83286
|
-
for (const [unit, spec] of Object.entries(UNIT_TABLE)) if (spec.dimension === dimension) out.push(unit);
|
|
83287
|
-
return out;
|
|
83288
|
-
}
|
|
83289
|
-
//#endregion
|
|
83290
83696
|
//#region src/composition/evaluate-field.ts
|
|
83291
83697
|
/**
|
|
83292
83698
|
* One composed field, evaluated from what its sources say NOW (D659).
|
|
@@ -96679,6 +97085,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
96679
97085
|
access: "view",
|
|
96680
97086
|
role: "admin"
|
|
96681
97087
|
},
|
|
97088
|
+
"serverManagement.installDesktopUpdate": {
|
|
97089
|
+
capName: "server-management",
|
|
97090
|
+
capScope: "system",
|
|
97091
|
+
addonId: null,
|
|
97092
|
+
access: "create",
|
|
97093
|
+
role: "admin"
|
|
97094
|
+
},
|
|
96682
97095
|
"serverManagement.restartServer": {
|
|
96683
97096
|
capName: "server-management",
|
|
96684
97097
|
capScope: "system",
|
|
@@ -100988,7 +101401,8 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
100988
101401
|
min: 4,
|
|
100989
101402
|
max: 200,
|
|
100990
101403
|
step: 1,
|
|
100991
|
-
unit: "g"
|
|
101404
|
+
unit: "g",
|
|
101405
|
+
quantity: "mass"
|
|
100992
101406
|
},
|
|
100993
101407
|
optional: true
|
|
100994
101408
|
}]
|
|
@@ -101007,7 +101421,8 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
101007
101421
|
min: 4,
|
|
101008
101422
|
max: 200,
|
|
101009
101423
|
step: 1,
|
|
101010
|
-
unit: "g"
|
|
101424
|
+
unit: "g",
|
|
101425
|
+
quantity: "mass"
|
|
101011
101426
|
},
|
|
101012
101427
|
optional: true
|
|
101013
101428
|
}, {
|
|
@@ -101018,7 +101433,8 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
101018
101433
|
min: 4,
|
|
101019
101434
|
max: 200,
|
|
101020
101435
|
step: 1,
|
|
101021
|
-
unit: "g"
|
|
101436
|
+
unit: "g",
|
|
101437
|
+
quantity: "mass"
|
|
101022
101438
|
},
|
|
101023
101439
|
optional: true
|
|
101024
101440
|
}]
|
|
@@ -110879,6 +111295,7 @@ function createSystemProxy(api) {
|
|
|
110879
111295
|
getServerPackageStatus: (input) => dispatch("serverManagement", "getServerPackageStatus", "query", input),
|
|
110880
111296
|
checkServerUpdate: (input) => dispatch("serverManagement", "checkServerUpdate", "mutation", input),
|
|
110881
111297
|
applyServerUpdate: (input) => dispatch("serverManagement", "applyServerUpdate", "mutation", input),
|
|
111298
|
+
installDesktopUpdate: (input) => dispatch("serverManagement", "installDesktopUpdate", "mutation", input),
|
|
110882
111299
|
rollbackServerUpdate: (input) => dispatch("serverManagement", "rollbackServerUpdate", "mutation", input),
|
|
110883
111300
|
restartServer: (input) => dispatch("serverManagement", "restartServer", "mutation", input),
|
|
110884
111301
|
getLaunchOverrides: (input) => dispatch("serverManagement", "getLaunchOverrides", "query", input),
|
|
@@ -122354,6 +122771,7 @@ exports.DeleteIntegrationResultSchema = DeleteIntegrationResultSchema;
|
|
|
122354
122771
|
exports.DeliveryParamSchema = DeliveryParamSchema;
|
|
122355
122772
|
exports.DeliveryParamValueSchema = DeliveryParamValueSchema;
|
|
122356
122773
|
exports.DerivativeHelperSpecSchema = require_composition.DerivativeHelperSpecSchema;
|
|
122774
|
+
exports.DesktopAppStatusSchema = DesktopAppStatusSchema;
|
|
122357
122775
|
exports.DetailCropConventionSchema = DetailCropConventionSchema;
|
|
122358
122776
|
exports.DetectionCatalogClassMapSchema = DetectionCatalogClassMapSchema;
|
|
122359
122777
|
exports.DetectionSourceSchema = DetectionSourceSchema;
|
|
@@ -122641,6 +123059,8 @@ exports.ImportModelBundleInputSchema = ImportModelBundleInputSchema;
|
|
|
122641
123059
|
exports.ImportModelBundleResultSchema = ImportModelBundleResultSchema;
|
|
122642
123060
|
exports.InferenceDeviceExclusionReasonSchema = InferenceDeviceExclusionReasonSchema;
|
|
122643
123061
|
exports.IngestOwnerSchema = IngestOwnerSchema;
|
|
123062
|
+
exports.InstallDesktopUpdateReasonSchema = InstallDesktopUpdateReasonSchema;
|
|
123063
|
+
exports.InstallDesktopUpdateResultSchema = InstallDesktopUpdateResultSchema;
|
|
122644
123064
|
exports.InstalledPackageSchema = InstalledPackageSchema;
|
|
122645
123065
|
exports.IntegralHelperSpecSchema = require_composition.IntegralHelperSpecSchema;
|
|
122646
123066
|
exports.IntegrationLiteSchema = IntegrationLiteSchema;
|
|
@@ -123321,6 +123741,8 @@ exports.PtzPresetFunctionSchema = PtzPresetFunctionSchema;
|
|
|
123321
123741
|
exports.PtzPresetSchema = PtzPresetSchema;
|
|
123322
123742
|
exports.PtzStatusSchema = PtzStatusSchema;
|
|
123323
123743
|
exports.QUANTITY_BASE = require_sleep.QUANTITY_BASE;
|
|
123744
|
+
exports.QuantityUnitError = QuantityUnitError;
|
|
123745
|
+
exports.QuantityValueSchema = QuantityValueSchema;
|
|
123324
123746
|
exports.QueryFilterSchema = QueryFilterSchema;
|
|
123325
123747
|
exports.RATE_CONTROL_RELAXED = RATE_CONTROL_RELAXED;
|
|
123326
123748
|
exports.RATE_CONTROL_TIGHT = RATE_CONTROL_TIGHT;
|
|
@@ -123863,6 +124285,7 @@ exports.UninstallNodeOutcomeSchema = UninstallNodeOutcomeSchema;
|
|
|
123863
124285
|
exports.UninstallNodeResultSchema = UninstallNodeResultSchema;
|
|
123864
124286
|
exports.UninstallPackageResultSchema = UninstallPackageResultSchema;
|
|
123865
124287
|
exports.UnitConversionError = UnitConversionError;
|
|
124288
|
+
exports.UnitWarningSchema = UnitWarningSchema;
|
|
123866
124289
|
exports.UnknownRecordKindError = require_sleep.UnknownRecordKindError;
|
|
123867
124290
|
exports.UnreleasedClaimSchema = UnreleasedClaimSchema;
|
|
123868
124291
|
exports.UnstampedEventMediaCountSchema = UnstampedEventMediaCountSchema;
|
|
@@ -124026,6 +124449,7 @@ exports.autoAssignProfiles = autoAssignProfiles;
|
|
|
124026
124449
|
exports.automationControlCapability = automationControlCapability;
|
|
124027
124450
|
exports.backupCapability = backupCapability;
|
|
124028
124451
|
exports.bareAddonId = bareAddonId;
|
|
124452
|
+
exports.baseUnitForQuantity = baseUnitForQuantity;
|
|
124029
124453
|
exports.baseUnitOf = require_sleep.baseUnitOf;
|
|
124030
124454
|
exports.batteryCapability = batteryCapability;
|
|
124031
124455
|
exports.bestLocationMatch = bestLocationMatch;
|
|
@@ -124074,6 +124498,7 @@ exports.canConvertUnit = canConvertUnit;
|
|
|
124074
124498
|
exports.canonicalEgressPlan = canonicalEgressPlan;
|
|
124075
124499
|
exports.canonicalIconKey = canonicalIconKey;
|
|
124076
124500
|
exports.canonicalizeAppCallback = canonicalizeAppCallback;
|
|
124501
|
+
exports.capUnitResolver = capUnitResolver;
|
|
124077
124502
|
exports.capabilityScopesOf = capabilityScopesOf;
|
|
124078
124503
|
exports.capacityForModel = capacityForModel;
|
|
124079
124504
|
exports.capacitySessionsOf = capacitySessionsOf;
|
|
@@ -124156,6 +124581,7 @@ exports.contactCapability = contactCapability;
|
|
|
124156
124581
|
exports.containingParentIndex = containingParentIndex;
|
|
124157
124582
|
exports.controlCapability = controlCapability;
|
|
124158
124583
|
exports.convertPresetFeature = convertPresetFeature;
|
|
124584
|
+
exports.convertQuantityInput = convertQuantityInput;
|
|
124159
124585
|
exports.convertUnit = convertUnit;
|
|
124160
124586
|
exports.convertUnitTargets = convertUnitTargets;
|
|
124161
124587
|
exports.coralUsableUnits = coralUsableUnits;
|
|
@@ -124471,6 +124897,7 @@ exports.isObjectInput = isObjectInput;
|
|
|
124471
124897
|
exports.isOccupancyRule = isOccupancyRule;
|
|
124472
124898
|
exports.isOwnerOnlyEventCategory = require_event_category.isOwnerOnlyEventCategory;
|
|
124473
124899
|
exports.isPlugApplianceType = isPlugApplianceType;
|
|
124900
|
+
exports.isQuantityValue = isQuantityValue;
|
|
124474
124901
|
exports.isReadingQuantity = require_sleep.isReadingQuantity;
|
|
124475
124902
|
exports.isRemoteCustomKey = isRemoteCustomKey;
|
|
124476
124903
|
exports.isRemoteKnownRole = isRemoteKnownRole;
|
|
@@ -124601,12 +125028,15 @@ exports.nodePickerItems = nodePickerItems;
|
|
|
124601
125028
|
exports.nodePin = require_sleep.nodePin;
|
|
124602
125029
|
exports.nodeRemovalHookCapability = nodeRemovalHookCapability;
|
|
124603
125030
|
exports.nodesCapability = nodesCapability;
|
|
125031
|
+
exports.normalizeActionUnits = normalizeActionUnits;
|
|
124604
125032
|
exports.normalizeAddonInitResult = require_sleep.normalizeAddonInitResult;
|
|
124605
125033
|
exports.normalizeAudioLabel = normalizeAudioLabel;
|
|
125034
|
+
exports.normalizeConditionUnits = normalizeConditionUnits;
|
|
124606
125035
|
exports.normalizeCoreBlockWrite = normalizeCoreBlockWrite;
|
|
124607
125036
|
exports.normalizeNcMediaPolicy = normalizeNcMediaPolicy;
|
|
124608
125037
|
exports.normalizeNodeId = require_sleep.normalizeNodeId;
|
|
124609
125038
|
exports.normalizeOrigin = normalizeOrigin;
|
|
125039
|
+
exports.normalizeRecipeUnits = normalizeRecipeUnits;
|
|
124610
125040
|
exports.normalizeSecretOwner = require_sleep.normalizeSecretOwner;
|
|
124611
125041
|
exports.normalizeTokenScopes = normalizeTokenScopes;
|
|
124612
125042
|
exports.normalizeUnit = normalizeUnit;
|
|
@@ -124638,6 +125068,8 @@ exports.paletteFromStored = paletteFromStored;
|
|
|
124638
125068
|
exports.paletteLegend = paletteLegend;
|
|
124639
125069
|
exports.paletteResultSchema = paletteResultSchema;
|
|
124640
125070
|
exports.paletteSwatchSchema = paletteSwatchSchema;
|
|
125071
|
+
exports.paramMeta = paramMeta;
|
|
125072
|
+
exports.paramMetaOf = paramMetaOf;
|
|
124641
125073
|
exports.parseAcceleratorFactsJson = parseAcceleratorFactsJson;
|
|
124642
125074
|
exports.parseAdminBase = parseAdminBase;
|
|
124643
125075
|
exports.parseAlertEpisodePayload = parseAlertEpisodePayload;
|
|
@@ -125023,6 +125455,7 @@ exports.turnProviderCapability = turnProviderCapability;
|
|
|
125023
125455
|
exports.unitCompanionField = unitCompanionField;
|
|
125024
125456
|
exports.unitDimension = unitDimension;
|
|
125025
125457
|
exports.unitsForDimension = unitsForDimension;
|
|
125458
|
+
exports.unitsForQuantity = unitsForQuantity;
|
|
125026
125459
|
exports.unreachableExtensionSlotRow = unreachableExtensionSlotRow;
|
|
125027
125460
|
exports.unwrapSchema = unwrapSchema;
|
|
125028
125461
|
exports.updateCapability = updateCapability;
|