@camstack/addon-provider-homeassistant 1.2.648 → 1.2.650
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 +13 -0
- package/dist/addon.js +2 -1
- package/dist/addon.mjs +2 -1
- package/dist/{ha-broker-source-iLA_DsW8.mjs → ha-broker-source-B2v2dnPe.mjs} +294 -105
- package/dist/{ha-broker-source-Ba20mhmb.js → ha-broker-source-DUj9pUWr.js} +294 -105
- package/dist/ha-export/ha-export.addon.js +123 -41
- package/dist/ha-export/ha-export.addon.mjs +123 -41
- package/package.json +2 -2
|
@@ -784,7 +784,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
784
784
|
return EventCategory;
|
|
785
785
|
}({});
|
|
786
786
|
//#endregion
|
|
787
|
-
//#region ../types/dist/device-type-
|
|
787
|
+
//#region ../types/dist/device-type-CfHw_quR.mjs
|
|
788
788
|
/**
|
|
789
789
|
import { errMsg } from '@camstack/types'
|
|
790
790
|
* Extract a human-readable message from an unknown error value.
|
|
@@ -973,6 +973,9 @@ var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
|
973
973
|
DeviceFeature["CoverPositionable"] = "cover-positionable";
|
|
974
974
|
/** Cover exposes slat-tilt control. Gates the tilt slider UI. */
|
|
975
975
|
DeviceFeature["CoverTilt"] = "cover-tilt";
|
|
976
|
+
/** Cover has a real stop: `stop` halts the travel in place. Gates the stop
|
|
977
|
+
* control in exporters; a provider whose `stop` is a no-op never declares it. */
|
|
978
|
+
DeviceFeature["CoverStoppable"] = "cover-stoppable";
|
|
976
979
|
/** Valve exposes intermediate position control (0..100). Gates the
|
|
977
980
|
* position slider / drag surface UI. */
|
|
978
981
|
DeviceFeature["ValvePositionable"] = "valve-positionable";
|
|
@@ -5971,7 +5974,7 @@ var ZodIssueCode = {
|
|
|
5971
5974
|
var ZodFirstPartyTypeKind;
|
|
5972
5975
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5973
5976
|
//#endregion
|
|
5974
|
-
//#region ../types/dist/sleep-
|
|
5977
|
+
//#region ../types/dist/sleep-QsoHs66J.mjs
|
|
5975
5978
|
/**
|
|
5976
5979
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5977
5980
|
* window to float samples (D455).
|
|
@@ -6088,7 +6091,7 @@ function isKeychainStoredField(field) {
|
|
|
6088
6091
|
var SECRET_CLEAR = { $secretClear: true };
|
|
6089
6092
|
/** The `'***'` token D634 redaction writes for non-admins. */
|
|
6090
6093
|
var LEGACY_DEVICE_REDACTION = "***";
|
|
6091
|
-
function isRecord$
|
|
6094
|
+
function isRecord$7(value) {
|
|
6092
6095
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6093
6096
|
}
|
|
6094
6097
|
function makeSecretMarker(ref) {
|
|
@@ -6099,12 +6102,12 @@ function makeSecretMarker(ref) {
|
|
|
6099
6102
|
}
|
|
6100
6103
|
/** A stored marker: an object whose `$secret` is a non-empty string. */
|
|
6101
6104
|
function isSecretMarker(value) {
|
|
6102
|
-
if (!isRecord$
|
|
6105
|
+
if (!isRecord$7(value)) return false;
|
|
6103
6106
|
const ref = value["$secret"];
|
|
6104
6107
|
return typeof ref === "string" && ref.length > 0;
|
|
6105
6108
|
}
|
|
6106
6109
|
function isSecretClear(value) {
|
|
6107
|
-
return isRecord$
|
|
6110
|
+
return isRecord$7(value) && value["$secretClear"] === true;
|
|
6108
6111
|
}
|
|
6109
6112
|
/**
|
|
6110
6113
|
* The UI view of a stored secret field value: a marker becomes "set", inline
|
|
@@ -6857,7 +6860,7 @@ var KeychainWriteRefusedError = class extends Error {
|
|
|
6857
6860
|
}
|
|
6858
6861
|
};
|
|
6859
6862
|
var KEEP = { kind: "keep" };
|
|
6860
|
-
function isRecord$
|
|
6863
|
+
function isRecord$6(value) {
|
|
6861
6864
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6862
6865
|
}
|
|
6863
6866
|
function defaultMintId() {
|
|
@@ -6870,7 +6873,7 @@ function collectSecretMarkerRefs(value, out = []) {
|
|
|
6870
6873
|
return out;
|
|
6871
6874
|
}
|
|
6872
6875
|
if (Array.isArray(value)) for (const item of value) collectSecretMarkerRefs(item, out);
|
|
6873
|
-
else if (isRecord$
|
|
6876
|
+
else if (isRecord$6(value)) for (const child of Object.values(value)) collectSecretMarkerRefs(child, out);
|
|
6874
6877
|
return out;
|
|
6875
6878
|
}
|
|
6876
6879
|
async function storedValueEquals(secrets, marker, candidate) {
|
|
@@ -6925,7 +6928,7 @@ function rowId(row, idKey) {
|
|
|
6925
6928
|
return null;
|
|
6926
6929
|
}
|
|
6927
6930
|
async function writeArray(ctx, node, incoming, stored, fieldPath) {
|
|
6928
|
-
const storedRows = Array.isArray(stored) ? stored.filter(isRecord$
|
|
6931
|
+
const storedRows = Array.isArray(stored) ? stored.filter(isRecord$6) : [];
|
|
6929
6932
|
if (!Array.isArray(incoming)) {
|
|
6930
6933
|
ctx.deletes.push(...collectSecretMarkerRefs(storedRows));
|
|
6931
6934
|
return {
|
|
@@ -6941,7 +6944,7 @@ async function writeArray(ctx, node, incoming, stored, fieldPath) {
|
|
|
6941
6944
|
const kept = /* @__PURE__ */ new Set();
|
|
6942
6945
|
const rows = [];
|
|
6943
6946
|
for (const row of incoming) {
|
|
6944
|
-
if (!isRecord$
|
|
6947
|
+
if (!isRecord$6(row)) {
|
|
6945
6948
|
rows.push(row);
|
|
6946
6949
|
continue;
|
|
6947
6950
|
}
|
|
@@ -6966,7 +6969,7 @@ async function writeNode(ctx, node, incoming, stored, fieldPath) {
|
|
|
6966
6969
|
case "leaf": return writeLeaf(ctx, incoming, stored, fieldPath);
|
|
6967
6970
|
case "array": return writeArray(ctx, node, incoming, stored, fieldPath);
|
|
6968
6971
|
case "object": {
|
|
6969
|
-
if (!isRecord$
|
|
6972
|
+
if (!isRecord$6(incoming)) {
|
|
6970
6973
|
if (incoming === void 0) return KEEP;
|
|
6971
6974
|
ctx.deletes.push(...collectSecretMarkerRefs(stored));
|
|
6972
6975
|
return {
|
|
@@ -6974,7 +6977,7 @@ async function writeNode(ctx, node, incoming, stored, fieldPath) {
|
|
|
6974
6977
|
value: incoming
|
|
6975
6978
|
};
|
|
6976
6979
|
}
|
|
6977
|
-
const storedObj = isRecord$
|
|
6980
|
+
const storedObj = isRecord$6(stored) ? stored : {};
|
|
6978
6981
|
return {
|
|
6979
6982
|
kind: "value",
|
|
6980
6983
|
value: await writeMembers(ctx, node.children, incoming, storedObj, (m) => `${fieldPath}.${m}`)
|
|
@@ -7097,7 +7100,7 @@ async function resolveSecretMarkers(value, secrets, options = {}) {
|
|
|
7097
7100
|
value: items
|
|
7098
7101
|
};
|
|
7099
7102
|
}
|
|
7100
|
-
if (isRecord$
|
|
7103
|
+
if (isRecord$6(v)) {
|
|
7101
7104
|
const out = {};
|
|
7102
7105
|
for (const [k, child] of Object.entries(v)) {
|
|
7103
7106
|
const s = substitute(child);
|
|
@@ -7129,7 +7132,7 @@ var SecretOverwriteRefusedError = class extends Error {
|
|
|
7129
7132
|
this.name = "SecretOverwriteRefusedError";
|
|
7130
7133
|
}
|
|
7131
7134
|
};
|
|
7132
|
-
function isRecord$
|
|
7135
|
+
function isRecord$5(value) {
|
|
7133
7136
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7134
7137
|
}
|
|
7135
7138
|
function resolvedValue(pass, marker) {
|
|
@@ -7158,7 +7161,7 @@ function inArray(pass, incoming, stored) {
|
|
|
7158
7161
|
return incoming.map((item, index) => {
|
|
7159
7162
|
const twin = stored[index];
|
|
7160
7163
|
if (isSecretMarker(twin)) return typeof item === "string" && item === resolvedValue(pass, twin) ? twin : item;
|
|
7161
|
-
if (isRecord$
|
|
7164
|
+
if (isRecord$5(item) && isRecord$5(twin)) return inArrayRow(pass, item, twin);
|
|
7162
7165
|
if (Array.isArray(item) && Array.isArray(twin)) return inArray(pass, item, twin);
|
|
7163
7166
|
return item;
|
|
7164
7167
|
});
|
|
@@ -7169,7 +7172,7 @@ function inArrayRow(pass, incoming, stored) {
|
|
|
7169
7172
|
const twin = stored[key];
|
|
7170
7173
|
if (isSecretMarker(twin)) {
|
|
7171
7174
|
if (typeof value === "string" && value === resolvedValue(pass, twin)) out[key] = twin;
|
|
7172
|
-
} else if (isRecord$
|
|
7175
|
+
} else if (isRecord$5(value) && isRecord$5(twin)) out[key] = inArrayRow(pass, value, twin);
|
|
7173
7176
|
else if (Array.isArray(value) && Array.isArray(twin)) out[key] = inArray(pass, value, twin);
|
|
7174
7177
|
}
|
|
7175
7178
|
return out;
|
|
@@ -7177,7 +7180,7 @@ function inArrayRow(pass, incoming, stored) {
|
|
|
7177
7180
|
async function walk(pass, incoming, stored) {
|
|
7178
7181
|
if (isSecretMarker(stored)) return atMarker(pass, incoming, stored);
|
|
7179
7182
|
if (Array.isArray(incoming) && Array.isArray(stored)) return inArray(pass, incoming, stored);
|
|
7180
|
-
if (!isRecord$
|
|
7183
|
+
if (!isRecord$5(incoming) || !isRecord$5(stored)) return incoming;
|
|
7181
7184
|
const out = { ...incoming };
|
|
7182
7185
|
for (const [key, value] of Object.entries(incoming)) out[key] = await walk(pass, value, stored[key]);
|
|
7183
7186
|
return out;
|
|
@@ -7208,7 +7211,7 @@ async function restoreUnchangedSecrets(input) {
|
|
|
7208
7211
|
function isJsonEqual(a, b) {
|
|
7209
7212
|
if (Object.is(a, b)) return true;
|
|
7210
7213
|
if (Array.isArray(a)) return Array.isArray(b) && a.length === b.length && a.every((v, i) => isJsonEqual(v, b[i]));
|
|
7211
|
-
if (isRecord$
|
|
7214
|
+
if (isRecord$5(a) && isRecord$5(b)) {
|
|
7212
7215
|
const keys = Object.keys(a);
|
|
7213
7216
|
if (keys.length !== Object.keys(b).length) return false;
|
|
7214
7217
|
return keys.every((k) => Object.prototype.hasOwnProperty.call(b, k) && isJsonEqual(a[k], b[k]));
|
|
@@ -7232,7 +7235,7 @@ function markerKeysOf(blob, owner) {
|
|
|
7232
7235
|
}
|
|
7233
7236
|
function nodeFromStored(value, owner) {
|
|
7234
7237
|
if (isSecretMarker(value)) return isSecretRefOwnedBy(value.$secret, owner) ? { kind: "leaf" } : null;
|
|
7235
|
-
if (!isRecord$
|
|
7238
|
+
if (!isRecord$5(value)) return null;
|
|
7236
7239
|
const children = /* @__PURE__ */ new Map();
|
|
7237
7240
|
for (const [key, child] of Object.entries(value)) {
|
|
7238
7241
|
const node = nodeFromStored(child, owner);
|
|
@@ -7851,6 +7854,44 @@ var BaseAddon = class {
|
|
|
7851
7854
|
return null;
|
|
7852
7855
|
}
|
|
7853
7856
|
/**
|
|
7857
|
+
* D986 scoped settings: the form shape of the CLUSTER-wide settings one capability this addon
|
|
7858
|
+
* provides owns, or `null` when it has none. `cap` is a capability name the addon's manifest
|
|
7859
|
+
* declares. Stored as `addon-settings` rows `<addonId>.<field>`. The keys of this schema, of
|
|
7860
|
+
* {@link nodeSettingsSchema} and of {@link deviceDefaultsSchema} are disjoint, and a key never
|
|
7861
|
+
* contains `@` (guard `check-scoped-settings-declared`). SHAPE only: values are read by scope.
|
|
7862
|
+
*/
|
|
7863
|
+
async clusterSettingsSchema(_cap) {
|
|
7864
|
+
return null;
|
|
7865
|
+
}
|
|
7866
|
+
/**
|
|
7867
|
+
* D986: the form shape of the settings one capability owns PER NODE, or `null`. Stored as
|
|
7868
|
+
* `addon-settings` rows `<addonId>.<field>@<nodeId>` carrying `nodeId` in the row data, so a
|
|
7869
|
+
* forgotten node's rows go in one central delete.
|
|
7870
|
+
*/
|
|
7871
|
+
async nodeSettingsSchema(_cap) {
|
|
7872
|
+
return null;
|
|
7873
|
+
}
|
|
7874
|
+
/**
|
|
7875
|
+
* D986: the form shape of the FLEET DEFAULTS of the per-device settings one capability owns,
|
|
7876
|
+
* or `null`. Stored as `addon-settings` rows `<addonId>.<field>`; a device resolves its value
|
|
7877
|
+
* as device row, then this default, then the schema default (`resolveDeviceSettings`).
|
|
7878
|
+
*/
|
|
7879
|
+
async deviceDefaultsSchema(_cap) {
|
|
7880
|
+
return null;
|
|
7881
|
+
}
|
|
7882
|
+
/**
|
|
7883
|
+
* The host's read of the scoped declarations: the schema one capability declares for `scope`,
|
|
7884
|
+
* or `null`. Beside {@link getIntegrationFormSchema}, the same shape: the hook is protected, the
|
|
7885
|
+
* host asks this method.
|
|
7886
|
+
*/
|
|
7887
|
+
async getScopedSettingsSchema(scope, cap) {
|
|
7888
|
+
switch (scope) {
|
|
7889
|
+
case "cluster": return this.clusterSettingsSchema(cap);
|
|
7890
|
+
case "node": return this.nodeSettingsSchema(cap);
|
|
7891
|
+
case "device-defaults": return this.deviceDefaultsSchema(cap);
|
|
7892
|
+
}
|
|
7893
|
+
}
|
|
7894
|
+
/**
|
|
7854
7895
|
* What the create wizard and the integration edit page render for one instance: the addon's
|
|
7855
7896
|
* per-instance schema when it declares one, else its global schema (what they always showed).
|
|
7856
7897
|
*/
|
|
@@ -8644,47 +8685,6 @@ function normalizeAddonInitResult(result) {
|
|
|
8644
8685
|
if (Array.isArray(result)) return { providers: result };
|
|
8645
8686
|
return result;
|
|
8646
8687
|
}
|
|
8647
|
-
/**
|
|
8648
|
-
* The share-view scope kinds a share-link token can carry. The hub mints
|
|
8649
|
-
* and validates them (`ShareViewGrantSchema` builds its
|
|
8650
|
-
* enum from this list); a data plane names the kinds it ACCEPTS in `share`.
|
|
8651
|
-
*/
|
|
8652
|
-
var SHARE_VIEW_KINDS = ["grid-view", "events-view"];
|
|
8653
|
-
/** The wire shape of {@link PeerBytesTicket} — see the type for what it is. */
|
|
8654
|
-
var PeerBytesTicketSchema = object({
|
|
8655
|
-
/** `http://127.0.0.1:<port>/<token>`. One `GET` takes it. */
|
|
8656
|
-
url: string().min(1),
|
|
8657
|
-
/**
|
|
8658
|
-
* The HOST node this URL means something on — the hub or a named agent,
|
|
8659
|
-
* never a runner. {@link AddonPeerBytes.open} compares it to its own and
|
|
8660
|
-
* refuses `cross-node` by name when they differ, without dialling.
|
|
8661
|
-
*/
|
|
8662
|
-
hostNodeId: string().min(1),
|
|
8663
|
-
expiresAtMs: number().int().nonnegative(),
|
|
8664
|
-
/**
|
|
8665
|
-
* What the producer DECLARED the body to be, when it knows — `null` when it
|
|
8666
|
-
* does not. Never `0` for unknown (D393): a consumer sizing a bound off this
|
|
8667
|
-
* must be able to tell "the producer did not say" from "the body is empty".
|
|
8668
|
-
*/
|
|
8669
|
-
declaredBytes: number().int().nonnegative().nullable()
|
|
8670
|
-
});
|
|
8671
|
-
/** Limits and names of `ctx.records` (D881). One authority; the engine and the facade read it. */
|
|
8672
|
-
/** The files a kind may live in. `history` is device-history's (D850), never records. */
|
|
8673
|
-
var RECORD_DATABASES = ["settings", "events"];
|
|
8674
|
-
/** The classes of a kind: the `@durable` vocabulary, one authority (replaces the annotation). */
|
|
8675
|
-
var RECORD_CLASSES = [
|
|
8676
|
-
"config",
|
|
8677
|
-
"ledger",
|
|
8678
|
-
"audit",
|
|
8679
|
-
"mirror",
|
|
8680
|
-
"ephemeral"
|
|
8681
|
-
];
|
|
8682
|
-
var RECORD_DEFAULT_MAX_DATA_BYTES = 64 * 1024;
|
|
8683
|
-
var RECORD_MAX_DATA_BYTES = 1024 * 1024;
|
|
8684
|
-
var RECORD_BATCH_MAX = 1e3;
|
|
8685
|
-
var RECORD_QUERY_MAX = 1e3;
|
|
8686
|
-
/** A kind in the `settings` file may not bound itself above this (D447: high volume is `events`). */
|
|
8687
|
-
var RECORD_SETTINGS_MAX_ROWS = 5e4;
|
|
8688
8688
|
var PREFIX = "records/";
|
|
8689
8689
|
/** The base of every records failure. `detail` is the human part of the message. */
|
|
8690
8690
|
var RecordsError = class extends Error {
|
|
@@ -8717,6 +8717,83 @@ var DeclarationRefusedError = class extends RecordsError {
|
|
|
8717
8717
|
this.name = "DeclarationRefusedError";
|
|
8718
8718
|
}
|
|
8719
8719
|
};
|
|
8720
|
+
/** Limits and names of `ctx.records` (D881). One authority; the engine and the facade read it. */
|
|
8721
|
+
/** The files a kind may live in. `history` is device-history's (D850), never records. */
|
|
8722
|
+
var RECORD_DATABASES = ["settings", "events"];
|
|
8723
|
+
/** The classes of a kind: the `@durable` vocabulary, one authority (replaces the annotation). */
|
|
8724
|
+
var RECORD_CLASSES = [
|
|
8725
|
+
"config",
|
|
8726
|
+
"ledger",
|
|
8727
|
+
"audit",
|
|
8728
|
+
"mirror",
|
|
8729
|
+
"ephemeral"
|
|
8730
|
+
];
|
|
8731
|
+
var RECORD_DEFAULT_MAX_DATA_BYTES = 64 * 1024;
|
|
8732
|
+
var RECORD_MAX_DATA_BYTES = 1024 * 1024;
|
|
8733
|
+
var RECORD_BATCH_MAX = 1e3;
|
|
8734
|
+
var RECORD_QUERY_MAX = 1e3;
|
|
8735
|
+
/** A kind in the `settings` file may not bound itself above this (D447: high volume is `events`). */
|
|
8736
|
+
var RECORD_SETTINGS_MAX_ROWS = 5e4;
|
|
8737
|
+
/**
|
|
8738
|
+
* Secret fields of a record, addressed the way a Zod schema declares them
|
|
8739
|
+
* (`collectZodSecretPaths`): dotted keys, `[]` for "each element of this array"
|
|
8740
|
+
* (`auth.accessToken`, `headers[].value`).
|
|
8741
|
+
*
|
|
8742
|
+
* Array elements are matched by a DECLARED id key (`secretArrayKeys`:
|
|
8743
|
+
* `{ headers: 'name' }`), never by index, so reordering a list keeps every
|
|
8744
|
+
* keychain ref (the same rule as `arrayItemFieldPath`). The concrete path of a
|
|
8745
|
+
* leaf names its element: `headers[X-Api].value`.
|
|
8746
|
+
*
|
|
8747
|
+
* Pure and browser-safe. Nothing here mutates: every transform returns a new value.
|
|
8748
|
+
*/
|
|
8749
|
+
/** The array prefixes (declared form, e.g. `headers` or `a.headers`) of a path. */
|
|
8750
|
+
function parseSecretPath(path) {
|
|
8751
|
+
if (path.length === 0) throw new InvalidRecordError("an empty secret path");
|
|
8752
|
+
return path.split(".").map((raw) => {
|
|
8753
|
+
const each = raw.endsWith("[]");
|
|
8754
|
+
const key = each ? raw.slice(0, -2) : raw;
|
|
8755
|
+
if (key.length === 0) throw new InvalidRecordError(`secret path "${path}" has an empty segment`);
|
|
8756
|
+
return {
|
|
8757
|
+
key,
|
|
8758
|
+
each
|
|
8759
|
+
};
|
|
8760
|
+
});
|
|
8761
|
+
}
|
|
8762
|
+
/** The declared array prefixes of `path` that need an id key (`headers`, `a.rows`). */
|
|
8763
|
+
function secretArrayPrefixes(path) {
|
|
8764
|
+
const segments = parseSecretPath(path);
|
|
8765
|
+
const prefixes = [];
|
|
8766
|
+
const walked = [];
|
|
8767
|
+
for (const segment of segments) {
|
|
8768
|
+
walked.push(segment.key);
|
|
8769
|
+
if (segment.each) prefixes.push(walked.join("."));
|
|
8770
|
+
}
|
|
8771
|
+
return prefixes;
|
|
8772
|
+
}
|
|
8773
|
+
/**
|
|
8774
|
+
* The share-view scope kinds a share-link token can carry. The hub mints
|
|
8775
|
+
* and validates them (`ShareViewGrantSchema` builds its
|
|
8776
|
+
* enum from this list); a data plane names the kinds it ACCEPTS in `share`.
|
|
8777
|
+
*/
|
|
8778
|
+
var SHARE_VIEW_KINDS = ["grid-view", "events-view"];
|
|
8779
|
+
/** The wire shape of {@link PeerBytesTicket} — see the type for what it is. */
|
|
8780
|
+
var PeerBytesTicketSchema = object({
|
|
8781
|
+
/** `http://127.0.0.1:<port>/<token>`. One `GET` takes it. */
|
|
8782
|
+
url: string().min(1),
|
|
8783
|
+
/**
|
|
8784
|
+
* The HOST node this URL means something on — the hub or a named agent,
|
|
8785
|
+
* never a runner. {@link AddonPeerBytes.open} compares it to its own and
|
|
8786
|
+
* refuses `cross-node` by name when they differ, without dialling.
|
|
8787
|
+
*/
|
|
8788
|
+
hostNodeId: string().min(1),
|
|
8789
|
+
expiresAtMs: number().int().nonnegative(),
|
|
8790
|
+
/**
|
|
8791
|
+
* What the producer DECLARED the body to be, when it knows — `null` when it
|
|
8792
|
+
* does not. Never `0` for unknown (D393): a consumer sizing a bound off this
|
|
8793
|
+
* must be able to tell "the producer did not say" from "the body is empty".
|
|
8794
|
+
*/
|
|
8795
|
+
declaredBytes: number().int().nonnegative().nullable()
|
|
8796
|
+
});
|
|
8720
8797
|
function defOf(schema) {
|
|
8721
8798
|
const zodBag = Reflect.get(schema, "_zod");
|
|
8722
8799
|
if (typeof zodBag !== "object" || zodBag === null) return {};
|
|
@@ -8785,42 +8862,6 @@ function collectZodSecretPaths(schema, prefix = "") {
|
|
|
8785
8862
|
return [...new Set(paths)];
|
|
8786
8863
|
}
|
|
8787
8864
|
/**
|
|
8788
|
-
* Secret fields of a record, addressed the way a Zod schema declares them
|
|
8789
|
-
* (`collectZodSecretPaths`): dotted keys, `[]` for "each element of this array"
|
|
8790
|
-
* (`auth.accessToken`, `headers[].value`).
|
|
8791
|
-
*
|
|
8792
|
-
* Array elements are matched by a DECLARED id key (`secretArrayKeys`:
|
|
8793
|
-
* `{ headers: 'name' }`), never by index, so reordering a list keeps every
|
|
8794
|
-
* keychain ref (the same rule as `arrayItemFieldPath`). The concrete path of a
|
|
8795
|
-
* leaf names its element: `headers[X-Api].value`.
|
|
8796
|
-
*
|
|
8797
|
-
* Pure and browser-safe. Nothing here mutates: every transform returns a new value.
|
|
8798
|
-
*/
|
|
8799
|
-
/** The array prefixes (declared form, e.g. `headers` or `a.headers`) of a path. */
|
|
8800
|
-
function parseSecretPath(path) {
|
|
8801
|
-
if (path.length === 0) throw new InvalidRecordError("an empty secret path");
|
|
8802
|
-
return path.split(".").map((raw) => {
|
|
8803
|
-
const each = raw.endsWith("[]");
|
|
8804
|
-
const key = each ? raw.slice(0, -2) : raw;
|
|
8805
|
-
if (key.length === 0) throw new InvalidRecordError(`secret path "${path}" has an empty segment`);
|
|
8806
|
-
return {
|
|
8807
|
-
key,
|
|
8808
|
-
each
|
|
8809
|
-
};
|
|
8810
|
-
});
|
|
8811
|
-
}
|
|
8812
|
-
/** The declared array prefixes of `path` that need an id key (`headers`, `a.rows`). */
|
|
8813
|
-
function secretArrayPrefixes(path) {
|
|
8814
|
-
const segments = parseSecretPath(path);
|
|
8815
|
-
const prefixes = [];
|
|
8816
|
-
const walked = [];
|
|
8817
|
-
for (const segment of segments) {
|
|
8818
|
-
walked.push(segment.key);
|
|
8819
|
-
if (segment.each) prefixes.push(walked.join("."));
|
|
8820
|
-
}
|
|
8821
|
-
return prefixes;
|
|
8822
|
-
}
|
|
8823
|
-
/**
|
|
8824
8865
|
* Record kinds (D881): the declaration an addon makes of one kind of fact, the
|
|
8825
8866
|
* Zod row schema that describes it, and the helper that turns the two into the
|
|
8826
8867
|
* JSON the engine stores.
|
|
@@ -9785,6 +9826,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9785
9826
|
"humidity-sensor",
|
|
9786
9827
|
"image",
|
|
9787
9828
|
"image-settings",
|
|
9829
|
+
"integration-instances",
|
|
9788
9830
|
"integrations",
|
|
9789
9831
|
"intercom",
|
|
9790
9832
|
"ir-transmitter",
|
|
@@ -11718,7 +11760,7 @@ object({
|
|
|
11718
11760
|
params: record(string(), union([string(), number()])).optional()
|
|
11719
11761
|
});
|
|
11720
11762
|
//#endregion
|
|
11721
|
-
//#region ../types/dist/composition-
|
|
11763
|
+
//#region ../types/dist/composition-Dh3RfMx5.mjs
|
|
11722
11764
|
/**
|
|
11723
11765
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11724
11766
|
*
|
|
@@ -21355,6 +21397,7 @@ var SYSTEM_CAP_VOCABULARY = {
|
|
|
21355
21397
|
"load-contribution": system(INTERNAL),
|
|
21356
21398
|
"local-network": system(NETWORK),
|
|
21357
21399
|
"log-channels": system(INTERNAL),
|
|
21400
|
+
"integration-instances": system(INTERNAL),
|
|
21358
21401
|
"log-destination": system(INTERNAL),
|
|
21359
21402
|
"login-method": system(IDENTITY),
|
|
21360
21403
|
"mesh-network": system(NETWORK),
|
|
@@ -43655,7 +43698,7 @@ var TargetKindCapsSchema = object({
|
|
|
43655
43698
|
* the union is large and not meant for runtime validation here; the exported
|
|
43656
43699
|
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
43657
43700
|
*/
|
|
43658
|
-
var ConfigSchemaPassthrough$
|
|
43701
|
+
var ConfigSchemaPassthrough$4 = unknown();
|
|
43659
43702
|
var TargetKindSchema = object({
|
|
43660
43703
|
kind: string(),
|
|
43661
43704
|
label: string(),
|
|
@@ -43692,7 +43735,7 @@ var TargetKindSchema = object({
|
|
|
43692
43735
|
* its raster path, which is the safe default for an unknown image.
|
|
43693
43736
|
*/
|
|
43694
43737
|
iconMediaType: string().optional(),
|
|
43695
|
-
configSchema: ConfigSchemaPassthrough$
|
|
43738
|
+
configSchema: ConfigSchemaPassthrough$4,
|
|
43696
43739
|
/**
|
|
43697
43740
|
* The config keys that decide WHERE this kind's secrets are sent (server,
|
|
43698
43741
|
* base URL, instance, chat, recipient). A save that changes any of them
|
|
@@ -55815,6 +55858,78 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
|
|
|
55815
55858
|
auth: "admin"
|
|
55816
55859
|
});
|
|
55817
55860
|
/**
|
|
55861
|
+
* `integration-instances` - the connection of an addon that holds ONE or SEVERAL
|
|
55862
|
+
* (an account, a relay, a destination) as typed records (D985, D986). The addon's
|
|
55863
|
+
* own function page reads and writes them (Logging for Loki); the Integrations
|
|
55864
|
+
* page lists only the integrations that bring devices (D996).
|
|
55865
|
+
*
|
|
55866
|
+
* A collection of providers: each addon that holds connections registers one and a
|
|
55867
|
+
* caller reaches a provider with the pinned `addonId`.
|
|
55868
|
+
*
|
|
55869
|
+
* Identity: the instance id is immutable and opaque to the caller. A record the
|
|
55870
|
+
* Loki migration made keeps the `integrations` registry id it was created under
|
|
55871
|
+
* (`int_NNNN`); a single instance made by its function page takes the addon id.
|
|
55872
|
+
* `name` is the editable label.
|
|
55873
|
+
*
|
|
55874
|
+
* Secrets: every field the instance kind marks `.meta({ secret: true })` reaches
|
|
55875
|
+
* the form as a `SecretFieldView`, never text (D789). A patch value omitted, `''`
|
|
55876
|
+
* or the redaction token KEEPS the stored secret; `{ $secretClear: true }`
|
|
55877
|
+
* clears it.
|
|
55878
|
+
*/
|
|
55879
|
+
var ConfigSchemaPassthrough$3 = custom();
|
|
55880
|
+
var IntegrationInstanceIdSchema = string().min(1);
|
|
55881
|
+
var IntegrationInstanceDescriptionSchema = object({
|
|
55882
|
+
/** `single`: at most one instance can exist (Loki). `multiple`: an account each. */
|
|
55883
|
+
instanceMode: _enum(["single", "multiple"]),
|
|
55884
|
+
/** What the instance is, for the UI (`destination`, `relay`, `account`). */
|
|
55885
|
+
kind: string(),
|
|
55886
|
+
/** True when `testInstance` really probes the remote. */
|
|
55887
|
+
canTest: boolean()
|
|
55888
|
+
});
|
|
55889
|
+
var IntegrationInstanceStatusSchema = object({
|
|
55890
|
+
state: _enum([
|
|
55891
|
+
"ok",
|
|
55892
|
+
"off",
|
|
55893
|
+
"error",
|
|
55894
|
+
"unknown"
|
|
55895
|
+
]),
|
|
55896
|
+
detail: string().optional()
|
|
55897
|
+
});
|
|
55898
|
+
var IntegrationInstanceSchema = object({
|
|
55899
|
+
id: IntegrationInstanceIdSchema,
|
|
55900
|
+
name: string(),
|
|
55901
|
+
/** The addon's own rule (an URL is present, a client id is present...). */
|
|
55902
|
+
configured: boolean(),
|
|
55903
|
+
/** Values for the instance form; a secret is a `SecretFieldView`, never text. */
|
|
55904
|
+
formValues: record(string(), unknown()),
|
|
55905
|
+
status: IntegrationInstanceStatusSchema.optional()
|
|
55906
|
+
});
|
|
55907
|
+
var IntegrationInstancePatchSchema = object({
|
|
55908
|
+
id: IntegrationInstanceIdSchema,
|
|
55909
|
+
name: string().min(1).optional(),
|
|
55910
|
+
/** Omitted / '' / redaction token keeps a secret; `{ $secretClear: true }` clears it. */
|
|
55911
|
+
values: record(string(), unknown())
|
|
55912
|
+
});
|
|
55913
|
+
method(_void(), IntegrationInstanceDescriptionSchema, { auth: "admin" }), method(object({ id: IntegrationInstanceIdSchema.nullable() }), ConfigSchemaPassthrough$3, { auth: "admin" }), method(_void(), array(IntegrationInstanceSchema).readonly(), { auth: "admin" }), method(object({ id: IntegrationInstanceIdSchema }), IntegrationInstanceSchema.nullable(), { auth: "admin" }), method(object({
|
|
55914
|
+
id: IntegrationInstanceIdSchema,
|
|
55915
|
+
name: string().min(1)
|
|
55916
|
+
}), object({ id: string() }), {
|
|
55917
|
+
kind: "mutation",
|
|
55918
|
+
auth: "admin"
|
|
55919
|
+
}), method(IntegrationInstancePatchSchema, object({ ok: literal(true) }), {
|
|
55920
|
+
kind: "mutation",
|
|
55921
|
+
auth: "admin"
|
|
55922
|
+
}), method(object({ id: IntegrationInstanceIdSchema }), object({ ok: literal(true) }), {
|
|
55923
|
+
kind: "mutation",
|
|
55924
|
+
auth: "admin"
|
|
55925
|
+
}), optionalMethod(object({
|
|
55926
|
+
id: IntegrationInstanceIdSchema.nullable(),
|
|
55927
|
+
values: record(string(), unknown())
|
|
55928
|
+
}), TestConnectionResultSchema$1, {
|
|
55929
|
+
kind: "mutation",
|
|
55930
|
+
auth: "admin"
|
|
55931
|
+
});
|
|
55932
|
+
/**
|
|
55818
55933
|
* Two-way audio / talk-back cap. Clients open a WebRTC audio-only
|
|
55819
55934
|
* session (server-initiated offer pattern, identical to the main
|
|
55820
55935
|
* video WebRTC flow) and the browser captures the mic; the server
|
|
@@ -66582,7 +66697,14 @@ var NcMediaPolicySchema = object({
|
|
|
66582
66697
|
*/
|
|
66583
66698
|
profile: CamProfileSchema.optional(),
|
|
66584
66699
|
/** See {@link NcLinkedCameraModeSchema}. */
|
|
66585
|
-
linkedCameras: NcLinkedCameraModeSchema.optional()
|
|
66700
|
+
linkedCameras: NcLinkedCameraModeSchema.optional(),
|
|
66701
|
+
/**
|
|
66702
|
+
* Sensor rules only: may this rule wake a SLEEPING battery camera to take
|
|
66703
|
+
* the linked still it attaches (D998)? Absent means yes, an explicit `false`
|
|
66704
|
+
* opts out. Deliberately not a Zod default: a rule that never chose keeps
|
|
66705
|
+
* following the hub's. One bounded wake per event; nothing is attached later.
|
|
66706
|
+
*/
|
|
66707
|
+
wakeSleepingCamera: boolean().optional()
|
|
66586
66708
|
});
|
|
66587
66709
|
/**
|
|
66588
66710
|
* Cooldown GRANULARITY over the subject's class — how much a fired
|
|
@@ -75163,7 +75285,16 @@ var smokeCapability = {
|
|
|
75163
75285
|
* future fields without breaking the existing call sites.
|
|
75164
75286
|
*/
|
|
75165
75287
|
var EmailAddressSchema = email();
|
|
75288
|
+
/**
|
|
75289
|
+
* Which relay of a multi-relay provider answers (D996). Absent = the provider's first / default
|
|
75290
|
+
* relay, so a caller written before relays existed keeps working unchanged. A provider with one
|
|
75291
|
+
* fixed relay ignores it. This is the integration instance id (`int_NNNN`), NOT the addon id: the
|
|
75292
|
+
* collection pin `addonId` still picks the provider, `instanceId` picks the relay inside it.
|
|
75293
|
+
*/
|
|
75294
|
+
var InstanceIdSchema = string().min(1).optional();
|
|
75295
|
+
var RelayPinSchema = object({ instanceId: InstanceIdSchema });
|
|
75166
75296
|
var SendEmailInputSchema = object({
|
|
75297
|
+
instanceId: InstanceIdSchema,
|
|
75167
75298
|
to: union([EmailAddressSchema, array(EmailAddressSchema).min(1)]),
|
|
75168
75299
|
cc: array(EmailAddressSchema).optional(),
|
|
75169
75300
|
bcc: array(EmailAddressSchema).optional(),
|
|
@@ -75199,11 +75330,11 @@ method(SendEmailInputSchema, SendEmailResultSchema, {
|
|
|
75199
75330
|
kind: "mutation",
|
|
75200
75331
|
auth: "admin",
|
|
75201
75332
|
access: "create"
|
|
75202
|
-
}), method(
|
|
75333
|
+
}), method(RelayPinSchema, SmtpStatusSchema, {
|
|
75203
75334
|
kind: "mutation",
|
|
75204
75335
|
auth: "admin",
|
|
75205
75336
|
access: "view"
|
|
75206
|
-
}), method(
|
|
75337
|
+
}), method(RelayPinSchema, SmtpStatusSchema, { auth: "admin" });
|
|
75207
75338
|
/**
|
|
75208
75339
|
* A single device snapshot returned as base64 JPEG/PNG.
|
|
75209
75340
|
*
|
|
@@ -75235,10 +75366,12 @@ DeviceType.Camera, method(object({
|
|
|
75235
75366
|
* even when the cache is well within the device's
|
|
75236
75367
|
* `snapshotMaxAgeS` window.
|
|
75237
75368
|
*
|
|
75238
|
-
* **`force` is
|
|
75369
|
+
* **`force` is a demand with a named principal, not a freshness
|
|
75370
|
+
* preference** — an operator button, the scheduled refresh (D847), or a
|
|
75371
|
+
* notification rule that left the camera's wake allowed (D998). On a
|
|
75239
75372
|
* battery camera it is the one thing that walks past the wrapper's
|
|
75240
|
-
* sleep gate and wakes the camera, so a
|
|
75241
|
-
*
|
|
75373
|
+
* sleep gate and wakes the camera, so a poller, a thumbnail or a
|
|
75374
|
+
* prestream must NEVER set it. Every such caller
|
|
75242
75375
|
* gets the cached frame, which on a sleeping battery camera is the
|
|
75243
75376
|
* correct answer: stale but honest beats woken.
|
|
75244
75377
|
*/
|
|
@@ -80088,7 +80221,7 @@ function runningFromMediaPlayer(state, previous, fetchedAt, transitionAt) {
|
|
|
80088
80221
|
if (state === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
|
|
80089
80222
|
return nativeSlice(false, state, previous, transitionAtMs, fetchedAt, null);
|
|
80090
80223
|
}
|
|
80091
|
-
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
80224
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
80092
80225
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
80093
80226
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
80094
80227
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
@@ -85271,6 +85404,62 @@ Object.freeze({
|
|
|
85271
85404
|
access: "create",
|
|
85272
85405
|
role: "admin"
|
|
85273
85406
|
},
|
|
85407
|
+
"integrationInstances.createInstance": {
|
|
85408
|
+
capName: "integration-instances",
|
|
85409
|
+
capScope: "system",
|
|
85410
|
+
addonId: null,
|
|
85411
|
+
access: "create",
|
|
85412
|
+
role: "admin"
|
|
85413
|
+
},
|
|
85414
|
+
"integrationInstances.deleteInstance": {
|
|
85415
|
+
capName: "integration-instances",
|
|
85416
|
+
capScope: "system",
|
|
85417
|
+
addonId: null,
|
|
85418
|
+
access: "delete",
|
|
85419
|
+
role: "admin"
|
|
85420
|
+
},
|
|
85421
|
+
"integrationInstances.describe": {
|
|
85422
|
+
capName: "integration-instances",
|
|
85423
|
+
capScope: "system",
|
|
85424
|
+
addonId: null,
|
|
85425
|
+
access: "view",
|
|
85426
|
+
role: "admin"
|
|
85427
|
+
},
|
|
85428
|
+
"integrationInstances.getInstance": {
|
|
85429
|
+
capName: "integration-instances",
|
|
85430
|
+
capScope: "system",
|
|
85431
|
+
addonId: null,
|
|
85432
|
+
access: "view",
|
|
85433
|
+
role: "admin"
|
|
85434
|
+
},
|
|
85435
|
+
"integrationInstances.instanceFormSchema": {
|
|
85436
|
+
capName: "integration-instances",
|
|
85437
|
+
capScope: "system",
|
|
85438
|
+
addonId: null,
|
|
85439
|
+
access: "view",
|
|
85440
|
+
role: "admin"
|
|
85441
|
+
},
|
|
85442
|
+
"integrationInstances.listInstances": {
|
|
85443
|
+
capName: "integration-instances",
|
|
85444
|
+
capScope: "system",
|
|
85445
|
+
addonId: null,
|
|
85446
|
+
access: "view",
|
|
85447
|
+
role: "admin"
|
|
85448
|
+
},
|
|
85449
|
+
"integrationInstances.testInstance": {
|
|
85450
|
+
capName: "integration-instances",
|
|
85451
|
+
capScope: "system",
|
|
85452
|
+
addonId: null,
|
|
85453
|
+
access: "create",
|
|
85454
|
+
role: "admin"
|
|
85455
|
+
},
|
|
85456
|
+
"integrationInstances.updateInstance": {
|
|
85457
|
+
capName: "integration-instances",
|
|
85458
|
+
capScope: "system",
|
|
85459
|
+
addonId: null,
|
|
85460
|
+
access: "create",
|
|
85461
|
+
role: "admin"
|
|
85462
|
+
},
|
|
85274
85463
|
"integrations.create": {
|
|
85275
85464
|
capName: "integrations",
|
|
85276
85465
|
capScope: "system",
|