@camstack/addon-provider-homeassistant 1.2.654 → 1.2.655
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 +8 -0
- package/dist/addon.js +312 -88
- package/dist/addon.mjs +309 -88
- package/dist/ha-export/ha-export.addon.js +71 -31
- package/dist/ha-export/ha-export.addon.mjs +71 -31
- package/dist/{ha-instance-settings-Bn_Trz6p.js → ha-instance-settings-5Ms7yRju.js} +940 -309
- package/dist/{ha-instance-settings-g5pwb3Fi.mjs → ha-instance-settings-DLDNOmgL.mjs} +899 -310
- package/package.json +6 -2
|
@@ -5980,7 +5980,7 @@ var ZodIssueCode = {
|
|
|
5980
5980
|
var ZodFirstPartyTypeKind;
|
|
5981
5981
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5982
5982
|
//#endregion
|
|
5983
|
-
//#region ../types/dist/sleep-
|
|
5983
|
+
//#region ../types/dist/sleep-BkzQdpzF.mjs
|
|
5984
5984
|
/**
|
|
5985
5985
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5986
5986
|
* window to float samples (D455).
|
|
@@ -6075,6 +6075,16 @@ var AddonMigrationsBlockedError = class extends Error {
|
|
|
6075
6075
|
this.migrationIds = migrationIds;
|
|
6076
6076
|
}
|
|
6077
6077
|
};
|
|
6078
|
+
/**
|
|
6079
|
+
* The value a redacted secret is replaced with on every read surface.
|
|
6080
|
+
*
|
|
6081
|
+
* It is also the WRITE-BACK token: an `upsertLocation` that sends this value
|
|
6082
|
+
* back for a key means "keep what is stored", which is what lets an operator
|
|
6083
|
+
* rename a location without retyping its password. A literal an operator could
|
|
6084
|
+
* plausibly choose as a real password would turn that convenience into a way
|
|
6085
|
+
* to lock yourself out, hence the sentinel shape.
|
|
6086
|
+
*/
|
|
6087
|
+
var REDACTED_SECRET = "__camstack_redacted__";
|
|
6078
6088
|
/** Is this field's stored value a credential? */
|
|
6079
6089
|
function isSecretConfigField(field) {
|
|
6080
6090
|
if (field.type === "password") return true;
|
|
@@ -6128,9 +6138,16 @@ function isSecretMarker(value) {
|
|
|
6128
6138
|
const ref = value["$secret"];
|
|
6129
6139
|
return typeof ref === "string" && ref.length > 0;
|
|
6130
6140
|
}
|
|
6141
|
+
/** Anything carrying a `$secret` key — a stored marker or a UI view of one. */
|
|
6142
|
+
function isSecretMarkerLike(value) {
|
|
6143
|
+
return isRecord$7(value) && Object.prototype.hasOwnProperty.call(value, "$secret");
|
|
6144
|
+
}
|
|
6131
6145
|
function isSecretClear(value) {
|
|
6132
6146
|
return isRecord$7(value) && value["$secretClear"] === true;
|
|
6133
6147
|
}
|
|
6148
|
+
function isSecretFieldView(value) {
|
|
6149
|
+
return isRecord$7(value) && value["set"] === true && isSecretMarkerLike(value);
|
|
6150
|
+
}
|
|
6134
6151
|
/**
|
|
6135
6152
|
* The UI view of a stored secret field value: a marker becomes "set", inline
|
|
6136
6153
|
* plaintext becomes "set (inline)", nothing becomes `null`. A value never
|
|
@@ -6780,11 +6797,36 @@ function projectStore(store, perNodeKeys, nodeId) {
|
|
|
6780
6797
|
}
|
|
6781
6798
|
return out;
|
|
6782
6799
|
}
|
|
6800
|
+
/**
|
|
6801
|
+
* The address of one keychain value: `secret://<owner>/<scope>/<fieldPath>`.
|
|
6802
|
+
*
|
|
6803
|
+
* A ref is DETERMINISTIC from where the value lives — the owner addon, the
|
|
6804
|
+
* scope (global, one node, one device, one integration, one row of a business
|
|
6805
|
+
* collection) and the field path inside that scope — so saving the same field
|
|
6806
|
+
* twice updates the same ref, and the ref itself says which settings blob
|
|
6807
|
+
* points at it. It is also the AAD of the value's ciphertext: a ciphertext
|
|
6808
|
+
* copied onto another ref does not decrypt.
|
|
6809
|
+
*
|
|
6810
|
+
* Array items are addressed by ITEM ID, never by index
|
|
6811
|
+
* (`providers[authentik].clientSecret`), so reordering a list keeps every ref.
|
|
6812
|
+
*
|
|
6813
|
+
* Pure and browser-safe: no node builtins, no I/O.
|
|
6814
|
+
*/
|
|
6815
|
+
/** The URI scheme of every keychain ref. */
|
|
6816
|
+
var SECRET_REF_SCHEME = "secret://";
|
|
6783
6817
|
var GLOBAL_SCOPE = { kind: "global" };
|
|
6784
6818
|
/** The scope every addon-wide (not per-node, not per-device) setting lives in. */
|
|
6785
6819
|
function globalSecretScope() {
|
|
6786
6820
|
return GLOBAL_SCOPE;
|
|
6787
6821
|
}
|
|
6822
|
+
/**
|
|
6823
|
+
* An addon id as a ref owner. A hub in-process builtin's context id is
|
|
6824
|
+
* `addon:<id>`; the owner of its secrets is `<id>`, exactly as for the same
|
|
6825
|
+
* addon running forked.
|
|
6826
|
+
*/
|
|
6827
|
+
function normalizeSecretOwner(addonId) {
|
|
6828
|
+
return addonId.startsWith("addon:") ? addonId.slice(6) : addonId;
|
|
6829
|
+
}
|
|
6788
6830
|
function encodeSegment(value) {
|
|
6789
6831
|
return encodeURIComponent(value);
|
|
6790
6832
|
}
|
|
@@ -6795,6 +6837,16 @@ function decodeSegment(value) {
|
|
|
6795
6837
|
return null;
|
|
6796
6838
|
}
|
|
6797
6839
|
}
|
|
6840
|
+
/** The scope as it appears inside a ref (`global`, `node/<id>`, …). */
|
|
6841
|
+
function formatSecretScope(scope) {
|
|
6842
|
+
switch (scope.kind) {
|
|
6843
|
+
case "global": return "global";
|
|
6844
|
+
case "node": return `node/${encodeSegment(scope.nodeId)}`;
|
|
6845
|
+
case "device": return `device/${scope.deviceId}`;
|
|
6846
|
+
case "integration": return `integration/${encodeSegment(scope.integrationId)}`;
|
|
6847
|
+
case "row": return `row/${encodeSegment(scope.collection)}/${encodeSegment(scope.rowId)}`;
|
|
6848
|
+
}
|
|
6849
|
+
}
|
|
6798
6850
|
/**
|
|
6799
6851
|
* The field path of a value inside an array item, addressed by the item's id:
|
|
6800
6852
|
* `arrayItemFieldPath('providers', 'authentik', 'clientSecret')` →
|
|
@@ -6803,6 +6855,13 @@ function decodeSegment(value) {
|
|
|
6803
6855
|
function arrayItemFieldPath(arrayKey, itemId, fieldKey) {
|
|
6804
6856
|
return `${arrayKey}[${encodeSegment(itemId)}].${fieldKey}`;
|
|
6805
6857
|
}
|
|
6858
|
+
/** Build a ref. Throws on an empty owner or field path — both are bugs. */
|
|
6859
|
+
function buildSecretRef(parts) {
|
|
6860
|
+
const owner = normalizeSecretOwner(parts.owner);
|
|
6861
|
+
if (owner.length === 0) throw new Error("buildSecretRef: owner is empty");
|
|
6862
|
+
if (parts.fieldPath.length === 0) throw new Error("buildSecretRef: fieldPath is empty");
|
|
6863
|
+
return `${SECRET_REF_SCHEME}${encodeSegment(owner)}/${formatSecretScope(parts.scope)}/${parts.fieldPath}`;
|
|
6864
|
+
}
|
|
6806
6865
|
function parseScope(segments) {
|
|
6807
6866
|
switch (segments[0]) {
|
|
6808
6867
|
case "global": return {
|
|
@@ -8068,6 +8127,10 @@ var BaseAddon = class {
|
|
|
8068
8127
|
const stored = keychain ? await this.readAddonStoreWithRetry() : {};
|
|
8069
8128
|
const patch = {};
|
|
8070
8129
|
for (const key of keys) {
|
|
8130
|
+
if (tree.get(key)?.kind === "array") {
|
|
8131
|
+
patch[key] = [];
|
|
8132
|
+
continue;
|
|
8133
|
+
}
|
|
8071
8134
|
const keychainStored = tree.has(key) || collectSecretMarkerRefs(stored[key]).length > 0;
|
|
8072
8135
|
patch[key] = keychain && keychainStored ? SECRET_CLEAR : "";
|
|
8073
8136
|
}
|
|
@@ -8756,6 +8819,8 @@ var RECORD_BATCH_MAX = 1e3;
|
|
|
8756
8819
|
var RECORD_QUERY_MAX = 1e3;
|
|
8757
8820
|
/** A kind in the `settings` file may not bound itself above this (D447: high volume is `events`). */
|
|
8758
8821
|
var RECORD_SETTINGS_MAX_ROWS = 5e4;
|
|
8822
|
+
/** The `Column`-free proof prefix: a ref collection for a kind's secret fields. */
|
|
8823
|
+
var RECORD_SECRET_COLLECTION_PREFIX = "records:";
|
|
8759
8824
|
/**
|
|
8760
8825
|
* Secret fields of a record, addressed the way a Zod schema declares them
|
|
8761
8826
|
* (`collectZodSecretPaths`): dotted keys, `[]` for "each element of this array"
|
|
@@ -8792,6 +8857,112 @@ function secretArrayPrefixes(path) {
|
|
|
8792
8857
|
}
|
|
8793
8858
|
return prefixes;
|
|
8794
8859
|
}
|
|
8860
|
+
function isRecord$4(value) {
|
|
8861
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8862
|
+
}
|
|
8863
|
+
function elementId(element, idKey, declared, prefix) {
|
|
8864
|
+
const id = isRecord$4(element) ? element[idKey] : void 0;
|
|
8865
|
+
if (typeof id !== "string" || id.length === 0) throw new InvalidRecordError(`"${declared}": every element of "${prefix}" needs a non-empty string "${idKey}" to carry a secret`);
|
|
8866
|
+
return id;
|
|
8867
|
+
}
|
|
8868
|
+
/**
|
|
8869
|
+
* Visit every secret leaf PRESENT in `data` (an absent branch has nothing to
|
|
8870
|
+
* visit). `replace` returns the new leaf value, or {@link REMOVE_LEAF}; the
|
|
8871
|
+
* result is a new body, `data` is untouched.
|
|
8872
|
+
*/
|
|
8873
|
+
var REMOVE_LEAF = Symbol("remove-leaf");
|
|
8874
|
+
function mapAt(node, segments, index, walkedKeys, concretePrefix, declared, arrayKeys, visit) {
|
|
8875
|
+
if (!isRecord$4(node)) return node;
|
|
8876
|
+
const segment = segments[index];
|
|
8877
|
+
if (segment === void 0) return node;
|
|
8878
|
+
if (!Object.prototype.hasOwnProperty.call(node, segment.key)) return node;
|
|
8879
|
+
const child = node[segment.key];
|
|
8880
|
+
const keys = [...walkedKeys, segment.key];
|
|
8881
|
+
const last = index === segments.length - 1;
|
|
8882
|
+
if (segment.each) {
|
|
8883
|
+
if (!Array.isArray(child)) return node;
|
|
8884
|
+
const prefix = keys.join(".");
|
|
8885
|
+
const idKey = arrayKeys[prefix];
|
|
8886
|
+
if (idKey === void 0) throw new InvalidRecordError(`"${declared}": no id key declared for the array "${prefix}"`);
|
|
8887
|
+
const mapped = child.map((element) => {
|
|
8888
|
+
const id = elementId(element, idKey, declared, prefix);
|
|
8889
|
+
const concrete = `${concretePrefix}${concretePrefix.length > 0 ? "." : ""}${segment.key}[${encodeURIComponent(id)}]`;
|
|
8890
|
+
return last ? element : mapAt(element, segments, index + 1, keys, concrete, declared, arrayKeys, visit);
|
|
8891
|
+
});
|
|
8892
|
+
return {
|
|
8893
|
+
...node,
|
|
8894
|
+
[segment.key]: mapped
|
|
8895
|
+
};
|
|
8896
|
+
}
|
|
8897
|
+
const concrete = `${concretePrefix}${concretePrefix.length > 0 ? "." : ""}${segment.key}`;
|
|
8898
|
+
if (last) {
|
|
8899
|
+
const replacement = visit({
|
|
8900
|
+
declared,
|
|
8901
|
+
concrete,
|
|
8902
|
+
value: child
|
|
8903
|
+
});
|
|
8904
|
+
if (replacement === REMOVE_LEAF) return Object.fromEntries(Object.entries(node).filter(([key]) => key !== segment.key));
|
|
8905
|
+
return {
|
|
8906
|
+
...node,
|
|
8907
|
+
[segment.key]: replacement
|
|
8908
|
+
};
|
|
8909
|
+
}
|
|
8910
|
+
return {
|
|
8911
|
+
...node,
|
|
8912
|
+
[segment.key]: mapAt(child, segments, index + 1, keys, concrete, declared, arrayKeys, visit)
|
|
8913
|
+
};
|
|
8914
|
+
}
|
|
8915
|
+
/** Replace/remove every present secret leaf; returns a NEW body. */
|
|
8916
|
+
function mapSecretLeaves(data, paths, arrayKeys, visit) {
|
|
8917
|
+
let current = data;
|
|
8918
|
+
for (const declared of paths) current = mapAt(current, parseSecretPath(declared), 0, [], "", declared, arrayKeys, visit);
|
|
8919
|
+
return current;
|
|
8920
|
+
}
|
|
8921
|
+
/**
|
|
8922
|
+
* The keychain collection name a kind's secrets live under. Prefixed so a
|
|
8923
|
+
* record's refs never collide with the refs a legacy collection of the same name
|
|
8924
|
+
* already holds during an adoption.
|
|
8925
|
+
*/
|
|
8926
|
+
function recordSecretCollection(kind) {
|
|
8927
|
+
return `${RECORD_SECRET_COLLECTION_PREFIX}${kind}`;
|
|
8928
|
+
}
|
|
8929
|
+
/** The ONE ref a row's secret field may carry: the engine and the facade both build it here. */
|
|
8930
|
+
function recordSecretRef(owner, kind, rowId, concretePath) {
|
|
8931
|
+
return buildSecretRef({
|
|
8932
|
+
owner,
|
|
8933
|
+
scope: {
|
|
8934
|
+
kind: "row",
|
|
8935
|
+
collection: recordSecretCollection(kind),
|
|
8936
|
+
rowId
|
|
8937
|
+
},
|
|
8938
|
+
fieldPath: concretePath
|
|
8939
|
+
});
|
|
8940
|
+
}
|
|
8941
|
+
/**
|
|
8942
|
+
* A stored secret, as an admin read shows it: a VIEW naming the row's own
|
|
8943
|
+
* keychain ref (`set: true`), never the value and no longer the bare redaction
|
|
8944
|
+
* token. The form hands it to the secret field, which reveals the value by ref
|
|
8945
|
+
* through the audited `keychain-admin.reveal`; sent back untouched it keeps the
|
|
8946
|
+
* stored secret (the records door reads a view as KEEP).
|
|
8947
|
+
*
|
|
8948
|
+
* ONE implementation for the entries service and for every addon that serves
|
|
8949
|
+
* its own instances (`RecordIntegrationInstances`).
|
|
8950
|
+
*/
|
|
8951
|
+
function isRecord$3(value) {
|
|
8952
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8953
|
+
}
|
|
8954
|
+
function secretViewsOf(owner, kind, id, decl, data) {
|
|
8955
|
+
if (decl.secretPaths.length === 0) return data;
|
|
8956
|
+
const shown = mapSecretLeaves(data, decl.secretPaths, decl.secretArrayKeys, (leaf) => {
|
|
8957
|
+
if (leaf.value !== "__camstack_redacted__") return leaf.value;
|
|
8958
|
+
return {
|
|
8959
|
+
$secret: recordSecretRef(owner, kind, id, leaf.concrete),
|
|
8960
|
+
v: 1,
|
|
8961
|
+
set: true
|
|
8962
|
+
};
|
|
8963
|
+
});
|
|
8964
|
+
return isRecord$3(shown) ? shown : data;
|
|
8965
|
+
}
|
|
8795
8966
|
/**
|
|
8796
8967
|
* The share-view scope kinds a share-link token can carry. The hub mints
|
|
8797
8968
|
* and validates them (`ShareViewGrantSchema` builds its
|
|
@@ -9014,7 +9185,7 @@ function defineRecordKinds(specs) {
|
|
|
9014
9185
|
retention: spec.retention,
|
|
9015
9186
|
deviceRemoval: spec.deviceRemoval,
|
|
9016
9187
|
maxDataBytes: spec.maxDataBytes,
|
|
9017
|
-
secretPaths: [...secretPaths],
|
|
9188
|
+
secretPaths: [...new Set([...secretPaths, ...spec.retiredSecretPaths ?? []])],
|
|
9018
9189
|
secretArrayKeys: spec.secretArrayKeys === void 0 ? void 0 : { ...spec.secretArrayKeys },
|
|
9019
9190
|
transactFamily: spec.transactFamily,
|
|
9020
9191
|
entry: spec.entry === void 0 ? void 0 : {
|
|
@@ -9059,6 +9230,7 @@ function defineEntryKind(name, spec) {
|
|
|
9059
9230
|
...spec.database === void 0 ? {} : { database: spec.database },
|
|
9060
9231
|
...spec.indexes === void 0 ? {} : { indexes: spec.indexes },
|
|
9061
9232
|
...spec.secretArrayKeys === void 0 ? {} : { secretArrayKeys: spec.secretArrayKeys },
|
|
9233
|
+
...spec.retiredSecretPaths === void 0 ? {} : { retiredSecretPaths: spec.retiredSecretPaths },
|
|
9062
9234
|
entry: {
|
|
9063
9235
|
title: spec.title,
|
|
9064
9236
|
...spec.nameField === void 0 ? {} : { nameField: spec.nameField }
|
|
@@ -11786,7 +11958,7 @@ object({
|
|
|
11786
11958
|
params: record(string(), union([string(), number()])).optional()
|
|
11787
11959
|
});
|
|
11788
11960
|
//#endregion
|
|
11789
|
-
//#region ../types/dist/composition-
|
|
11961
|
+
//#region ../types/dist/composition-CRNwcFYY.mjs
|
|
11790
11962
|
/**
|
|
11791
11963
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11792
11964
|
*
|
|
@@ -12549,38 +12721,6 @@ function validateExpressionSource(src) {
|
|
|
12549
12721
|
return null;
|
|
12550
12722
|
}
|
|
12551
12723
|
/**
|
|
12552
|
-
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
12553
|
-
*
|
|
12554
|
-
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
12555
|
-
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
12556
|
-
* a cycle, so running starts only after 30 s above the line.
|
|
12557
|
-
*
|
|
12558
|
-
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
12559
|
-
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
12560
|
-
* report "finished" in the middle of the program, so the stop dwell is
|
|
12561
|
-
* 10 minutes on every type. The number is stored per type so one machine
|
|
12562
|
-
* can move later without moving the others.
|
|
12563
|
-
*/
|
|
12564
|
-
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
12565
|
-
var APPLIANCE_KINDS = [
|
|
12566
|
-
"washer",
|
|
12567
|
-
"dryer",
|
|
12568
|
-
"dishwasher"
|
|
12569
|
-
];
|
|
12570
|
-
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
12571
|
-
/**
|
|
12572
|
-
* A dumb plug-in stove or heater, built from a smart plug (a `Heater`).
|
|
12573
|
-
*
|
|
12574
|
-
* The plug is the actuator: `switch.setState` is a FORWARD to the plug's own
|
|
12575
|
-
* (D967), so the heater switches exactly as the plug does. Running is the
|
|
12576
|
-
* plug being on; when a power reading is also named, running is the draw
|
|
12577
|
-
* staying above the line instead (a plug left on with the stove's own
|
|
12578
|
-
* thermostat open is not heating). 50 W is far above any standby and below
|
|
12579
|
-
* the smallest radiator.
|
|
12580
|
-
*/
|
|
12581
|
-
var HEATER_TEMPLATE_ID = "heater";
|
|
12582
|
-
DeviceType.Heater;
|
|
12583
|
-
/**
|
|
12584
12724
|
* Statistics and integrals over a history read (D944).
|
|
12585
12725
|
*
|
|
12586
12726
|
* Pure: the same points always give the same answer, so a restart recomputes
|
|
@@ -12724,34 +12864,6 @@ var HelperSpecSchema = discriminatedUnion("kind", [
|
|
|
12724
12864
|
/** Actuator groups only. Readings leave this unset. */
|
|
12725
12865
|
active: ActiveCriterionSchema.optional()
|
|
12726
12866
|
}),
|
|
12727
|
-
object({
|
|
12728
|
-
kind: literal("appliance"),
|
|
12729
|
-
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
12730
|
-
appliance: _enum(APPLIANCE_KINDS),
|
|
12731
|
-
thresholdWatts: number().positive(),
|
|
12732
|
-
startDwellMs: number().int().nonnegative(),
|
|
12733
|
-
stopDwellMs: number().int().nonnegative(),
|
|
12734
|
-
member: HelperMemberSchema,
|
|
12735
|
-
/**
|
|
12736
|
-
* The plug that powers the appliance (`switch.on`). Optional: when set, the
|
|
12737
|
-
* composition carries a `power-source` feature, so the hub can cut and restore
|
|
12738
|
-
* that plug (power-source link of a NEW-target composition).
|
|
12739
|
-
*/
|
|
12740
|
-
powerSwitch: HelperMemberSchema.optional(),
|
|
12741
|
-
/** How long a forced restart keeps the plug off; the cap's default when unset. */
|
|
12742
|
-
offSeconds: number().optional()
|
|
12743
|
-
}),
|
|
12744
|
-
object({
|
|
12745
|
-
kind: literal("heater"),
|
|
12746
|
-
templateId: literal(HEATER_TEMPLATE_ID),
|
|
12747
|
-
/** The plug, read and commanded at `switch.on`. */
|
|
12748
|
-
plug: HelperMemberSchema,
|
|
12749
|
-
/** The plug's power reading, when it has one: running is then the draw, not the switch. */
|
|
12750
|
-
meter: HelperMemberSchema.optional(),
|
|
12751
|
-
thresholdWatts: number().positive(),
|
|
12752
|
-
startDwellMs: number().int().nonnegative(),
|
|
12753
|
-
stopDwellMs: number().int().nonnegative()
|
|
12754
|
-
}),
|
|
12755
12867
|
object({
|
|
12756
12868
|
kind: literal("statistic"),
|
|
12757
12869
|
stat: _enum(STATISTIC_STATS),
|
|
@@ -12975,7 +13087,7 @@ var CompositionSchema = object({
|
|
|
12975
13087
|
kind: literal("existing"),
|
|
12976
13088
|
device: CompositionSourceRefSchema
|
|
12977
13089
|
})]),
|
|
12978
|
-
features: array(CompositionFeatureSchema).min(
|
|
13090
|
+
features: array(CompositionFeatureSchema).min(0).max(16),
|
|
12979
13091
|
/**
|
|
12980
13092
|
* Present when the block is a helper template. Absent on a free
|
|
12981
13093
|
* composition (the room example, device 4603). The editor reads this,
|
|
@@ -13310,6 +13422,157 @@ function buildCapturingReply(envelope) {
|
|
|
13310
13422
|
};
|
|
13311
13423
|
return wrapper;
|
|
13312
13424
|
}
|
|
13425
|
+
/** The most instances one addon lists (an integrations page, not a table). */
|
|
13426
|
+
var INSTANCES_LIST_MAX = 1e3;
|
|
13427
|
+
/** The keys of the kind's secret fields that sit at the top level of the body. */
|
|
13428
|
+
function topLevelSecretKeys(paths) {
|
|
13429
|
+
return new Set(paths.filter((p) => !p.includes(".") && !p.includes("[")));
|
|
13430
|
+
}
|
|
13431
|
+
var RecordIntegrationInstances = class {
|
|
13432
|
+
records;
|
|
13433
|
+
kind;
|
|
13434
|
+
hooks;
|
|
13435
|
+
handle;
|
|
13436
|
+
secretKeys;
|
|
13437
|
+
nameField;
|
|
13438
|
+
constructor(records, kind, hooks) {
|
|
13439
|
+
this.records = records;
|
|
13440
|
+
this.kind = kind;
|
|
13441
|
+
this.hooks = hooks;
|
|
13442
|
+
this.handle = records.kind(kind);
|
|
13443
|
+
this.secretKeys = topLevelSecretKeys(kind.declaration.secretPaths);
|
|
13444
|
+
this.nameField = kind.declaration.entry?.nameField ?? "name";
|
|
13445
|
+
}
|
|
13446
|
+
/**
|
|
13447
|
+
* One instance read for the addon's own runtime; null when absent. When the keychain is
|
|
13448
|
+
* locked the row is served WITHOUT its secrets and says so (`secrets: 'unavailable'`), so the
|
|
13449
|
+
* caller can keep what it had instead of reconfiguring with an empty secret (D49).
|
|
13450
|
+
*/
|
|
13451
|
+
async readResolved(id) {
|
|
13452
|
+
try {
|
|
13453
|
+
const record = await this.handle.getResolved(id);
|
|
13454
|
+
return record === null ? null : {
|
|
13455
|
+
id,
|
|
13456
|
+
body: record.data,
|
|
13457
|
+
enabled: record.data.enabled !== false,
|
|
13458
|
+
secrets: "resolved"
|
|
13459
|
+
};
|
|
13460
|
+
} catch (err) {
|
|
13461
|
+
if (!(err instanceof RecordSecretUnavailableError)) throw err;
|
|
13462
|
+
const stored = await this.handle.get(id);
|
|
13463
|
+
if (stored === null) return null;
|
|
13464
|
+
return {
|
|
13465
|
+
id,
|
|
13466
|
+
body: Object.fromEntries(Object.entries(stored.data).filter(([key]) => !this.secretKeys.has(key))),
|
|
13467
|
+
enabled: stored.data.enabled !== false,
|
|
13468
|
+
secrets: "unavailable"
|
|
13469
|
+
};
|
|
13470
|
+
}
|
|
13471
|
+
}
|
|
13472
|
+
/** The body of {@link readResolved} alone; a locked keychain yields the row without secrets. */
|
|
13473
|
+
async getResolved(id) {
|
|
13474
|
+
return (await this.readResolved(id))?.body ?? null;
|
|
13475
|
+
}
|
|
13476
|
+
/** Every instance, secrets resolved where the keychain allows; an absent one is skipped. */
|
|
13477
|
+
async listResolved() {
|
|
13478
|
+
const page = await this.handle.query({ limit: INSTANCES_LIST_MAX });
|
|
13479
|
+
const out = [];
|
|
13480
|
+
for (const record of page.records) {
|
|
13481
|
+
const read = await this.readResolved(record.id);
|
|
13482
|
+
if (read !== null) out.push(read);
|
|
13483
|
+
}
|
|
13484
|
+
return out;
|
|
13485
|
+
}
|
|
13486
|
+
viewOf(record) {
|
|
13487
|
+
const shown = secretViewsOf(this.records.owner, this.kind.name, record.id, this.kind.declaration, record.data);
|
|
13488
|
+
const rawName = record.data[this.nameField];
|
|
13489
|
+
const kind = this.hooks.kindOf?.(record.data);
|
|
13490
|
+
const health = this.hooks.health?.(record.data, record.id);
|
|
13491
|
+
return {
|
|
13492
|
+
id: record.id,
|
|
13493
|
+
name: typeof rawName === "string" ? rawName : record.id,
|
|
13494
|
+
configured: this.hooks.configured(record.data),
|
|
13495
|
+
enabled: record.data.enabled !== false,
|
|
13496
|
+
formValues: shown,
|
|
13497
|
+
...kind !== void 0 ? { kind } : {},
|
|
13498
|
+
...health?.status !== void 0 ? { status: health.status } : {},
|
|
13499
|
+
...health?.lastCheckedAt !== void 0 ? { lastCheckedAt: health.lastCheckedAt } : {}
|
|
13500
|
+
};
|
|
13501
|
+
}
|
|
13502
|
+
describe = async () => this.hooks.mintId === void 0 ? this.hooks.description : {
|
|
13503
|
+
...this.hooks.description,
|
|
13504
|
+
mintsId: true
|
|
13505
|
+
};
|
|
13506
|
+
instanceFormSchema = async ({ id }) => this.hooks.formSchema(id);
|
|
13507
|
+
listInstances = async () => {
|
|
13508
|
+
return (await this.handle.query({ limit: INSTANCES_LIST_MAX })).records.map((record) => this.viewOf(record));
|
|
13509
|
+
};
|
|
13510
|
+
getInstance = async ({ id }) => {
|
|
13511
|
+
const record = await this.handle.get(id);
|
|
13512
|
+
return record === null ? null : this.viewOf(record);
|
|
13513
|
+
};
|
|
13514
|
+
/** Insert ONE row (`ifRev: 0`: an existing id is refused, never overwritten). */
|
|
13515
|
+
createInstance = async ({ id, name, kind }) => {
|
|
13516
|
+
const minted = id ?? this.hooks.mintId?.({
|
|
13517
|
+
name,
|
|
13518
|
+
...kind !== void 0 ? { kind } : {}
|
|
13519
|
+
});
|
|
13520
|
+
if (minted === void 0) throw new Error("createInstance needs an id: this provider does not mint one");
|
|
13521
|
+
await this.handle.put({
|
|
13522
|
+
id: minted,
|
|
13523
|
+
data: this.hooks.initialBody(name, kind)
|
|
13524
|
+
}, { ifRev: 0 });
|
|
13525
|
+
await this.hooks.onChanged?.(minted);
|
|
13526
|
+
return { id: minted };
|
|
13527
|
+
};
|
|
13528
|
+
updateInstance = async ({ id, name, values }) => {
|
|
13529
|
+
const patch = {};
|
|
13530
|
+
for (const [key, value] of Object.entries(values)) {
|
|
13531
|
+
if (value === void 0) continue;
|
|
13532
|
+
if (!this.secretKeys.has(key)) patch[key] = value;
|
|
13533
|
+
else if (isSecretClear(value)) patch[key] = null;
|
|
13534
|
+
else if (typeof value === "string" && value !== "" && value !== "__camstack_redacted__" && !isSecretFieldView(value)) patch[key] = value;
|
|
13535
|
+
}
|
|
13536
|
+
if (name !== void 0) patch[this.nameField] = name;
|
|
13537
|
+
await this.handle.patch(id, patch);
|
|
13538
|
+
await this.hooks.onChanged?.(id);
|
|
13539
|
+
return { ok: true };
|
|
13540
|
+
};
|
|
13541
|
+
/** The switch lives in the record body; the addon is told so it applies it (D996). */
|
|
13542
|
+
setInstanceEnabled = async ({ id, enabled }) => {
|
|
13543
|
+
await this.handle.patch(id, { enabled });
|
|
13544
|
+
await this.hooks.onChanged?.(id);
|
|
13545
|
+
return { ok: true };
|
|
13546
|
+
};
|
|
13547
|
+
/** The row and its keychain refs go together (the records door). */
|
|
13548
|
+
deleteInstance = async ({ id }) => {
|
|
13549
|
+
await this.handle.delete(id);
|
|
13550
|
+
await this.hooks.onChanged?.(id);
|
|
13551
|
+
return { ok: true };
|
|
13552
|
+
};
|
|
13553
|
+
testInstance = async (input) => {
|
|
13554
|
+
if (this.hooks.test === void 0) return {
|
|
13555
|
+
success: false,
|
|
13556
|
+
status: "unsupported",
|
|
13557
|
+
error: "This integration declares no connection test"
|
|
13558
|
+
};
|
|
13559
|
+
return this.hooks.test(input);
|
|
13560
|
+
};
|
|
13561
|
+
/** The flat provider object to hand to `registerProvider`. */
|
|
13562
|
+
toProvider() {
|
|
13563
|
+
return {
|
|
13564
|
+
describe: this.describe,
|
|
13565
|
+
instanceFormSchema: this.instanceFormSchema,
|
|
13566
|
+
listInstances: this.listInstances,
|
|
13567
|
+
getInstance: this.getInstance,
|
|
13568
|
+
createInstance: this.createInstance,
|
|
13569
|
+
updateInstance: this.updateInstance,
|
|
13570
|
+
setInstanceEnabled: this.setInstanceEnabled,
|
|
13571
|
+
deleteInstance: this.deleteInstance,
|
|
13572
|
+
testInstance: this.testInstance
|
|
13573
|
+
};
|
|
13574
|
+
}
|
|
13575
|
+
};
|
|
13313
13576
|
var EncodeProfileSchema = object({
|
|
13314
13577
|
video: object({
|
|
13315
13578
|
codec: _enum([
|
|
@@ -14415,6 +14678,58 @@ var MigrationOwnerStepSchema = object({
|
|
|
14415
14678
|
/** The ledger state the engine found: `pending` has no row yet. */
|
|
14416
14679
|
state: union([literal("pending"), MigrationStatusSchema])
|
|
14417
14680
|
});
|
|
14681
|
+
function isPlain(value) {
|
|
14682
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14683
|
+
}
|
|
14684
|
+
async function flattenNestedRecords(ports, spec) {
|
|
14685
|
+
const ids = await ports.listNested(spec.legacyKey);
|
|
14686
|
+
if (ids.length === 0) return {
|
|
14687
|
+
outcome: "already-done",
|
|
14688
|
+
summary: { converted: 0 }
|
|
14689
|
+
};
|
|
14690
|
+
const rows = /* @__PURE__ */ new Map();
|
|
14691
|
+
for (const id of ids) try {
|
|
14692
|
+
rows.set(id, await ports.readResolved(id));
|
|
14693
|
+
} catch (err) {
|
|
14694
|
+
const why = err instanceof Error ? err.message : String(err);
|
|
14695
|
+
throw new Error(`record '${id}': cannot be read with its secrets (${why}) - nothing moved`);
|
|
14696
|
+
}
|
|
14697
|
+
for (const [id, row] of rows) {
|
|
14698
|
+
const legacy = row[spec.legacyKey];
|
|
14699
|
+
if (!isPlain(legacy)) throw new Error(`record '${id}': '${spec.legacyKey}' is not an object - nothing moved`);
|
|
14700
|
+
const flat = spec.toFlat(legacy, row);
|
|
14701
|
+
await ports.patch(id, flat);
|
|
14702
|
+
const back = await ports.readResolved(id);
|
|
14703
|
+
const wrong = spec.flatSecretKeys.filter((key) => {
|
|
14704
|
+
const sent = flat[key];
|
|
14705
|
+
const got = back[key];
|
|
14706
|
+
return (typeof sent === "string" ? sent : "") !== (typeof got === "string" ? got : "");
|
|
14707
|
+
});
|
|
14708
|
+
if (wrong.length > 0) {
|
|
14709
|
+
await ports.patch(id, Object.fromEntries(Object.keys(flat).map((key) => [key, null])));
|
|
14710
|
+
throw new Error(`record '${id}': ${wrong.join(", ")} did not read back from its new home - the row is unchanged`);
|
|
14711
|
+
}
|
|
14712
|
+
await ports.patch(id, { [spec.legacyKey]: null });
|
|
14713
|
+
}
|
|
14714
|
+
return {
|
|
14715
|
+
outcome: "done",
|
|
14716
|
+
summary: { converted: rows.size }
|
|
14717
|
+
};
|
|
14718
|
+
}
|
|
14719
|
+
/** The ports over one kind's records handle. */
|
|
14720
|
+
function flattenPortsOver(handle) {
|
|
14721
|
+
return {
|
|
14722
|
+
listNested: async (legacyKey) => (await handle.query({ limit: 1e3 })).records.filter((r) => legacyKey in r.data).map((r) => r.id),
|
|
14723
|
+
readResolved: async (id) => {
|
|
14724
|
+
const row = await handle.getResolved(id);
|
|
14725
|
+
if (row === null) throw new Error("the record is gone");
|
|
14726
|
+
return row.data;
|
|
14727
|
+
},
|
|
14728
|
+
patch: async (id, patch) => {
|
|
14729
|
+
await handle.patch(id, patch);
|
|
14730
|
+
}
|
|
14731
|
+
};
|
|
14732
|
+
}
|
|
14418
14733
|
/**
|
|
14419
14734
|
* The trainer contract — what the hub hands the cloud trainer and what it
|
|
14420
14735
|
* gets back (cloud training, D805+).
|
|
@@ -50287,117 +50602,6 @@ function actuator(input) {
|
|
|
50287
50602
|
};
|
|
50288
50603
|
}
|
|
50289
50604
|
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
50290
|
-
var PowerSourceRefusalReasonSchema = _enum([
|
|
50291
|
-
"no-power-source",
|
|
50292
|
-
"switch-missing",
|
|
50293
|
-
"switch-offline",
|
|
50294
|
-
"switch-unknown",
|
|
50295
|
-
"restart-in-progress",
|
|
50296
|
-
"switch-call-failed"
|
|
50297
|
-
]);
|
|
50298
|
-
var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
|
|
50299
|
-
accepted: literal(false),
|
|
50300
|
-
reason: PowerSourceRefusalReasonSchema,
|
|
50301
|
-
/** One line for the operator, naming the switch. */
|
|
50302
|
-
message: string()
|
|
50303
|
-
})]);
|
|
50304
|
-
var PowerSourceInfoSchema = object({
|
|
50305
|
-
/** False when the device has no power source linked; the rest is then empty. */
|
|
50306
|
-
linked: boolean(),
|
|
50307
|
-
switchDeviceId: number().nullable(),
|
|
50308
|
-
switchName: string().nullable(),
|
|
50309
|
-
/** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
|
|
50310
|
-
switchOn: boolean().nullable(),
|
|
50311
|
-
switchOnline: boolean().nullable(),
|
|
50312
|
-
restartInProgress: boolean(),
|
|
50313
|
-
offSeconds: number().int()
|
|
50314
|
-
});
|
|
50315
|
-
/** The composed slice: the switch state the link mirrors, plus the stored off time. */
|
|
50316
|
-
var PowerSourceStateSchema = object({
|
|
50317
|
-
/** Null while the switch has not reported: unknown is never `false` (D393). */
|
|
50318
|
-
switchOn: boolean().nullable(),
|
|
50319
|
-
offSeconds: number().int(),
|
|
50320
|
-
lastFetchedAt: number()
|
|
50321
|
-
});
|
|
50322
|
-
var POWER_SOURCE_DEVICE_TYPES = [
|
|
50323
|
-
DeviceType.Gateway,
|
|
50324
|
-
DeviceType.Hub,
|
|
50325
|
-
DeviceType.Camera,
|
|
50326
|
-
DeviceType.Sensor,
|
|
50327
|
-
DeviceType.MediaPlayer,
|
|
50328
|
-
DeviceType.Vacuum,
|
|
50329
|
-
DeviceType.Generic,
|
|
50330
|
-
DeviceType.Washer,
|
|
50331
|
-
DeviceType.Dryer,
|
|
50332
|
-
DeviceType.Dishwasher,
|
|
50333
|
-
DeviceType.PetFountain,
|
|
50334
|
-
DeviceType.Fan,
|
|
50335
|
-
DeviceType.Humidifier,
|
|
50336
|
-
DeviceType.Climate,
|
|
50337
|
-
DeviceType.WaterHeater
|
|
50338
|
-
];
|
|
50339
|
-
var powerSourceCustomize = {
|
|
50340
|
-
version: 1,
|
|
50341
|
-
targets: [{
|
|
50342
|
-
id: "switch",
|
|
50343
|
-
cardinality: "scalar",
|
|
50344
|
-
vocabulary: {
|
|
50345
|
-
cap: "power-source",
|
|
50346
|
-
stateField: "switchOn"
|
|
50347
|
-
},
|
|
50348
|
-
deviceTypes: POWER_SOURCE_DEVICE_TYPES,
|
|
50349
|
-
apply: "add",
|
|
50350
|
-
path: "switchOn",
|
|
50351
|
-
sources: [{
|
|
50352
|
-
kind: "switch",
|
|
50353
|
-
transforms: [{ kind: "identity" }]
|
|
50354
|
-
}],
|
|
50355
|
-
companions: [{
|
|
50356
|
-
kind: "constant",
|
|
50357
|
-
path: "offSeconds",
|
|
50358
|
-
value: 10,
|
|
50359
|
-
when: "add"
|
|
50360
|
-
}, {
|
|
50361
|
-
kind: "clock",
|
|
50362
|
-
path: "lastFetchedAt",
|
|
50363
|
-
when: "always"
|
|
50364
|
-
}],
|
|
50365
|
-
sourceReport: { status: "assignment-status" }
|
|
50366
|
-
}]
|
|
50367
|
-
};
|
|
50368
|
-
var deviceInput$2 = object({ deviceId: number().int().nonnegative() });
|
|
50369
|
-
var powerSourceCapability = {
|
|
50370
|
-
name: "power-source",
|
|
50371
|
-
scope: "device",
|
|
50372
|
-
mode: "singleton",
|
|
50373
|
-
deviceTypes: POWER_SOURCE_DEVICE_TYPES,
|
|
50374
|
-
methods: {
|
|
50375
|
-
getStatus: systemMethod(deviceInput$2, PowerSourceInfoSchema, { auth: "admin" }),
|
|
50376
|
-
powerOn: systemMethod(deviceInput$2, PowerSourceActionResultSchema, {
|
|
50377
|
-
kind: "mutation",
|
|
50378
|
-
auth: "admin"
|
|
50379
|
-
}),
|
|
50380
|
-
powerOff: systemMethod(deviceInput$2, PowerSourceActionResultSchema, {
|
|
50381
|
-
kind: "mutation",
|
|
50382
|
-
auth: "admin"
|
|
50383
|
-
}),
|
|
50384
|
-
forceRestart: systemMethod(deviceInput$2, PowerSourceActionResultSchema, {
|
|
50385
|
-
kind: "mutation",
|
|
50386
|
-
auth: "admin"
|
|
50387
|
-
})
|
|
50388
|
-
},
|
|
50389
|
-
runtimeState: PowerSourceStateSchema,
|
|
50390
|
-
customize: powerSourceCustomize,
|
|
50391
|
-
/**
|
|
50392
|
-
* Runtime-state durability: **session** — mirrored from the linked switch on
|
|
50393
|
-
* its next report; a restored value would outlive the reading it names.
|
|
50394
|
-
*
|
|
50395
|
-
* See `RuntimeStateDurability`. Enforced by
|
|
50396
|
-
* `scripts/check-runtime-state-durability.ts`.
|
|
50397
|
-
*/
|
|
50398
|
-
durability: "session",
|
|
50399
|
-
history: "none"
|
|
50400
|
-
};
|
|
50401
50605
|
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
50402
50606
|
DeviceType.Camera;
|
|
50403
50607
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
@@ -50425,6 +50629,165 @@ var ComposableCapabilitiesSchema = object({ caps: array(object({
|
|
|
50425
50629
|
}).optional()
|
|
50426
50630
|
})) });
|
|
50427
50631
|
/**
|
|
50632
|
+
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
50633
|
+
* `z.infer`, they do not restate the shape.
|
|
50634
|
+
*/
|
|
50635
|
+
var OverrideSourceSchema = object({
|
|
50636
|
+
addonId: string().min(1),
|
|
50637
|
+
stableId: string().min(1),
|
|
50638
|
+
cap: string().min(1),
|
|
50639
|
+
fieldPath: string().min(1)
|
|
50640
|
+
});
|
|
50641
|
+
var IdentityTransformDraftSchema = object({ kind: literal("identity") });
|
|
50642
|
+
var InvertTransformDraftSchema = object({ kind: literal("invert") });
|
|
50643
|
+
var ThresholdTransformDraftSchema = object({
|
|
50644
|
+
kind: literal("threshold"),
|
|
50645
|
+
comparison: _enum(["gte", "lte"]),
|
|
50646
|
+
threshold: number(),
|
|
50647
|
+
startDwellMs: number().nonnegative(),
|
|
50648
|
+
stopDwellMs: number().nonnegative()
|
|
50649
|
+
});
|
|
50650
|
+
var CustomizeTransformDraftSchema = discriminatedUnion("kind", [
|
|
50651
|
+
IdentityTransformDraftSchema,
|
|
50652
|
+
InvertTransformDraftSchema,
|
|
50653
|
+
ThresholdTransformDraftSchema,
|
|
50654
|
+
object({
|
|
50655
|
+
kind: literal("linear"),
|
|
50656
|
+
scale: number(),
|
|
50657
|
+
offset: number(),
|
|
50658
|
+
clampMin: number().optional(),
|
|
50659
|
+
clampMax: number().optional()
|
|
50660
|
+
}),
|
|
50661
|
+
object({
|
|
50662
|
+
kind: literal("enum-map"),
|
|
50663
|
+
mapping: record(string(), string().nullable())
|
|
50664
|
+
}),
|
|
50665
|
+
object({ kind: literal("number") })
|
|
50666
|
+
]);
|
|
50667
|
+
var ScalarOverrideDraftSchema = object({
|
|
50668
|
+
kind: literal("scalar"),
|
|
50669
|
+
cap: string().min(1),
|
|
50670
|
+
targetId: string().min(1),
|
|
50671
|
+
source: OverrideSourceSchema,
|
|
50672
|
+
transform: CustomizeTransformDraftSchema
|
|
50673
|
+
});
|
|
50674
|
+
var KeyedArrayOverrideDraftSchema = object({
|
|
50675
|
+
kind: literal("keyedArray"),
|
|
50676
|
+
cap: string().min(1),
|
|
50677
|
+
targetId: string().min(1),
|
|
50678
|
+
key: string().min(1),
|
|
50679
|
+
label: string().min(1),
|
|
50680
|
+
fieldPath: string().min(1),
|
|
50681
|
+
source: OverrideSourceSchema,
|
|
50682
|
+
transform: CustomizeTransformDraftSchema
|
|
50683
|
+
});
|
|
50684
|
+
var PulseOverrideDraftSchema = object({
|
|
50685
|
+
kind: literal("pulse"),
|
|
50686
|
+
cap: string().min(1),
|
|
50687
|
+
targetId: string().min(1),
|
|
50688
|
+
enabled: boolean(),
|
|
50689
|
+
debounceMs: number().nonnegative(),
|
|
50690
|
+
edges: array(_enum([
|
|
50691
|
+
"rising",
|
|
50692
|
+
"button",
|
|
50693
|
+
"native-event"
|
|
50694
|
+
])).min(1).optional(),
|
|
50695
|
+
sources: array(OverrideSourceSchema).min(1)
|
|
50696
|
+
});
|
|
50697
|
+
var SpanSourceDraftSchema = OverrideSourceSchema.extend({ mode: _enum([
|
|
50698
|
+
"in-addition",
|
|
50699
|
+
"confirm",
|
|
50700
|
+
"replace"
|
|
50701
|
+
]).optional() });
|
|
50702
|
+
discriminatedUnion("kind", [
|
|
50703
|
+
ScalarOverrideDraftSchema,
|
|
50704
|
+
KeyedArrayOverrideDraftSchema,
|
|
50705
|
+
PulseOverrideDraftSchema,
|
|
50706
|
+
object({
|
|
50707
|
+
kind: literal("span"),
|
|
50708
|
+
cap: string().min(1),
|
|
50709
|
+
targetId: string().min(1),
|
|
50710
|
+
timeoutMs: number().nonnegative(),
|
|
50711
|
+
cooldownMs: number().nonnegative().optional(),
|
|
50712
|
+
sources: array(SpanSourceDraftSchema)
|
|
50713
|
+
})
|
|
50714
|
+
]);
|
|
50715
|
+
object({
|
|
50716
|
+
targetId: string().min(1),
|
|
50717
|
+
configured: boolean(),
|
|
50718
|
+
source: _enum(["native", "assigned"]),
|
|
50719
|
+
state: _enum([
|
|
50720
|
+
"active",
|
|
50721
|
+
"stale",
|
|
50722
|
+
"released",
|
|
50723
|
+
"unavailable"
|
|
50724
|
+
]),
|
|
50725
|
+
reason: string().nullable()
|
|
50726
|
+
});
|
|
50727
|
+
/**
|
|
50728
|
+
* What a running-threshold proposal says (planning#405). The schema is the
|
|
50729
|
+
* type: the algorithm, the capability method and the UI all read `z.infer`.
|
|
50730
|
+
*
|
|
50731
|
+
* A proposal is read-only advice: it carries the numbers it was derived from
|
|
50732
|
+
* (`evidence`) so the operator can judge it, and an `insufficient` answer names
|
|
50733
|
+
* WHY with a typed reason and the catalog defaults, never an invented number.
|
|
50734
|
+
*/
|
|
50735
|
+
var RunningProposalTierSchema = _enum(["raw", "5m"]);
|
|
50736
|
+
var RunningProposalConfidenceSchema = _enum([
|
|
50737
|
+
"high",
|
|
50738
|
+
"medium",
|
|
50739
|
+
"low"
|
|
50740
|
+
]);
|
|
50741
|
+
var RunningProposalInsufficientReasonSchema = _enum([
|
|
50742
|
+
"no-history",
|
|
50743
|
+
"span-too-short",
|
|
50744
|
+
"truncated",
|
|
50745
|
+
"no-idle-floor",
|
|
50746
|
+
"no-runs",
|
|
50747
|
+
"no-separation"
|
|
50748
|
+
]);
|
|
50749
|
+
var RunningProposalReplaySchema = object({
|
|
50750
|
+
/** Intervals the real dwell expression held true over the window. */
|
|
50751
|
+
intervals: number().int().nonnegative(),
|
|
50752
|
+
/** Intervals outside every run, or a second interval inside one. */
|
|
50753
|
+
extra: number().int().nonnegative(),
|
|
50754
|
+
/** Runs without an interval of their own (none, or merged into a neighbour). */
|
|
50755
|
+
missed: number().int().nonnegative()
|
|
50756
|
+
});
|
|
50757
|
+
var RunningProposalEvidenceSchema = object({
|
|
50758
|
+
tier: RunningProposalTierSchema,
|
|
50759
|
+
spanMs: number().nonnegative(),
|
|
50760
|
+
from: number(),
|
|
50761
|
+
to: number(),
|
|
50762
|
+
points: number().int().nonnegative(),
|
|
50763
|
+
runsFound: number().int().nonnegative(),
|
|
50764
|
+
pausesFound: number().int().nonnegative(),
|
|
50765
|
+
longestPauseMs: number().nonnegative(),
|
|
50766
|
+
idleFloorW: number(),
|
|
50767
|
+
noiseCeilingW: number(),
|
|
50768
|
+
plateauW: number(),
|
|
50769
|
+
replay: RunningProposalReplaySchema
|
|
50770
|
+
});
|
|
50771
|
+
var RunningProposalInsufficientEvidenceSchema = object({
|
|
50772
|
+
spanMs: number().nonnegative(),
|
|
50773
|
+
points: number().int().nonnegative(),
|
|
50774
|
+
runsFound: number().int().nonnegative()
|
|
50775
|
+
});
|
|
50776
|
+
var RunningThresholdProposalSchema = discriminatedUnion("state", [object({
|
|
50777
|
+
state: literal("proposal"),
|
|
50778
|
+
transform: ThresholdTransformDraftSchema,
|
|
50779
|
+
evidence: RunningProposalEvidenceSchema,
|
|
50780
|
+
confidence: RunningProposalConfidenceSchema,
|
|
50781
|
+
/** Why the confidence is not higher; empty when nothing held it back. */
|
|
50782
|
+
notes: array(string())
|
|
50783
|
+
}), object({
|
|
50784
|
+
state: literal("insufficient"),
|
|
50785
|
+
reason: RunningProposalInsufficientReasonSchema,
|
|
50786
|
+
evidence: RunningProposalInsufficientEvidenceSchema,
|
|
50787
|
+
/** The catalog defaults, offered as what stands when nothing better is known. */
|
|
50788
|
+
fallback: ThresholdTransformDraftSchema
|
|
50789
|
+
})]);
|
|
50790
|
+
/**
|
|
50428
50791
|
* The report of a one-shot "move this owner's plaintext secrets into the
|
|
50429
50792
|
* keychain" run (D878). COUNTS only - never a value, never a ref.
|
|
50430
50793
|
*
|
|
@@ -50714,6 +51077,14 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
|
|
|
50714
51077
|
kind: "mutation",
|
|
50715
51078
|
auth: "admin",
|
|
50716
51079
|
access: "view"
|
|
51080
|
+
}), method(object({
|
|
51081
|
+
deviceId: number().int(),
|
|
51082
|
+
cap: string().min(1),
|
|
51083
|
+
fieldPath: string().min(1),
|
|
51084
|
+
deviceType: _enum(DeviceType).optional()
|
|
51085
|
+
}), RunningThresholdProposalSchema, {
|
|
51086
|
+
auth: "admin",
|
|
51087
|
+
access: "view"
|
|
50717
51088
|
}), method(object({
|
|
50718
51089
|
blockId: string().min(1),
|
|
50719
51090
|
trace: AutomationRunTraceSchema.optional(),
|
|
@@ -51690,7 +52061,46 @@ method(object({
|
|
|
51690
52061
|
* exposes only the COMMON surface: link state, supported device
|
|
51691
52062
|
* kinds (so the UI can filter the device picker), and per-device
|
|
51692
52063
|
* expose/unexpose.
|
|
52064
|
+
*
|
|
52065
|
+
* INSTANCES. One export addon can serve several independent targets (a
|
|
52066
|
+
* HomeKit bridge, a Home Assistant broker). `listInstances` names them.
|
|
52067
|
+
* `instanceId` on a READ is optional: absent = the whole addon (linked if any
|
|
52068
|
+
* enabled instance is, `exposedDeviceCount` = distinct devices, `setup` = the
|
|
52069
|
+
* default instance's); present = that instance; an id the provider does not
|
|
52070
|
+
* serve is refused with `ExportInstanceUnknownError` (`export-instance-unknown`),
|
|
52071
|
+
* never answered empty. `instanceId` on a WRITE is REQUIRED: a membership
|
|
52072
|
+
* change always names the target it changes. A single-instance provider
|
|
52073
|
+
* accepts an absent id on a read or its own id, and refuses any other.
|
|
52074
|
+
*/
|
|
52075
|
+
/** Which instance of an export addon a call addresses. Absent on a read = the whole addon. */
|
|
52076
|
+
var InstanceIdSchema$1 = string().min(1);
|
|
52077
|
+
var InstancePinSchema = object({ instanceId: InstanceIdSchema$1.optional() });
|
|
52078
|
+
/** One independent export target of an addon. */
|
|
52079
|
+
var ExportInstanceSchema = object({
|
|
52080
|
+
instanceId: InstanceIdSchema$1,
|
|
52081
|
+
name: string(),
|
|
52082
|
+
enabled: boolean(),
|
|
52083
|
+
kind: string().optional()
|
|
52084
|
+
});
|
|
52085
|
+
var EXPORT_INSTANCE_UNKNOWN = "export-instance-unknown";
|
|
52086
|
+
/** The named failure of an `instanceId` the provider does not serve. The message starts with the code. */
|
|
52087
|
+
var ExportInstanceUnknownError = class extends Error {
|
|
52088
|
+
code = EXPORT_INSTANCE_UNKNOWN;
|
|
52089
|
+
instanceId;
|
|
52090
|
+
constructor(addon, instanceId) {
|
|
52091
|
+
super(`${EXPORT_INSTANCE_UNKNOWN}: ${addon} serves no instance "${instanceId}"`);
|
|
52092
|
+
this.name = "ExportInstanceUnknownError";
|
|
52093
|
+
this.instanceId = instanceId;
|
|
52094
|
+
}
|
|
52095
|
+
};
|
|
52096
|
+
/**
|
|
52097
|
+
* The instance a `getStatus` call names. The cap's `status` block injects a per-device
|
|
52098
|
+
* `getStatus({ deviceId })` beside the method's own `{ instanceId? }`, so the provider sees
|
|
52099
|
+
* both shapes; only the second names an instance (a per-device status read is addon-wide).
|
|
51693
52100
|
*/
|
|
52101
|
+
function statusInstanceOf(input) {
|
|
52102
|
+
return "instanceId" in input ? input.instanceId : void 0;
|
|
52103
|
+
}
|
|
51694
52104
|
var LinkStateSchema = _enum([
|
|
51695
52105
|
"unlinked",
|
|
51696
52106
|
"linked",
|
|
@@ -51741,10 +52151,14 @@ var ExposedDeviceSchema = object({
|
|
|
51741
52151
|
capabilities: array(string()).optional()
|
|
51742
52152
|
});
|
|
51743
52153
|
var ExposeInputSchema = object({
|
|
52154
|
+
instanceId: InstanceIdSchema$1,
|
|
51744
52155
|
deviceId: string(),
|
|
51745
52156
|
capabilities: array(string()).optional()
|
|
51746
52157
|
});
|
|
51747
|
-
var UnexposeInputSchema = object({
|
|
52158
|
+
var UnexposeInputSchema = object({
|
|
52159
|
+
instanceId: InstanceIdSchema$1,
|
|
52160
|
+
deviceId: string()
|
|
52161
|
+
});
|
|
51748
52162
|
/**
|
|
51749
52163
|
* What an exporter may expose besides devices (D968). An action and a
|
|
51750
52164
|
* notification target are LIST ENTRIES, never devices (D954): they enter an
|
|
@@ -51773,8 +52187,14 @@ var ExposedEntitySchema = object({
|
|
|
51773
52187
|
entity: ExportEntityRefSchema,
|
|
51774
52188
|
exposedAs: string().optional()
|
|
51775
52189
|
});
|
|
51776
|
-
var ExposeEntityInputSchema = object({
|
|
51777
|
-
|
|
52190
|
+
var ExposeEntityInputSchema = object({
|
|
52191
|
+
instanceId: InstanceIdSchema$1,
|
|
52192
|
+
entity: ExportEntityRefSchema
|
|
52193
|
+
});
|
|
52194
|
+
var UnexposeEntityInputSchema = object({
|
|
52195
|
+
instanceId: InstanceIdSchema$1,
|
|
52196
|
+
entity: ExportEntityRefSchema
|
|
52197
|
+
});
|
|
51778
52198
|
var deviceExportCapability = {
|
|
51779
52199
|
name: "device-export",
|
|
51780
52200
|
scope: "system",
|
|
@@ -51794,9 +52214,10 @@ var deviceExportCapability = {
|
|
|
51794
52214
|
*/
|
|
51795
52215
|
exposesDeviceSettings: true,
|
|
51796
52216
|
methods: {
|
|
51797
|
-
getStatus: method(
|
|
51798
|
-
|
|
51799
|
-
|
|
52217
|
+
getStatus: method(InstancePinSchema, DeviceExportStatusSchema),
|
|
52218
|
+
listInstances: method(_void(), array(ExportInstanceSchema)),
|
|
52219
|
+
listSupportedDeviceKinds: method(InstancePinSchema, array(DeviceKindSchema)),
|
|
52220
|
+
listExposedDevices: method(InstancePinSchema, array(ExposedDeviceSchema)),
|
|
51800
52221
|
exposeDevice: method(ExposeInputSchema, _void(), {
|
|
51801
52222
|
kind: "mutation",
|
|
51802
52223
|
auth: "admin"
|
|
@@ -51806,7 +52227,7 @@ var deviceExportCapability = {
|
|
|
51806
52227
|
auth: "admin"
|
|
51807
52228
|
}),
|
|
51808
52229
|
listSupportedEntityKinds: optionalMethod(_void(), array(ExportEntityKindSchema)),
|
|
51809
|
-
listExposedEntities: optionalMethod(
|
|
52230
|
+
listExposedEntities: optionalMethod(InstancePinSchema, array(ExposedEntitySchema)),
|
|
51810
52231
|
exposeEntity: optionalMethod(ExposeEntityInputSchema, _void(), {
|
|
51811
52232
|
kind: "mutation",
|
|
51812
52233
|
auth: "admin"
|
|
@@ -55411,15 +55832,15 @@ var FanPresetCaptureResultSchema = object({
|
|
|
55411
55832
|
items: array(FanCaptureItemSchema),
|
|
55412
55833
|
omitted: array(FanCaptureOmissionSchema)
|
|
55413
55834
|
});
|
|
55414
|
-
var deviceInput$
|
|
55835
|
+
var deviceInput$2 = object({ deviceId: number().int().nonnegative() });
|
|
55415
55836
|
DeviceType.Fan;
|
|
55416
|
-
method(deviceInput$
|
|
55837
|
+
method(deviceInput$2, array(FanPresetSchema), { auth: "protected" }), method(deviceInput$2.extend({ presets: array(FanPresetSchema).max(12) }), FanPresetsSetResultSchema, {
|
|
55417
55838
|
kind: "mutation",
|
|
55418
55839
|
auth: "admin"
|
|
55419
|
-
}), method(deviceInput$
|
|
55840
|
+
}), method(deviceInput$2.extend({ presetId: string().min(1) }), FanPresetApplyResultSchema, {
|
|
55420
55841
|
kind: "mutation",
|
|
55421
55842
|
auth: "protected"
|
|
55422
|
-
}), method(deviceInput$
|
|
55843
|
+
}), method(deviceInput$2.extend({
|
|
55423
55844
|
fields: array(FanCaptureFieldSchema).optional(),
|
|
55424
55845
|
steps: array(ActionStepSchema).max(20).default([])
|
|
55425
55846
|
}), FanPresetCaptureResultSchema, { auth: "protected" });
|
|
@@ -56330,13 +56751,50 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
|
|
|
56330
56751
|
*/
|
|
56331
56752
|
var ConfigSchemaPassthrough$3 = custom();
|
|
56332
56753
|
var IntegrationInstanceIdSchema = string().min(1);
|
|
56754
|
+
var IntegrationInstanceModeSchema = _enum(["single", "multiple"]);
|
|
56755
|
+
/**
|
|
56756
|
+
* One kind of instance a provider can create (an adapter, an account type). The sign-in and
|
|
56757
|
+
* connect fields follow the `broker` contract (`broker.cap.ts`): `signIn.basePath` is a
|
|
56758
|
+
* hub-relative route set speaking the sign-in contract, `connectPath` / `disconnectPath` open an
|
|
56759
|
+
* interactive account link (popup) and may carry `{{brokerId}}`, which the UI replaces with the
|
|
56760
|
+
* instance id.
|
|
56761
|
+
*/
|
|
56762
|
+
var IntegrationInstanceKindSchema = object({
|
|
56763
|
+
/** Stable id of the kind, sent back as `createInstance.kind`. */
|
|
56764
|
+
id: string().min(1),
|
|
56765
|
+
label: string().min(1),
|
|
56766
|
+
/** The kind signs in through a server-held interactive session. */
|
|
56767
|
+
signIn: object({
|
|
56768
|
+
basePath: string().min(1),
|
|
56769
|
+
methods: array(_enum(["device-code", "proxy"])).optional()
|
|
56770
|
+
}).optional(),
|
|
56771
|
+
/** Relative hub path to start an interactive account link of an instance of this kind. */
|
|
56772
|
+
connectPath: string().min(1).optional(),
|
|
56773
|
+
/** Relative hub path to disconnect that account. */
|
|
56774
|
+
disconnectPath: string().min(1).optional()
|
|
56775
|
+
});
|
|
56333
56776
|
var IntegrationInstanceDescriptionSchema = object({
|
|
56334
56777
|
/** `single`: at most one instance can exist (Loki). `multiple`: an account each. */
|
|
56335
|
-
instanceMode:
|
|
56778
|
+
instanceMode: IntegrationInstanceModeSchema,
|
|
56336
56779
|
/** What the instance is, for the UI (`destination`, `relay`, `account`). */
|
|
56337
56780
|
kind: string(),
|
|
56338
56781
|
/** True when `testInstance` really probes the remote. */
|
|
56339
|
-
canTest: boolean()
|
|
56782
|
+
canTest: boolean(),
|
|
56783
|
+
/**
|
|
56784
|
+
* The kinds an instance can be of. Absent or one entry: nothing to choose; more than one: the
|
|
56785
|
+
* Add flow asks which first and sends it as `createInstance.kind`.
|
|
56786
|
+
*/
|
|
56787
|
+
kinds: array(IntegrationInstanceKindSchema).optional(),
|
|
56788
|
+
/**
|
|
56789
|
+
* The provider accepts `createInstance.id` for an id that once existed (an adopted id, because
|
|
56790
|
+
* devices carry it). The UI then offers "restore under its old id" on Add. Absent means no.
|
|
56791
|
+
*/
|
|
56792
|
+
allowRestoreId: boolean().optional(),
|
|
56793
|
+
/**
|
|
56794
|
+
* `createInstance` without an `id` works: the provider mints it. Absent means the caller must
|
|
56795
|
+
* send an id (the UI then mints an opaque one).
|
|
56796
|
+
*/
|
|
56797
|
+
mintsId: boolean().optional()
|
|
56340
56798
|
});
|
|
56341
56799
|
var IntegrationInstanceStatusSchema = object({
|
|
56342
56800
|
state: _enum([
|
|
@@ -56345,7 +56803,9 @@ var IntegrationInstanceStatusSchema = object({
|
|
|
56345
56803
|
"error",
|
|
56346
56804
|
"unknown"
|
|
56347
56805
|
]),
|
|
56348
|
-
detail: string().optional()
|
|
56806
|
+
detail: string().optional(),
|
|
56807
|
+
/** A short human word for the state ("Signed in", "Token expired"); shown instead of `state`. */
|
|
56808
|
+
label: string().optional()
|
|
56349
56809
|
});
|
|
56350
56810
|
var IntegrationInstanceSchema = object({
|
|
56351
56811
|
id: IntegrationInstanceIdSchema,
|
|
@@ -56357,9 +56817,13 @@ var IntegrationInstanceSchema = object({
|
|
|
56357
56817
|
* (`enabled !== false`, so a row written before the field existed is on).
|
|
56358
56818
|
*/
|
|
56359
56819
|
enabled: boolean(),
|
|
56820
|
+
/** The kind of this instance (one of `describe().kinds[].id`), when the provider has kinds. */
|
|
56821
|
+
kind: string().optional(),
|
|
56360
56822
|
/** Values for the instance form; a secret is a `SecretFieldView`, never text. */
|
|
56361
56823
|
formValues: record(string(), unknown()),
|
|
56362
|
-
status: IntegrationInstanceStatusSchema.optional()
|
|
56824
|
+
status: IntegrationInstanceStatusSchema.optional(),
|
|
56825
|
+
/** Epoch ms of the last probe of the remote that produced `status`; absent when never checked. */
|
|
56826
|
+
lastCheckedAt: number().optional()
|
|
56363
56827
|
});
|
|
56364
56828
|
var IntegrationInstancePatchSchema = object({
|
|
56365
56829
|
id: IntegrationInstanceIdSchema,
|
|
@@ -56367,31 +56831,57 @@ var IntegrationInstancePatchSchema = object({
|
|
|
56367
56831
|
/** Omitted / '' / redaction token keeps a secret; `{ $secretClear: true }` clears it. */
|
|
56368
56832
|
values: record(string(), unknown())
|
|
56369
56833
|
});
|
|
56370
|
-
|
|
56371
|
-
|
|
56372
|
-
|
|
56373
|
-
|
|
56374
|
-
|
|
56375
|
-
|
|
56376
|
-
|
|
56377
|
-
|
|
56378
|
-
|
|
56379
|
-
|
|
56380
|
-
|
|
56381
|
-
|
|
56382
|
-
|
|
56383
|
-
|
|
56384
|
-
|
|
56385
|
-
|
|
56386
|
-
|
|
56387
|
-
|
|
56388
|
-
}),
|
|
56389
|
-
|
|
56390
|
-
|
|
56391
|
-
}),
|
|
56392
|
-
|
|
56393
|
-
|
|
56394
|
-
|
|
56834
|
+
var integrationInstancesCapability = {
|
|
56835
|
+
name: "integration-instances",
|
|
56836
|
+
scope: "system",
|
|
56837
|
+
mode: "collection",
|
|
56838
|
+
methods: {
|
|
56839
|
+
describe: method(_void(), IntegrationInstanceDescriptionSchema, { auth: "admin" }),
|
|
56840
|
+
/** The form; `id: null` is the create form. */
|
|
56841
|
+
instanceFormSchema: method(object({ id: IntegrationInstanceIdSchema.nullable() }), ConfigSchemaPassthrough$3, { auth: "admin" }),
|
|
56842
|
+
listInstances: method(_void(), array(IntegrationInstanceSchema).readonly(), { auth: "admin" }),
|
|
56843
|
+
getInstance: method(object({ id: IntegrationInstanceIdSchema }), IntegrationInstanceSchema.nullable(), { auth: "admin" }),
|
|
56844
|
+
/**
|
|
56845
|
+
* Insert the typed record. With `id` it is stored under that id (a duplicate id is refused);
|
|
56846
|
+
* without one the PROVIDER mints it and answers it. `kind` picks one of `describe().kinds`.
|
|
56847
|
+
*/
|
|
56848
|
+
createInstance: method(object({
|
|
56849
|
+
id: IntegrationInstanceIdSchema.optional(),
|
|
56850
|
+
name: string().min(1),
|
|
56851
|
+
kind: string().min(1).optional()
|
|
56852
|
+
}), object({ id: string() }), {
|
|
56853
|
+
kind: "mutation",
|
|
56854
|
+
auth: "admin"
|
|
56855
|
+
}),
|
|
56856
|
+
updateInstance: method(IntegrationInstancePatchSchema, object({ ok: literal(true) }), {
|
|
56857
|
+
kind: "mutation",
|
|
56858
|
+
auth: "admin"
|
|
56859
|
+
}),
|
|
56860
|
+
/**
|
|
56861
|
+
* Switch ONE instance on or off. A row control, not a form field: `updateInstance.values` is the
|
|
56862
|
+
* form patch (D62, D996). An off instance keeps its record and secrets and does no work.
|
|
56863
|
+
*/
|
|
56864
|
+
setInstanceEnabled: method(object({
|
|
56865
|
+
id: IntegrationInstanceIdSchema,
|
|
56866
|
+
enabled: boolean()
|
|
56867
|
+
}), object({ ok: literal(true) }), {
|
|
56868
|
+
kind: "mutation",
|
|
56869
|
+
auth: "admin"
|
|
56870
|
+
}),
|
|
56871
|
+
/** Delete the record and its keychain refs together. */
|
|
56872
|
+
deleteInstance: method(object({ id: IntegrationInstanceIdSchema }), object({ ok: literal(true) }), {
|
|
56873
|
+
kind: "mutation",
|
|
56874
|
+
auth: "admin"
|
|
56875
|
+
}),
|
|
56876
|
+
testInstance: optionalMethod(object({
|
|
56877
|
+
id: IntegrationInstanceIdSchema.nullable(),
|
|
56878
|
+
values: record(string(), unknown())
|
|
56879
|
+
}), TestConnectionResultSchema$1, {
|
|
56880
|
+
kind: "mutation",
|
|
56881
|
+
auth: "admin"
|
|
56882
|
+
})
|
|
56883
|
+
}
|
|
56884
|
+
};
|
|
56395
56885
|
/**
|
|
56396
56886
|
* Two-way audio / talk-back cap. Clients open a WebRTC audio-only
|
|
56397
56887
|
* session (server-initiated offer pattern, identical to the main
|
|
@@ -58409,6 +58899,11 @@ var LogEntrySchema = object({
|
|
|
58409
58899
|
* flight, and not asking for the next slice ends the scan.
|
|
58410
58900
|
*/
|
|
58411
58901
|
var LogReadQuerySchema = object({
|
|
58902
|
+
/**
|
|
58903
|
+
* Which destination INSTANCE answers (a destination addon may hold several records). Absent ⇒
|
|
58904
|
+
* the provider's first readable one, so a caller written before instances existed is unchanged.
|
|
58905
|
+
*/
|
|
58906
|
+
instanceId: string().min(1).max(200).optional(),
|
|
58412
58907
|
/** Correlates `cancelRead`. Caller-chosen, unique per in-flight read. */
|
|
58413
58908
|
requestId: string().min(1).max(64).optional(),
|
|
58414
58909
|
/** The device the line is about (`tags.deviceId`, numeric). */
|
|
@@ -58471,6 +58966,8 @@ var LogReadResultSchema = object({
|
|
|
58471
58966
|
/** True when `cancelRead` ended this slice early. */
|
|
58472
58967
|
cancelled: boolean().optional()
|
|
58473
58968
|
});
|
|
58969
|
+
/** Names one destination instance; absent ⇒ the provider's first readable one. */
|
|
58970
|
+
var LogInstanceSelectorSchema = object({ instanceId: string().min(1).max(200).optional() });
|
|
58474
58971
|
var LogReadCapabilitiesSchema = object({
|
|
58475
58972
|
/** False ⇒ this destination only ships lines (console, forwarder, an unconfigured Loki). */
|
|
58476
58973
|
readable: boolean(),
|
|
@@ -58489,7 +58986,7 @@ var LogReadCapabilitiesSchema = object({
|
|
|
58489
58986
|
/** How far back the store reaches, when the provider knows (days). */
|
|
58490
58987
|
retentionDays: number().nullable()
|
|
58491
58988
|
});
|
|
58492
|
-
method(LogEntrySchema, _void(), { kind: "mutation" }), optionalMethod(
|
|
58989
|
+
method(LogEntrySchema, _void(), { kind: "mutation" }), optionalMethod(LogInstanceSelectorSchema, LogReadCapabilitiesSchema, { auth: "admin" }), optionalMethod(LogReadQuerySchema, LogReadResultSchema, { auth: "admin" }), optionalMethod(object({ requestId: string().min(1).max(64) }), object({ cancelled: boolean() }), {
|
|
58493
58990
|
kind: "mutation",
|
|
58494
58991
|
auth: "admin"
|
|
58495
58992
|
});
|
|
@@ -70832,6 +71329,14 @@ var powerMeterCapability = {
|
|
|
70832
71329
|
deviceNative: true,
|
|
70833
71330
|
mode: "singleton",
|
|
70834
71331
|
deviceTypes: POWER_METER_DEVICE_TYPES,
|
|
71332
|
+
deviceConfig: { ui: {
|
|
71333
|
+
kind: "widget",
|
|
71334
|
+
widgetId: "host/power-meter-line",
|
|
71335
|
+
tab: "power",
|
|
71336
|
+
placement: "hero",
|
|
71337
|
+
label: "Power",
|
|
71338
|
+
order: 4
|
|
71339
|
+
} },
|
|
70835
71340
|
methods: {},
|
|
70836
71341
|
status: {
|
|
70837
71342
|
schema: PowerMeterStatusSchema,
|
|
@@ -70891,6 +71396,117 @@ var powerMeterCapability = {
|
|
|
70891
71396
|
volatileStateFields: ["lastFetchedAt"],
|
|
70892
71397
|
customize: powerMeterCustomize
|
|
70893
71398
|
};
|
|
71399
|
+
var PowerSourceRefusalReasonSchema = _enum([
|
|
71400
|
+
"no-power-source",
|
|
71401
|
+
"switch-missing",
|
|
71402
|
+
"switch-offline",
|
|
71403
|
+
"switch-unknown",
|
|
71404
|
+
"restart-in-progress",
|
|
71405
|
+
"switch-call-failed"
|
|
71406
|
+
]);
|
|
71407
|
+
var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
|
|
71408
|
+
accepted: literal(false),
|
|
71409
|
+
reason: PowerSourceRefusalReasonSchema,
|
|
71410
|
+
/** One line for the operator, naming the switch. */
|
|
71411
|
+
message: string()
|
|
71412
|
+
})]);
|
|
71413
|
+
var PowerSourceInfoSchema = object({
|
|
71414
|
+
/** False when the device has no power source linked; the rest is then empty. */
|
|
71415
|
+
linked: boolean(),
|
|
71416
|
+
switchDeviceId: number().nullable(),
|
|
71417
|
+
switchName: string().nullable(),
|
|
71418
|
+
/** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
|
|
71419
|
+
switchOn: boolean().nullable(),
|
|
71420
|
+
switchOnline: boolean().nullable(),
|
|
71421
|
+
restartInProgress: boolean(),
|
|
71422
|
+
offSeconds: number().int()
|
|
71423
|
+
});
|
|
71424
|
+
/** The composed slice: the switch state the link mirrors, plus the stored off time. */
|
|
71425
|
+
var PowerSourceStateSchema = object({
|
|
71426
|
+
/** Null while the switch has not reported: unknown is never `false` (D393). */
|
|
71427
|
+
switchOn: boolean().nullable(),
|
|
71428
|
+
offSeconds: number().int(),
|
|
71429
|
+
lastFetchedAt: number()
|
|
71430
|
+
});
|
|
71431
|
+
var POWER_SOURCE_DEVICE_TYPES = [
|
|
71432
|
+
DeviceType.Gateway,
|
|
71433
|
+
DeviceType.Hub,
|
|
71434
|
+
DeviceType.Camera,
|
|
71435
|
+
DeviceType.Sensor,
|
|
71436
|
+
DeviceType.MediaPlayer,
|
|
71437
|
+
DeviceType.Vacuum,
|
|
71438
|
+
DeviceType.Generic,
|
|
71439
|
+
DeviceType.Washer,
|
|
71440
|
+
DeviceType.Dryer,
|
|
71441
|
+
DeviceType.Dishwasher,
|
|
71442
|
+
DeviceType.PetFountain,
|
|
71443
|
+
DeviceType.Fan,
|
|
71444
|
+
DeviceType.Humidifier,
|
|
71445
|
+
DeviceType.Climate,
|
|
71446
|
+
DeviceType.WaterHeater
|
|
71447
|
+
];
|
|
71448
|
+
var powerSourceCustomize = {
|
|
71449
|
+
version: 1,
|
|
71450
|
+
targets: [{
|
|
71451
|
+
id: "switch",
|
|
71452
|
+
cardinality: "scalar",
|
|
71453
|
+
vocabulary: {
|
|
71454
|
+
cap: "power-source",
|
|
71455
|
+
stateField: "switchOn"
|
|
71456
|
+
},
|
|
71457
|
+
deviceTypes: POWER_SOURCE_DEVICE_TYPES,
|
|
71458
|
+
apply: "add",
|
|
71459
|
+
path: "switchOn",
|
|
71460
|
+
sources: [{
|
|
71461
|
+
kind: "switch",
|
|
71462
|
+
transforms: [{ kind: "identity" }]
|
|
71463
|
+
}],
|
|
71464
|
+
companions: [{
|
|
71465
|
+
kind: "constant",
|
|
71466
|
+
path: "offSeconds",
|
|
71467
|
+
value: 10,
|
|
71468
|
+
when: "add"
|
|
71469
|
+
}, {
|
|
71470
|
+
kind: "clock",
|
|
71471
|
+
path: "lastFetchedAt",
|
|
71472
|
+
when: "always"
|
|
71473
|
+
}],
|
|
71474
|
+
sourceReport: { status: "assignment-status" }
|
|
71475
|
+
}]
|
|
71476
|
+
};
|
|
71477
|
+
var deviceInput$1 = object({ deviceId: number().int().nonnegative() });
|
|
71478
|
+
var powerSourceCapability = {
|
|
71479
|
+
name: "power-source",
|
|
71480
|
+
scope: "device",
|
|
71481
|
+
mode: "singleton",
|
|
71482
|
+
deviceTypes: POWER_SOURCE_DEVICE_TYPES,
|
|
71483
|
+
methods: {
|
|
71484
|
+
getStatus: systemMethod(deviceInput$1, PowerSourceInfoSchema, { auth: "admin" }),
|
|
71485
|
+
powerOn: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
|
|
71486
|
+
kind: "mutation",
|
|
71487
|
+
auth: "admin"
|
|
71488
|
+
}),
|
|
71489
|
+
powerOff: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
|
|
71490
|
+
kind: "mutation",
|
|
71491
|
+
auth: "admin"
|
|
71492
|
+
}),
|
|
71493
|
+
forceRestart: systemMethod(deviceInput$1, PowerSourceActionResultSchema, {
|
|
71494
|
+
kind: "mutation",
|
|
71495
|
+
auth: "admin"
|
|
71496
|
+
})
|
|
71497
|
+
},
|
|
71498
|
+
runtimeState: PowerSourceStateSchema,
|
|
71499
|
+
customize: powerSourceCustomize,
|
|
71500
|
+
/**
|
|
71501
|
+
* Runtime-state durability: **session** — mirrored from the linked switch on
|
|
71502
|
+
* its next report; a restored value would outlive the reading it names.
|
|
71503
|
+
*
|
|
71504
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
71505
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
71506
|
+
*/
|
|
71507
|
+
durability: "session",
|
|
71508
|
+
history: "none"
|
|
71509
|
+
};
|
|
70894
71510
|
/**
|
|
70895
71511
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
70896
71512
|
* on `DeviceType.Presence`. Read-only — no setters: presence is
|
|
@@ -80386,6 +81002,25 @@ function buildDescriptor(capName, kind) {
|
|
|
80386
81002
|
* contributes one entry per bound cap present in this map.
|
|
80387
81003
|
*/
|
|
80388
81004
|
var EVENT_KIND_BY_CAP = Object.freeze(Object.fromEntries(Object.entries(CAP_TO_KIND).map(([capName, kind]) => [capName, buildDescriptor(capName, kind)])));
|
|
81005
|
+
/**
|
|
81006
|
+
* What a remote key is CALLED and what it LOOKS like, for every role (D963),
|
|
81007
|
+
* shared by the admin UI and the viewer. A role is data on the wire; each
|
|
81008
|
+
* client resolves its name from `label` (English and Italian side by side) and
|
|
81009
|
+
* its glyph from `icon`, a lucide id from the shared icon catalogue — the
|
|
81010
|
+
* server sends an id, a client maps it to its own icon set.
|
|
81011
|
+
*
|
|
81012
|
+
* `legend` is text printed on the key INSTEAD of a glyph (a digit has no
|
|
81013
|
+
* pictogram): a client that can draw text shows it, one that cannot falls back
|
|
81014
|
+
* to `icon`.
|
|
81015
|
+
*/
|
|
81016
|
+
function digit(n) {
|
|
81017
|
+
return {
|
|
81018
|
+
label: t(n, n),
|
|
81019
|
+
icon: "hash",
|
|
81020
|
+
legend: n
|
|
81021
|
+
};
|
|
81022
|
+
}
|
|
81023
|
+
digit("0"), digit("1"), digit("2"), digit("3"), digit("4"), digit("5"), digit("6"), digit("7"), digit("8"), digit("9");
|
|
80389
81024
|
DeviceFeature.MediaPlayerPower, DeviceFeature.MediaPlayerVolumeStep, DeviceFeature.MediaPlayerChannelStep, DeviceFeature.MediaPlayerMute, DeviceFeature.MediaPlayerStop, DeviceFeature.MediaPlayerNext, DeviceFeature.MediaPlayerPrevious;
|
|
80390
81025
|
var btn = (idSuffix, row, col, init) => ({
|
|
80391
81026
|
idSuffix,
|
|
@@ -80550,6 +81185,34 @@ function runningFromMediaPlayer(state, previous, fetchedAt, transitionAt) {
|
|
|
80550
81185
|
if (state === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
|
|
80551
81186
|
return nativeSlice(false, state, previous, transitionAtMs, fetchedAt, null);
|
|
80552
81187
|
}
|
|
81188
|
+
/**
|
|
81189
|
+
* Propose a running threshold from a device's own power history (planning#405).
|
|
81190
|
+
*
|
|
81191
|
+
* Pure and deterministic: the same series gives the same answer. The series is
|
|
81192
|
+
* a HELD-VALUE step series — a point's value stands until the next point — which
|
|
81193
|
+
* is how device-history stores a gauge, so "time at a level" is exact, not a
|
|
81194
|
+
* count of samples.
|
|
81195
|
+
*
|
|
81196
|
+
* 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
|
|
81197
|
+
* near F. A device that is not near one level most of the time has no floor.
|
|
81198
|
+
* 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
|
|
81199
|
+
* 3. gaps between episodes split in two by the largest log-scale jump (>= 3x):
|
|
81200
|
+
* the short ones are pauses INSIDE a run (a soak), the long ones separate runs.
|
|
81201
|
+
* 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
|
|
81202
|
+
* grid a person would type; stop dwell covers the longest pause; start dwell
|
|
81203
|
+
* covers the longest standby blip above T.
|
|
81204
|
+
* 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
|
|
81205
|
+
* run must hold exactly one true interval and nothing may flap outside.
|
|
81206
|
+
*/
|
|
81207
|
+
var SECOND_MS = 1e3;
|
|
81208
|
+
var MINUTE_MS$1 = 60 * SECOND_MS;
|
|
81209
|
+
24 * (60 * MINUTE_MS$1);
|
|
81210
|
+
10 * MINUTE_MS$1;
|
|
81211
|
+
30 * SECOND_MS;
|
|
81212
|
+
60 * SECOND_MS;
|
|
81213
|
+
20 * MINUTE_MS$1;
|
|
81214
|
+
10 * SECOND_MS;
|
|
81215
|
+
10 * SECOND_MS;
|
|
80553
81216
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
80554
81217
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
80555
81218
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
@@ -83655,6 +84318,13 @@ Object.freeze({
|
|
|
83655
84318
|
access: "create",
|
|
83656
84319
|
role: "admin"
|
|
83657
84320
|
},
|
|
84321
|
+
"coreBlocks.proposeRunningThreshold": {
|
|
84322
|
+
capName: "core-blocks",
|
|
84323
|
+
capScope: "system",
|
|
84324
|
+
addonId: null,
|
|
84325
|
+
access: "view",
|
|
84326
|
+
role: "admin"
|
|
84327
|
+
},
|
|
83658
84328
|
"coreBlocks.reportAutomationRun": {
|
|
83659
84329
|
capName: "core-blocks",
|
|
83660
84330
|
capScope: "system",
|
|
@@ -84166,6 +84836,13 @@ Object.freeze({
|
|
|
84166
84836
|
access: "view",
|
|
84167
84837
|
role: "admin"
|
|
84168
84838
|
},
|
|
84839
|
+
"deviceExport.listInstances": {
|
|
84840
|
+
capName: "device-export",
|
|
84841
|
+
capScope: "system",
|
|
84842
|
+
addonId: null,
|
|
84843
|
+
access: "view",
|
|
84844
|
+
role: "admin"
|
|
84845
|
+
},
|
|
84169
84846
|
"deviceExport.listSupportedDeviceKinds": {
|
|
84170
84847
|
capName: "device-export",
|
|
84171
84848
|
capScope: "system",
|
|
@@ -93124,6 +93801,11 @@ Object.freeze({
|
|
|
93124
93801
|
form: "single",
|
|
93125
93802
|
optional: false
|
|
93126
93803
|
}],
|
|
93804
|
+
"coreBlocks.proposeRunningThreshold": [{
|
|
93805
|
+
name: "deviceId",
|
|
93806
|
+
form: "single",
|
|
93807
|
+
optional: false
|
|
93808
|
+
}],
|
|
93127
93809
|
"cover.close": [{
|
|
93128
93810
|
name: "deviceId",
|
|
93129
93811
|
form: "single",
|
|
@@ -95787,99 +96469,6 @@ Object.freeze({
|
|
|
95787
96469
|
"network-access": "ingress",
|
|
95788
96470
|
"smtp-provider": "email"
|
|
95789
96471
|
});
|
|
95790
|
-
/**
|
|
95791
|
-
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
95792
|
-
* `z.infer`, they do not restate the shape.
|
|
95793
|
-
*/
|
|
95794
|
-
var OverrideSourceSchema = object({
|
|
95795
|
-
addonId: string().min(1),
|
|
95796
|
-
stableId: string().min(1),
|
|
95797
|
-
cap: string().min(1),
|
|
95798
|
-
fieldPath: string().min(1)
|
|
95799
|
-
});
|
|
95800
|
-
var CustomizeTransformDraftSchema = discriminatedUnion("kind", [
|
|
95801
|
-
object({ kind: literal("identity") }),
|
|
95802
|
-
object({ kind: literal("invert") }),
|
|
95803
|
-
object({
|
|
95804
|
-
kind: literal("threshold"),
|
|
95805
|
-
comparison: _enum(["gte", "lte"]),
|
|
95806
|
-
threshold: number(),
|
|
95807
|
-
startDwellMs: number().nonnegative(),
|
|
95808
|
-
stopDwellMs: number().nonnegative()
|
|
95809
|
-
}),
|
|
95810
|
-
object({
|
|
95811
|
-
kind: literal("linear"),
|
|
95812
|
-
scale: number(),
|
|
95813
|
-
offset: number(),
|
|
95814
|
-
clampMin: number().optional(),
|
|
95815
|
-
clampMax: number().optional()
|
|
95816
|
-
}),
|
|
95817
|
-
object({
|
|
95818
|
-
kind: literal("enum-map"),
|
|
95819
|
-
mapping: record(string(), string().nullable())
|
|
95820
|
-
}),
|
|
95821
|
-
object({ kind: literal("number") })
|
|
95822
|
-
]);
|
|
95823
|
-
var ScalarOverrideDraftSchema = object({
|
|
95824
|
-
kind: literal("scalar"),
|
|
95825
|
-
cap: string().min(1),
|
|
95826
|
-
targetId: string().min(1),
|
|
95827
|
-
source: OverrideSourceSchema,
|
|
95828
|
-
transform: CustomizeTransformDraftSchema
|
|
95829
|
-
});
|
|
95830
|
-
var KeyedArrayOverrideDraftSchema = object({
|
|
95831
|
-
kind: literal("keyedArray"),
|
|
95832
|
-
cap: string().min(1),
|
|
95833
|
-
targetId: string().min(1),
|
|
95834
|
-
key: string().min(1),
|
|
95835
|
-
label: string().min(1),
|
|
95836
|
-
fieldPath: string().min(1),
|
|
95837
|
-
source: OverrideSourceSchema,
|
|
95838
|
-
transform: CustomizeTransformDraftSchema
|
|
95839
|
-
});
|
|
95840
|
-
var PulseOverrideDraftSchema = object({
|
|
95841
|
-
kind: literal("pulse"),
|
|
95842
|
-
cap: string().min(1),
|
|
95843
|
-
targetId: string().min(1),
|
|
95844
|
-
enabled: boolean(),
|
|
95845
|
-
debounceMs: number().nonnegative(),
|
|
95846
|
-
edges: array(_enum([
|
|
95847
|
-
"rising",
|
|
95848
|
-
"button",
|
|
95849
|
-
"native-event"
|
|
95850
|
-
])).min(1).optional(),
|
|
95851
|
-
sources: array(OverrideSourceSchema).min(1)
|
|
95852
|
-
});
|
|
95853
|
-
var SpanSourceDraftSchema = OverrideSourceSchema.extend({ mode: _enum([
|
|
95854
|
-
"in-addition",
|
|
95855
|
-
"confirm",
|
|
95856
|
-
"replace"
|
|
95857
|
-
]).optional() });
|
|
95858
|
-
discriminatedUnion("kind", [
|
|
95859
|
-
ScalarOverrideDraftSchema,
|
|
95860
|
-
KeyedArrayOverrideDraftSchema,
|
|
95861
|
-
PulseOverrideDraftSchema,
|
|
95862
|
-
object({
|
|
95863
|
-
kind: literal("span"),
|
|
95864
|
-
cap: string().min(1),
|
|
95865
|
-
targetId: string().min(1),
|
|
95866
|
-
timeoutMs: number().nonnegative(),
|
|
95867
|
-
cooldownMs: number().nonnegative().optional(),
|
|
95868
|
-
sources: array(SpanSourceDraftSchema)
|
|
95869
|
-
})
|
|
95870
|
-
]);
|
|
95871
|
-
object({
|
|
95872
|
-
targetId: string().min(1),
|
|
95873
|
-
configured: boolean(),
|
|
95874
|
-
source: _enum(["native", "assigned"]),
|
|
95875
|
-
state: _enum([
|
|
95876
|
-
"active",
|
|
95877
|
-
"stale",
|
|
95878
|
-
"released",
|
|
95879
|
-
"unavailable"
|
|
95880
|
-
]),
|
|
95881
|
-
reason: string().nullable()
|
|
95882
|
-
});
|
|
95883
96472
|
var G711_SCALE_CORRECTION_DB = {
|
|
95884
96473
|
PCMU: 20 * Math.log10(4),
|
|
95885
96474
|
PCMA: 20 * Math.log10(8)
|
|
@@ -97726,4 +98315,4 @@ async function listInstancesOrNothing(ports, onError) {
|
|
|
97726
98315
|
}
|
|
97727
98316
|
}
|
|
97728
98317
|
//#endregion
|
|
97729
|
-
export {
|
|
98318
|
+
export { enumSensorCapability as $, baseUnitOf as $t, automationControlCapability as A, runExportedAction as At, calendarSourceCapability as B, tamperCapability as Bt, RecordIntegrationInstances as C, EventCategory as Cn, prepareNotification as Ct, airQualitySensorCapability as D, publicEndpointReaderFrom as Dt, addonRoutesCapability as E, pruneDeletedEntities as Et, brightnessCapability as F, scriptRunnerCapability as Ft, consumableFormOf as G, vacuumControlCapability as Gt, climateControlCapability as H, tryConvertDelta as Ht, brokerCapability as I, sendToExportedTarget as It, controlCapability as J, waterHeaterCapability as Jt, consumableKindOf as K, valveCapability as Kt, buildAddonRouteProvider as L, smokeCapability as Lt, bestLocationMatch as M, runningFromMediaPlayer as Mt, binaryCapability as N, runningFromVacuumState as Nt, alarmPanelCapability as O, quantityFromUnit as Ot, boardKeySourceCapability as P, runningStateCapability as Pt, deviceExportCapability as Q, RecordSecretUnavailableError as Qt, buildDeviceAdminUrl as R, statusInstanceOf as Rt, RUNNING_STATE_COLD as S, errMsg as Sn, preconditionOf as St, accessoriesCapability as T, pressureSensorCapability as Tt, colorCapability as U, tryConvertUnit as Ut, carbonMonoxideCapability as V, temperatureSensorCapability as Vt, connectivityCapability as W, updateCapability as Wt, deviceAdminLinkCapability as X, BaseAddon as Xt, coverCapability as Y, weatherCapability as Yt, deviceAdoptionCapability as Z, REDACTED_SECRET as Zt, ExportInstanceUnknownError as _, unknown as _n, notifierCapability as _t, HA_PROVIDER_ADDON_ID$1 as a, isReadingQuantity as an, gasCapability as at, MediaPlayerRepeatSchema as b, DeviceRole as bn, parseAdminBase as bt, BaseDevice as c, array as cn, imageCapability as ct, COCO_TO_MACRO as d, literal as dn, lawnMowerControlCapability as dt, createEvent as en, eventEmitterCapability as et, CameraSwitchIdSchema as f, number as fn, lockControlCapability as ft, EnumSensorDateTimeFormatSchema as g, union as gn, notificationOutputCapability as gt, ConsumableStatusSchema as h, string as hn, normalizeUnit as ht, HA_BROKER_KIND as i, entryBody as in, floodCapability as it, batteryCapability as j, runningFromLawnMower as jt, ambientLightSensorCapability as k, resolveAttachmentUrls as kt, BaseDeviceProvider as l, boolean as ln, ingestReading as lt, ConsumableItemSchema as m, record as mn, motionCapability as mt, listInstancesOrNothing as n, defineEntryKind as nn, flattenNestedRecords as nt, listHomeAssistantBrokers as o, nodePin as on, humidifierCapability as ot, ConsumableFormSchema as p, object as pn, mediaPlayerCapability as pt, contactCapability as q, vibrationCapability as qt, settingsByBroker as r, defineRecordKinds as rn, flattenPortsOver as rt, AlarmArmModeSchema as s, _enum as sn, humiditySensorCapability as st, haInstanceSettingsPortsOver as t, defineAddonMigrations as tn, fanControlCapability as tt, CAMERA_SWITCH_ORDER as u, discriminatedUnion as un, integrationInstancesCapability as ut, FanDirectionSchema as v, url as vn, numericSensorCapability as vt, TargetSchema as w, presenceCapability as wt, PLUG_APPLIANCE_TYPES as x, DeviceType as xn, powerMeterCapability as xt, HvacModeSchema as y, DeviceFeature as yn, oauthIntegrationCapability as yt, buttonCapability as z, switchCapability as zt };
|