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