@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.
@@ -784,7 +784,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
784
784
  return EventCategory;
785
785
  }({});
786
786
  //#endregion
787
- //#region ../types/dist/device-type-BOWLtoOt.mjs
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-Bei295Bz.mjs
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$6(value) {
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$6(value)) return false;
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$6(value) && value["$secretClear"] === true;
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$5(value) {
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$5(value)) for (const child of Object.values(value)) collectSecretMarkerRefs(child, out);
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$5) : [];
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$5(row)) {
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$5(incoming)) {
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$5(stored) ? stored : {};
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$5(v)) {
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$4(value) {
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$4(item) && isRecord$4(twin)) return inArrayRow(pass, item, twin);
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$4(value) && isRecord$4(twin)) out[key] = inArrayRow(pass, value, twin);
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$4(incoming) || !isRecord$4(stored)) return incoming;
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$4(a) && isRecord$4(b)) {
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$4(value)) return null;
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-kKKOdFIG.mjs
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$3 = unknown();
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$3,
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(_void(), SmtpStatusSchema, {
75333
+ }), method(RelayPinSchema, SmtpStatusSchema, {
75203
75334
  kind: "mutation",
75204
75335
  auth: "admin",
75205
75336
  access: "view"
75206
- }), method(_void(), SmtpStatusSchema, { auth: "admin" });
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 an OPERATOR signal, not a freshness preference.** On a
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 background caller — a poller,
75241
- * an event handler, a thumbnail — must NEVER set it. Every such caller
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",