@camstack/addon-provider-homeassistant 1.2.654 → 1.2.655

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