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