@camstack/addon-import-alexa 0.2.197 → 0.2.198

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/addon.mjs CHANGED
@@ -5674,7 +5674,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
5674
5674
  return EventCategory;
5675
5675
  }({});
5676
5676
  //#endregion
5677
- //#region ../types/dist/device-type-D1fH5kaC.mjs
5677
+ //#region ../types/dist/device-type-DxCT0krO.mjs
5678
5678
  /**
5679
5679
  import { errMsg } from '@camstack/types'
5680
5680
  * Extract a human-readable message from an unknown error value.
@@ -5836,6 +5836,13 @@ var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
5836
5836
  * filters that want "all devices with on-motion behaviour".
5837
5837
  */
5838
5838
  DeviceFeature["MotionTrigger"] = "motion-trigger";
5839
+ /**
5840
+ * Device can be run for a chosen time and then stopped. Mirrors the
5841
+ * `timed-run` wrapper cap — the cap is bound by the core-blocks addon, not by
5842
+ * a driver, so the flag is derived from the device's bindings
5843
+ * (`featuresOfBoundCaps`). Gates the quick-run control in the viewer.
5844
+ */
5845
+ DeviceFeature["TimedRun"] = "timed-run";
5839
5846
  /** Light supports rgb-triplet color via `color` cap. */
5840
5847
  DeviceFeature["LightColorRgb"] = "light-color-rgb";
5841
5848
  /** Light supports HSV color via `color` cap. */
@@ -6059,7 +6066,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
6059
6066
  return DeviceRole;
6060
6067
  }({});
6061
6068
  //#endregion
6062
- //#region ../types/dist/sleep-CQP-REJp.mjs
6069
+ //#region ../types/dist/sleep-7El4r5Bl.mjs
6063
6070
  /**
6064
6071
  * The audio chunk plane's byte format, and the ONE expansion from a coded
6065
6072
  * window to float samples (D455).
@@ -8444,7 +8451,7 @@ function boundOf(list) {
8444
8451
  * Base class for CamStack addons. Eliminates settings boilerplate:
8445
8452
  *
8446
8453
  * - Typed `config` property with automatic resolution from store + defaults
8447
- * - `getGlobalSettings()` / `updateGlobalSettings()` auto-implemented
8454
+ * - the scoped settings API (`clusterSettings` / `nodeSettings` / `deviceDefaults`) auto-implemented
8448
8455
  * - `getAddonSettings()` / `updateAddonSettings()` auto-implemented
8449
8456
  * - `getDeviceSettings()` / `updateDeviceSettings()` auto-implemented
8450
8457
  * - `ctx` accessor for the AddonContext (no manual `this.ctxRef` storage)
@@ -8454,7 +8461,7 @@ function boundOf(list) {
8454
8461
  * Subclasses override:
8455
8462
  * - `onInitialize()` — addon-specific init logic, return ProviderRegistration[]
8456
8463
  * - `onShutdown()` — cleanup
8457
- * - `globalSettingsSchema()` / `deviceSettingsSchema()` — UI schemas
8464
+ * - `clusterSettingsSchema()` / `nodeSettingsSchema()` / `deviceSettingsSchema()` — UI schemas
8458
8465
  *
8459
8466
  * @example
8460
8467
  * ```ts
@@ -8468,7 +8475,7 @@ function boundOf(list) {
8468
8475
  * super({ maxRetries: 3, endpoint: 'http://localhost' })
8469
8476
  * }
8470
8477
  *
8471
- * protected globalSettingsSchema() {
8478
+ * protected clusterSettingsSchema() {
8472
8479
  * return this.schema({
8473
8480
  * sections: [{
8474
8481
  * id: 'main', title: 'Settings',
@@ -8511,7 +8518,7 @@ var BaseAddon = class {
8511
8518
  defaults;
8512
8519
  /**
8513
8520
  * Hidden-state paths that hold secrets (D787) — values the addon writes
8514
- * itself (`updateGlobalSettings`, `state()`) that no form field declares.
8521
+ * itself (`state()`, the scoped writers) that no form field declares.
8515
8522
  * Stored in the keychain exactly like a `password` field. Syntax:
8516
8523
  * `'snapshotSigningKey'`, `'identity.pincode'`, `'tokens[userId].accessToken'`
8517
8524
  * (`key[<id field>]` addresses array items by id, never by index).
@@ -8521,7 +8528,7 @@ var BaseAddon = class {
8521
8528
  /**
8522
8529
  * D986 M4: the scoped schemas this addon declared, resolved once per capability
8523
8530
  * (`loadScopedSchemas`) so the sync readers (`perNodeKeys`, the secret tree, the restart check)
8524
- * see them. Empty until loaded: the readers then fall back to {@link globalSettingsSchema}.
8531
+ * see them. Empty until loaded.
8525
8532
  */
8526
8533
  _scopedByCap = /* @__PURE__ */ new Map();
8527
8534
  _nodeKeysByCap = /* @__PURE__ */ new Map();
@@ -8707,7 +8714,7 @@ var BaseAddon = class {
8707
8714
  /** Addon-specific cleanup. Override if needed. */
8708
8715
  async onShutdown() {}
8709
8716
  /**
8710
- * Called after config is resolved during updateGlobalSettings/updateAddonSettings.
8717
+ * Called after config is resolved during a settings write.
8711
8718
  * Override to react to config changes (e.g. restart a sampler, reconnect a service).
8712
8719
  * Not called during initialize() — use onInitialize() for initial setup.
8713
8720
  */
@@ -8736,82 +8743,12 @@ var BaseAddon = class {
8736
8743
  scopedSettingsCapabilities() {
8737
8744
  return [];
8738
8745
  }
8739
- /** Override to provide global-level settings UI schema. */
8740
- globalSettingsSchema(_cap) {
8741
- return null;
8742
- }
8743
8746
  /** Override to provide device-level settings UI schema. */
8744
8747
  deviceSettingsSchema() {
8745
8748
  return null;
8746
8749
  }
8747
8750
  /**
8748
- * INTEGRATION-LEVEL SETTINGS — declare which of this addon's global sections
8749
- * ARE the configuration of its integration.
8750
- *
8751
- * Return the `ConfigSection.id`s, from {@link globalSettingsSchema}, that an
8752
- * operator should find on the addon's integration page (System →
8753
- * Integrations → <name>) rather than only in the cluster-wide list of every
8754
- * addon. Empty (the default) means the addon has no integration-level
8755
- * settings and no such surface is offered — this is opt-in, because whether
8756
- * an addon's configuration IS its integration's configuration depends on the
8757
- * nature of the integration.
8758
- *
8759
- * WHAT THIS IS NOT. It is not a scope. The selected sections keep living in
8760
- * the ONE global schema, in the ONE addon store, written by the ONE
8761
- * `updateGlobalSettings` path. There is deliberately no
8762
- * `updateIntegrationSettings`: a second write path is how a surface acquires
8763
- * a second store key, and this repo has shipped that twice (`btmPath@hub`,
8764
- * D266). Selecting sections cannot introduce a key that selecting cannot.
8765
- *
8766
- * WHY IT IS A LIST OF SECTION IDS AND NOT A MARKER ON THE SECTION.
8767
- * `ConfigFieldBase` used to carry `scope?: 'device' | 'global'` and it was
8768
- * removed with the reason recorded at
8769
- * `packages/types/src/interfaces/config-ui.ts:249` — *"a field's scope is
8770
- * determined by WHICH schema it lives in, not by a field-level marker."* A
8771
- * marker sprinkled across sections also has to borrow a field that already
8772
- * means something else; borrowing `section.tab` put the literal word
8773
- * "integration" into an operator-facing tab bar, because `tab` means "how to
8774
- * GROUP this visually" and cannot also mean "where this lives" (D269
8775
- * supersedes D268). One declaration, in one place, next to the schema whose
8776
- * ids it names.
8777
- */
8778
- integrationSettingSections() {
8779
- return [];
8780
- }
8781
- async getGlobalSettings(overlay, cap, nodeId) {
8782
- await this.loadScopedSchemas(cap);
8783
- const schema = this.globalSettingsSchema(cap) ?? this.scopedFormSchema(cap);
8784
- if (!schema) return { sections: [] };
8785
- const projected = await this.readRawProjectedStore(nodeId, cap);
8786
- return hydrateSchema(schema, overlay ? await this.overlayKeepingMarkers(projected, overlay) : projected, { inlineSecretsAsViews: true });
8787
- }
8788
- /**
8789
- * The integration-level view of this addon's settings: exactly the sections
8790
- * named by {@link integrationSettingSections}, hydrated from the SAME store
8791
- * `getGlobalSettings` reads, and narrowed to cluster-scoped fields.
8792
- *
8793
- * Returns `null` when the addon declared nothing — an addon that opts out has
8794
- * no integration settings surface at all, rather than an empty one that reads
8795
- * as a failed load.
8796
- *
8797
- * Three properties hold BY CONSTRUCTION, which is why they are here in core
8798
- * and not in whichever UI happens to render this:
8799
- *
8800
- * 1. **One key.** The payload is a SUBSET of the global schema, so a field
8801
- * shown here is the same field, with the same bare key, that the addon's
8802
- * own page shows. There is no integration-specific writer — callers save
8803
- * through `updateGlobalSettings` — so a second store key is unreachable,
8804
- * not merely discouraged.
8805
- * 2. **No node scope.** `perNode: true` fields are DROPPED. Their store key
8806
- * is `<key>@<nodeId>` and an integration is not a node; whichever node
8807
- * such a field silently picked would be a wrong answer for the operator
8808
- * who opened the page (D266).
8809
- * 3. **No silent typo.** A declared id that names no section throws. The
8810
- * alternative — skip it — turns a rename into a surface that quietly
8811
- * empties, which looks exactly like an addon with nothing to configure.
8812
- */
8813
- /**
8814
- * The form schema of ONE integration instance, or `null` to use {@link globalSettingsSchema}.
8751
+ * The form schema of ONE integration instance, or `null` to use the scoped form.
8815
8752
  *
8816
8753
  * Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
8817
8754
  * needs its connection fields, the default integration the addon's own sections. It is the
@@ -8984,6 +8921,19 @@ var BaseAddon = class {
8984
8921
  const overlay = await this.scopedSettingsOverlay(scope, cap, nodeId);
8985
8922
  return hydrateSchema(schema, overlay ? await this.overlayKeepingMarkers(stored, overlay) : stored, { inlineSecretsAsViews: true });
8986
8923
  }
8924
+ /**
8925
+ * The scoped schemas this addon serves: one entry per loaded (capability, scope), capabilities
8926
+ * in declaration order, scopes in {@link SCOPED_SETTINGS_SCOPES} order. `[]` when it declares
8927
+ * nothing.
8928
+ */
8929
+ async listScopedSettings() {
8930
+ await this.loadScopedSchemas();
8931
+ return [...this._scopedByCap].flatMap(([cap, entries]) => entries.map((entry) => ({
8932
+ cap,
8933
+ scope: entry.scope,
8934
+ sectionIds: entry.schema.sections.map((section) => section.id)
8935
+ })));
8936
+ }
8987
8937
  /** The OPERATOR's write of declared keys of one scope (D787 secret semantics). */
8988
8938
  async updateScopedSettings(scope, cap, patch, nodeId) {
8989
8939
  this._operatorWriteDepth++;
@@ -9009,32 +8959,15 @@ var BaseAddon = class {
9009
8959
  */
9010
8960
  async getIntegrationFormSchema(instance, nodeId) {
9011
8961
  const scoped = await this.integrationFormSchema(instance);
9012
- if (scoped === null) return this.getGlobalSettings(void 0, void 0, nodeId);
8962
+ if (scoped === null) return this.scopedForm(nodeId);
9013
8963
  return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
9014
8964
  }
9015
- async getIntegrationSettings(nodeId) {
9016
- const declared = this.integrationSettingSections();
9017
- if (declared.length === 0) return null;
9018
- const schema = this.globalSettingsSchema();
9019
- if (!schema) throw new Error(`${this.constructor.name}: integrationSettingSections() names [${declared.join(", ")}] but globalSettingsSchema() returns null.`);
9020
- const byId = new Map(schema.sections.map((section) => [section.id, section]));
9021
- const sections = [];
9022
- for (const id of declared) {
9023
- const section = byId.get(id);
9024
- if (!section) throw new Error(`${this.constructor.name}: integrationSettingSections() names unknown section "${id}". Known sections: [${[...byId.keys()].join(", ")}].`);
9025
- const fields = dropPerNodeFields(section.fields);
9026
- if (fields.length === 0) continue;
9027
- sections.push({
9028
- ...section,
9029
- fields
9030
- });
9031
- }
9032
- if (sections.length === 0) return null;
9033
- const projected = await this.readRawProjectedStore(nodeId);
9034
- return hydrateSchema({
9035
- ...schema,
9036
- sections
9037
- }, projected, { inlineSecretsAsViews: true });
8965
+ /** The form of the scoped schemas this addon declared, hydrated from its store. */
8966
+ async scopedForm(nodeId) {
8967
+ await this.loadScopedSchemas();
8968
+ const schema = this.scopedFormSchema();
8969
+ if (!schema) return { sections: [] };
8970
+ return hydrateSchema(schema, await this.readRawProjectedStore(nodeId), { inlineSecretsAsViews: true });
9038
8971
  }
9039
8972
  /**
9040
8973
  * The raw addon store PROJECTED onto the target node's bare per-node keys:
@@ -9043,8 +8976,8 @@ var BaseAddon = class {
9043
8976
  * bare fallback), all `@`-scoped and stray bare per-node keys are dropped.
9044
8977
  * A no-op passthrough when the schema declares no `perNode` field.
9045
8978
  *
9046
- * This is the sanctioned way for a `getGlobalSettings` OVERRIDE that needs
9047
- * the store for custom option logic (option narrowing, value snapping) to
8979
+ * This is the sanctioned way for an addon that needs
8980
+ * the store for custom logic (option narrowing, value snapping) to
9048
8981
  * read it per-node — never `ctx.settings.readAddonStore()` directly.
9049
8982
  * `nodeId` omitted ⇒ the local node (node-blind injection from ctx).
9050
8983
  *
@@ -9096,7 +9029,7 @@ var BaseAddon = class {
9096
9029
  }
9097
9030
  /**
9098
9031
  * Whether ONE global key of this addon's store was written, read three-way
9099
- * (D651). For a question a hydrated view cannot answer: `getGlobalSettings`
9032
+ * (D651). For a question a hydrated view cannot answer: a hydrated form
9100
9033
  * reports `value ?? default`, so "the operator chose the default" and "nobody
9101
9034
  * chose" look the same, and a failed read looks like both. A `perNode` key is
9102
9035
  * not supported here: its stored name is scoped.
@@ -9130,7 +9063,7 @@ var BaseAddon = class {
9130
9063
  }
9131
9064
  /**
9132
9065
  * The OPERATOR's write — a settings form or an admin API call, dispatched by
9133
- * the kernel. Identical to {@link updateGlobalSettings}, except that a secret
9066
+ * the kernel. The one in-process write of the addon blob that is not a scoped write; a secret
9134
9067
  * the operator sends is stored as sent even when it equals a pre-keychain
9135
9068
  * inline value: the operator re-entering a password is a change, an addon
9136
9069
  * writing back what it read is not (D787).
@@ -9143,9 +9076,6 @@ var BaseAddon = class {
9143
9076
  this._operatorWriteDepth--;
9144
9077
  }
9145
9078
  }
9146
- async updateGlobalSettings(patch, nodeId) {
9147
- await this.applyGlobalPatch(patch, nodeId);
9148
- }
9149
9079
  /**
9150
9080
  * REMOVE stored secrets — their keychain values and their markers (D787).
9151
9081
  *
@@ -9188,8 +9118,7 @@ var BaseAddon = class {
9188
9118
  await this.resolveConfig();
9189
9119
  await this.onConfigChanged();
9190
9120
  this.emitLifecycle(EventCategory.AddonUpdated, { level: "global" });
9191
- const legacy = this.globalSettingsSchema();
9192
- this.maybeAutoRestart(Object.keys(barePatch), [...legacy === null ? [] : [legacy], ...this.loadedScopedSchemas().map((entry) => entry.schema)]);
9121
+ this.maybeAutoRestart(Object.keys(barePatch), this.loadedScopedSchemas().map((entry) => entry.schema));
9193
9122
  return true;
9194
9123
  }
9195
9124
  /**
@@ -9227,10 +9156,7 @@ var BaseAddon = class {
9227
9156
  this._nodeKeysByCap = /* @__PURE__ */ new Map();
9228
9157
  this._addonSecretTree = null;
9229
9158
  }
9230
- /**
9231
- * The form the settings API serves while an addon declares no {@link globalSettingsSchema}: the
9232
- * sections of its scoped schemas, so dropping the old hook does not blank the form.
9233
- */
9159
+ /** The form of an addon's scoped schemas: their sections, each shown once. */
9234
9160
  scopedFormSchema(cap) {
9235
9161
  const byId = /* @__PURE__ */ new Map();
9236
9162
  for (const entry of this.loadedScopedSchemas(cap)) for (const section of entry.schema.sections) if (!byId.has(section.id)) byId.set(section.id, section);
@@ -9242,8 +9168,7 @@ var BaseAddon = class {
9242
9168
  return [...this._scopedByCap.values()].flat();
9243
9169
  }
9244
9170
  /**
9245
- * The field keys that are stored per node: every field of a {@link nodeSettingsSchema}, plus
9246
- * the fields the legacy {@link globalSettingsSchema} still marks `perNode: true`. Derived once
9171
+ * The field keys that are stored per node: every field of a {@link nodeSettingsSchema}. Derived once
9247
9172
  * per `cap` argument and memoized (schemas are static declarations). Empty set ⇒ every
9248
9173
  * per-node code path is bypassed and the settings API behaves like the node-agnostic one.
9249
9174
  * Call {@link loadScopedSchemas} first (the async seams do).
@@ -9252,8 +9177,7 @@ var BaseAddon = class {
9252
9177
  const cacheKey = cap ?? "";
9253
9178
  const cached = this._nodeKeysByCap.get(cacheKey);
9254
9179
  if (cached) return cached;
9255
- const legacy = this.globalSettingsSchema(cap);
9256
- const keys = new Set(legacy ? legacy.sections.flatMap((section) => collectPerNodeFieldKeys(section.fields)) : []);
9180
+ const keys = /* @__PURE__ */ new Set();
9257
9181
  for (const { scope, schema } of this.loadedScopedSchemas(cap)) {
9258
9182
  if (scope !== "node") continue;
9259
9183
  for (const section of schema.sections) for (const key of collectValueFieldKeys(section.fields)) keys.add(key);
@@ -9471,8 +9395,6 @@ var BaseAddon = class {
9471
9395
  }
9472
9396
  declaredKeySet() {
9473
9397
  const keys = new Set(Object.keys(this.defaults));
9474
- const schema = this.globalSettingsSchema();
9475
- if (schema) for (const section of schema.sections) for (const key of collectFieldKeys(section.fields)) keys.add(key);
9476
9398
  for (const { schema: scoped } of this.loadedScopedSchemas()) for (const section of scoped.sections) for (const key of collectFieldKeys(section.fields)) keys.add(key);
9477
9399
  for (const key of this._declaredStateKeys) keys.add(key);
9478
9400
  for (const path of this.secretStatePaths) {
@@ -9570,7 +9492,7 @@ var BaseAddon = class {
9570
9492
  /** The addon store's secret tree: schema fields by TYPE, plus `secretStatePaths`. */
9571
9493
  addonSecretTree() {
9572
9494
  if (this._addonSecretTree === null) {
9573
- const tree = new Map(secretTreeFromSchema(this.globalSettingsSchema()));
9495
+ const tree = /* @__PURE__ */ new Map();
9574
9496
  for (const { schema } of this.loadedScopedSchemas()) for (const [key, node] of secretTreeFromSchema(schema)) tree.set(key, node);
9575
9497
  this._addonSecretTree = mergeSecretStatePaths(tree, this.secretStatePaths);
9576
9498
  }
@@ -9782,47 +9704,6 @@ function classifyStoreError(err) {
9782
9704
  if (TRANSPORT_PHRASES.some((f) => message.includes(f))) return "transport";
9783
9705
  return "permanent";
9784
9706
  }
9785
- /**
9786
- * Collect the keys of every field marked `perNode: true`, recursing into
9787
- * layout containers (`group` fields and `sub-tabs` tabs) the same way
9788
- * `hydrateSchema` does. Valueless structural fields (separator/info/…)
9789
- * don't declare `perNode` and are excluded by the `in` narrowing.
9790
- */
9791
- /**
9792
- * The same fields with every `perNode: true` one removed, recursing into layout
9793
- * containers exactly as {@link collectPerNodeFieldKeys} does. A container left
9794
- * with no child is dropped rather than rendered empty.
9795
- *
9796
- * Used by `getIntegrationSettings`: an integration is not a node, so a field
9797
- * whose store key is `<key>@<nodeId>` has no node to belong to there.
9798
- */
9799
- function dropPerNodeFields(fields) {
9800
- const kept = [];
9801
- for (const field of fields) {
9802
- if (field.type === "group") {
9803
- const inner = dropPerNodeFields(field.fields);
9804
- if (inner.length > 0) kept.push({
9805
- ...field,
9806
- fields: inner
9807
- });
9808
- continue;
9809
- }
9810
- if (field.type === "sub-tabs") {
9811
- const tabs = field.tabs.map((tab) => ({
9812
- ...tab,
9813
- fields: dropPerNodeFields(tab.fields)
9814
- })).filter((tab) => tab.fields.length > 0);
9815
- if (tabs.length > 0) kept.push({
9816
- ...field,
9817
- tabs
9818
- });
9819
- continue;
9820
- }
9821
- if ("perNode" in field && field.perNode === true) continue;
9822
- kept.push(field);
9823
- }
9824
- return kept;
9825
- }
9826
9707
  /** The keys of the value-holding fields, recursing into layout containers. */
9827
9708
  function collectValueFieldKeys(fields) {
9828
9709
  const collected = [];
@@ -9855,21 +9736,6 @@ function collectFieldKeys(fields) {
9855
9736
  }
9856
9737
  return collected;
9857
9738
  }
9858
- function collectPerNodeFieldKeys(fields) {
9859
- const collected = [];
9860
- for (const field of fields) {
9861
- if (field.type === "group") {
9862
- collected.push(...collectPerNodeFieldKeys(field.fields));
9863
- continue;
9864
- }
9865
- if (field.type === "sub-tabs") {
9866
- for (const tab of field.tabs) collected.push(...collectPerNodeFieldKeys(tab.fields));
9867
- continue;
9868
- }
9869
- if ("perNode" in field && field.perNode === true) collected.push(field.key);
9870
- }
9871
- return collected;
9872
- }
9873
9739
  /**
9874
9740
  * Normalize an `ICamstackAddon.initialize()` return value into the
9875
9741
  * `AddonInitResult` envelope. Arrays are wrapped into `{ providers }`;
@@ -12630,13 +12496,25 @@ Object.freeze({
12630
12496
  "path": "temperature",
12631
12497
  "valueType": "number"
12632
12498
  }],
12633
- "timed-run": [{
12634
- "path": "activeUntil",
12635
- "valueType": "number"
12636
- }, {
12637
- "path": "requestedBy",
12638
- "valueType": "string"
12639
- }],
12499
+ "timed-run": [
12500
+ {
12501
+ "path": "activeUntil",
12502
+ "valueType": "number"
12503
+ },
12504
+ {
12505
+ "path": "requestedBy",
12506
+ "valueType": "string"
12507
+ },
12508
+ {
12509
+ "path": "quickRun.duration",
12510
+ "valueType": "number"
12511
+ },
12512
+ {
12513
+ "path": "quickRun.unit",
12514
+ "valueType": "enum",
12515
+ "enumValues": ["s", "min"]
12516
+ }
12517
+ ],
12640
12518
  "update": [
12641
12519
  {
12642
12520
  "path": "currentVersion",
@@ -12860,7 +12738,7 @@ object({
12860
12738
  params: record(string(), union([string(), number$1()])).optional()
12861
12739
  });
12862
12740
  //#endregion
12863
- //#region ../types/dist/composition-BmBHuDTQ.mjs
12741
+ //#region ../types/dist/composition-Bx0JvKUU.mjs
12864
12742
  /**
12865
12743
  * The ffmpeg build every CamStack node downloads, per platform and arch.
12866
12744
  *
@@ -14022,6 +13900,387 @@ var NodeColorIdSchema = _enum([
14022
13900
  "node-h"
14023
13901
  ]);
14024
13902
  //#endregion
13903
+ //#region ../types/dist/convert-BAzH15HU.mjs
13904
+ /**
13905
+ * Frozen unit → spec table. `•` in the doc marks each dimension's canonical
13906
+ * unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
13907
+ * `factor = 5/9`, `offset = -160/9` (kept as exact expressions, not rounded
13908
+ * decimals). K derives from `°C = K − 273.15`.
13909
+ */
13910
+ var UNIT_TABLE = {
13911
+ "°C": {
13912
+ dimension: "temperature",
13913
+ factor: 1,
13914
+ offset: 0
13915
+ },
13916
+ "°F": {
13917
+ dimension: "temperature",
13918
+ factor: 5 / 9,
13919
+ offset: -160 / 9
13920
+ },
13921
+ K: {
13922
+ dimension: "temperature",
13923
+ factor: 1,
13924
+ offset: -273.15
13925
+ },
13926
+ hPa: {
13927
+ dimension: "pressure",
13928
+ factor: 1,
13929
+ offset: 0
13930
+ },
13931
+ kPa: {
13932
+ dimension: "pressure",
13933
+ factor: 10,
13934
+ offset: 0
13935
+ },
13936
+ Pa: {
13937
+ dimension: "pressure",
13938
+ factor: .01,
13939
+ offset: 0
13940
+ },
13941
+ mbar: {
13942
+ dimension: "pressure",
13943
+ factor: 1,
13944
+ offset: 0
13945
+ },
13946
+ bar: {
13947
+ dimension: "pressure",
13948
+ factor: 1e3,
13949
+ offset: 0
13950
+ },
13951
+ inHg: {
13952
+ dimension: "pressure",
13953
+ factor: 33.8639,
13954
+ offset: 0
13955
+ },
13956
+ mmHg: {
13957
+ dimension: "pressure",
13958
+ factor: 1.33322,
13959
+ offset: 0
13960
+ },
13961
+ psi: {
13962
+ dimension: "pressure",
13963
+ factor: 68.9476,
13964
+ offset: 0
13965
+ },
13966
+ "m/s": {
13967
+ dimension: "speed",
13968
+ factor: 1,
13969
+ offset: 0
13970
+ },
13971
+ "km/h": {
13972
+ dimension: "speed",
13973
+ factor: 1 / 3.6,
13974
+ offset: 0
13975
+ },
13976
+ mph: {
13977
+ dimension: "speed",
13978
+ factor: .44704,
13979
+ offset: 0
13980
+ },
13981
+ kn: {
13982
+ dimension: "speed",
13983
+ factor: .514444,
13984
+ offset: 0
13985
+ },
13986
+ "mm/h": {
13987
+ dimension: "precipitation-rate",
13988
+ factor: 1,
13989
+ offset: 0
13990
+ },
13991
+ "in/h": {
13992
+ dimension: "precipitation-rate",
13993
+ factor: 25.4,
13994
+ offset: 0
13995
+ },
13996
+ m: {
13997
+ dimension: "length",
13998
+ factor: 1,
13999
+ offset: 0
14000
+ },
14001
+ mm: {
14002
+ dimension: "length",
14003
+ factor: .001,
14004
+ offset: 0
14005
+ },
14006
+ cm: {
14007
+ dimension: "length",
14008
+ factor: .01,
14009
+ offset: 0
14010
+ },
14011
+ km: {
14012
+ dimension: "length",
14013
+ factor: 1e3,
14014
+ offset: 0
14015
+ },
14016
+ in: {
14017
+ dimension: "length",
14018
+ factor: .0254,
14019
+ offset: 0
14020
+ },
14021
+ ft: {
14022
+ dimension: "length",
14023
+ factor: .3048,
14024
+ offset: 0
14025
+ },
14026
+ mi: {
14027
+ dimension: "length",
14028
+ factor: 1609.344,
14029
+ offset: 0
14030
+ },
14031
+ "m²": {
14032
+ dimension: "area",
14033
+ factor: 1,
14034
+ offset: 0
14035
+ },
14036
+ lx: {
14037
+ dimension: "illuminance",
14038
+ factor: 1,
14039
+ offset: 0
14040
+ },
14041
+ "W/m²": {
14042
+ dimension: "irradiance",
14043
+ factor: 1,
14044
+ offset: 0
14045
+ },
14046
+ W: {
14047
+ dimension: "power",
14048
+ factor: 1,
14049
+ offset: 0
14050
+ },
14051
+ kW: {
14052
+ dimension: "power",
14053
+ factor: 1e3,
14054
+ offset: 0
14055
+ },
14056
+ VA: {
14057
+ dimension: "apparent-power",
14058
+ factor: 1,
14059
+ offset: 0
14060
+ },
14061
+ Wh: {
14062
+ dimension: "energy",
14063
+ factor: 1,
14064
+ offset: 0
14065
+ },
14066
+ kWh: {
14067
+ dimension: "energy",
14068
+ factor: 1e3,
14069
+ offset: 0
14070
+ },
14071
+ MWh: {
14072
+ dimension: "energy",
14073
+ factor: 1e6,
14074
+ offset: 0
14075
+ },
14076
+ V: {
14077
+ dimension: "voltage",
14078
+ factor: 1,
14079
+ offset: 0
14080
+ },
14081
+ mV: {
14082
+ dimension: "voltage",
14083
+ factor: .001,
14084
+ offset: 0
14085
+ },
14086
+ A: {
14087
+ dimension: "current",
14088
+ factor: 1,
14089
+ offset: 0
14090
+ },
14091
+ mA: {
14092
+ dimension: "current",
14093
+ factor: .001,
14094
+ offset: 0
14095
+ },
14096
+ ppm: {
14097
+ dimension: "concentration-volume",
14098
+ factor: 1,
14099
+ offset: 0
14100
+ },
14101
+ ppb: {
14102
+ dimension: "concentration-volume",
14103
+ factor: .001,
14104
+ offset: 0
14105
+ },
14106
+ "µg/m³": {
14107
+ dimension: "concentration-mass",
14108
+ factor: 1,
14109
+ offset: 0
14110
+ },
14111
+ "mg/m³": {
14112
+ dimension: "concentration-mass",
14113
+ factor: 1e3,
14114
+ offset: 0
14115
+ },
14116
+ kg: {
14117
+ dimension: "mass",
14118
+ factor: 1,
14119
+ offset: 0
14120
+ },
14121
+ g: {
14122
+ dimension: "mass",
14123
+ factor: .001,
14124
+ offset: 0
14125
+ },
14126
+ lb: {
14127
+ dimension: "mass",
14128
+ factor: .453592,
14129
+ offset: 0
14130
+ },
14131
+ oz: {
14132
+ dimension: "mass",
14133
+ factor: .0283495,
14134
+ offset: 0
14135
+ },
14136
+ "%": {
14137
+ dimension: "percentage",
14138
+ factor: 1,
14139
+ offset: 0
14140
+ },
14141
+ L: {
14142
+ dimension: "volume",
14143
+ factor: 1,
14144
+ offset: 0
14145
+ },
14146
+ mL: {
14147
+ dimension: "volume",
14148
+ factor: .001,
14149
+ offset: 0
14150
+ },
14151
+ gal: {
14152
+ dimension: "volume",
14153
+ factor: 3.785411784,
14154
+ offset: 0
14155
+ },
14156
+ s: {
14157
+ dimension: "duration",
14158
+ factor: 1,
14159
+ offset: 0
14160
+ },
14161
+ ms: {
14162
+ dimension: "duration",
14163
+ factor: .001,
14164
+ offset: 0
14165
+ },
14166
+ min: {
14167
+ dimension: "duration",
14168
+ factor: 60,
14169
+ offset: 0
14170
+ },
14171
+ h: {
14172
+ dimension: "duration",
14173
+ factor: 3600,
14174
+ offset: 0
14175
+ },
14176
+ d: {
14177
+ dimension: "duration",
14178
+ factor: 86400,
14179
+ offset: 0
14180
+ },
14181
+ B: {
14182
+ dimension: "information",
14183
+ factor: 1,
14184
+ offset: 0
14185
+ },
14186
+ KiB: {
14187
+ dimension: "information",
14188
+ factor: 1024,
14189
+ offset: 0
14190
+ },
14191
+ MiB: {
14192
+ dimension: "information",
14193
+ factor: 1024 ** 2,
14194
+ offset: 0
14195
+ },
14196
+ GiB: {
14197
+ dimension: "information",
14198
+ factor: 1024 ** 3,
14199
+ offset: 0
14200
+ },
14201
+ TiB: {
14202
+ dimension: "information",
14203
+ factor: 1024 ** 4,
14204
+ offset: 0
14205
+ },
14206
+ kB: {
14207
+ dimension: "information",
14208
+ factor: 1e3,
14209
+ offset: 0
14210
+ },
14211
+ MB: {
14212
+ dimension: "information",
14213
+ factor: 1e6,
14214
+ offset: 0
14215
+ },
14216
+ GB: {
14217
+ dimension: "information",
14218
+ factor: 1e9,
14219
+ offset: 0
14220
+ },
14221
+ "°": {
14222
+ dimension: "angle",
14223
+ factor: 1,
14224
+ offset: 0
14225
+ },
14226
+ dBFS: {
14227
+ dimension: "sound-level",
14228
+ factor: 1,
14229
+ offset: 0
14230
+ },
14231
+ dBm: {
14232
+ dimension: "signal-level",
14233
+ factor: 1,
14234
+ offset: 0
14235
+ },
14236
+ mired: {
14237
+ dimension: "colour-temperature",
14238
+ factor: 1,
14239
+ offset: 0
14240
+ },
14241
+ kbps: {
14242
+ dimension: "bitrate",
14243
+ factor: 1,
14244
+ offset: 0
14245
+ },
14246
+ Mbps: {
14247
+ dimension: "bitrate",
14248
+ factor: 1e3,
14249
+ offset: 0
14250
+ },
14251
+ fps: {
14252
+ dimension: "rate",
14253
+ factor: 1,
14254
+ offset: 0
14255
+ }
14256
+ };
14257
+ /** Resolve a unit's `UnitSpec`, or `undefined` when the spelling is unknown. */
14258
+ function specFor(unit) {
14259
+ return Object.hasOwn(UNIT_TABLE, unit) ? UNIT_TABLE[unit] : void 0;
14260
+ }
14261
+ /** Value in `spec`'s unit → its dimension's canonical unit. */
14262
+ function toCanonical(value, spec) {
14263
+ return value * spec.factor + spec.offset;
14264
+ }
14265
+ /** Canonical-unit value → the unit described by `spec`. */
14266
+ function fromCanonical(canonical, spec) {
14267
+ return (canonical - spec.offset) / spec.factor;
14268
+ }
14269
+ /**
14270
+ * Graceful variant for the render path: returns the converted value, or
14271
+ * `undefined` when the conversion is refused (unknown unit / cross-dimension).
14272
+ * Never throws — a render caller falls back to the raw value + source unit.
14273
+ */
14274
+ function tryConvertUnit(value, from, to) {
14275
+ if (from === to) return value;
14276
+ const fromSpec = specFor(from);
14277
+ if (!fromSpec) return void 0;
14278
+ const toSpec = specFor(to);
14279
+ if (!toSpec) return void 0;
14280
+ if (fromSpec.dimension !== toSpec.dimension) return void 0;
14281
+ return fromCanonical(toCanonical(value, fromSpec), toSpec);
14282
+ }
14283
+ //#endregion
14025
14284
  //#region ../types/dist/index.mjs
14026
14285
  var SMTP_INBOUND_DEFAULT_PORT = 2525;
14027
14286
  var SMTP_INBOUND_DEFAULT_DOMAIN = "camstack.local";
@@ -43486,6 +43745,7 @@ var ExpressionBindingSourceSchema = union([
43486
43745
  object({
43487
43746
  kind: literal("global"),
43488
43747
  sourceStableId: string(),
43748
+ addonId: string().optional(),
43489
43749
  cap: string(),
43490
43750
  fieldPath: string()
43491
43751
  })
@@ -43612,385 +43872,6 @@ function extractSourceInfoFromMetadata(metadata) {
43612
43872
  return parsed.data;
43613
43873
  }
43614
43874
  /**
43615
- * Frozen unit → spec table. `•` in the doc marks each dimension's canonical
43616
- * unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
43617
- * `factor = 5/9`, `offset = -160/9` (kept as exact expressions, not rounded
43618
- * decimals). K derives from `°C = K − 273.15`.
43619
- */
43620
- var UNIT_TABLE = {
43621
- "°C": {
43622
- dimension: "temperature",
43623
- factor: 1,
43624
- offset: 0
43625
- },
43626
- "°F": {
43627
- dimension: "temperature",
43628
- factor: 5 / 9,
43629
- offset: -160 / 9
43630
- },
43631
- K: {
43632
- dimension: "temperature",
43633
- factor: 1,
43634
- offset: -273.15
43635
- },
43636
- hPa: {
43637
- dimension: "pressure",
43638
- factor: 1,
43639
- offset: 0
43640
- },
43641
- kPa: {
43642
- dimension: "pressure",
43643
- factor: 10,
43644
- offset: 0
43645
- },
43646
- Pa: {
43647
- dimension: "pressure",
43648
- factor: .01,
43649
- offset: 0
43650
- },
43651
- mbar: {
43652
- dimension: "pressure",
43653
- factor: 1,
43654
- offset: 0
43655
- },
43656
- bar: {
43657
- dimension: "pressure",
43658
- factor: 1e3,
43659
- offset: 0
43660
- },
43661
- inHg: {
43662
- dimension: "pressure",
43663
- factor: 33.8639,
43664
- offset: 0
43665
- },
43666
- mmHg: {
43667
- dimension: "pressure",
43668
- factor: 1.33322,
43669
- offset: 0
43670
- },
43671
- psi: {
43672
- dimension: "pressure",
43673
- factor: 68.9476,
43674
- offset: 0
43675
- },
43676
- "m/s": {
43677
- dimension: "speed",
43678
- factor: 1,
43679
- offset: 0
43680
- },
43681
- "km/h": {
43682
- dimension: "speed",
43683
- factor: 1 / 3.6,
43684
- offset: 0
43685
- },
43686
- mph: {
43687
- dimension: "speed",
43688
- factor: .44704,
43689
- offset: 0
43690
- },
43691
- kn: {
43692
- dimension: "speed",
43693
- factor: .514444,
43694
- offset: 0
43695
- },
43696
- "mm/h": {
43697
- dimension: "precipitation-rate",
43698
- factor: 1,
43699
- offset: 0
43700
- },
43701
- "in/h": {
43702
- dimension: "precipitation-rate",
43703
- factor: 25.4,
43704
- offset: 0
43705
- },
43706
- m: {
43707
- dimension: "length",
43708
- factor: 1,
43709
- offset: 0
43710
- },
43711
- mm: {
43712
- dimension: "length",
43713
- factor: .001,
43714
- offset: 0
43715
- },
43716
- cm: {
43717
- dimension: "length",
43718
- factor: .01,
43719
- offset: 0
43720
- },
43721
- km: {
43722
- dimension: "length",
43723
- factor: 1e3,
43724
- offset: 0
43725
- },
43726
- in: {
43727
- dimension: "length",
43728
- factor: .0254,
43729
- offset: 0
43730
- },
43731
- ft: {
43732
- dimension: "length",
43733
- factor: .3048,
43734
- offset: 0
43735
- },
43736
- mi: {
43737
- dimension: "length",
43738
- factor: 1609.344,
43739
- offset: 0
43740
- },
43741
- "m²": {
43742
- dimension: "area",
43743
- factor: 1,
43744
- offset: 0
43745
- },
43746
- lx: {
43747
- dimension: "illuminance",
43748
- factor: 1,
43749
- offset: 0
43750
- },
43751
- "W/m²": {
43752
- dimension: "irradiance",
43753
- factor: 1,
43754
- offset: 0
43755
- },
43756
- W: {
43757
- dimension: "power",
43758
- factor: 1,
43759
- offset: 0
43760
- },
43761
- kW: {
43762
- dimension: "power",
43763
- factor: 1e3,
43764
- offset: 0
43765
- },
43766
- VA: {
43767
- dimension: "apparent-power",
43768
- factor: 1,
43769
- offset: 0
43770
- },
43771
- Wh: {
43772
- dimension: "energy",
43773
- factor: 1,
43774
- offset: 0
43775
- },
43776
- kWh: {
43777
- dimension: "energy",
43778
- factor: 1e3,
43779
- offset: 0
43780
- },
43781
- MWh: {
43782
- dimension: "energy",
43783
- factor: 1e6,
43784
- offset: 0
43785
- },
43786
- V: {
43787
- dimension: "voltage",
43788
- factor: 1,
43789
- offset: 0
43790
- },
43791
- mV: {
43792
- dimension: "voltage",
43793
- factor: .001,
43794
- offset: 0
43795
- },
43796
- A: {
43797
- dimension: "current",
43798
- factor: 1,
43799
- offset: 0
43800
- },
43801
- mA: {
43802
- dimension: "current",
43803
- factor: .001,
43804
- offset: 0
43805
- },
43806
- ppm: {
43807
- dimension: "concentration-volume",
43808
- factor: 1,
43809
- offset: 0
43810
- },
43811
- ppb: {
43812
- dimension: "concentration-volume",
43813
- factor: .001,
43814
- offset: 0
43815
- },
43816
- "µg/m³": {
43817
- dimension: "concentration-mass",
43818
- factor: 1,
43819
- offset: 0
43820
- },
43821
- "mg/m³": {
43822
- dimension: "concentration-mass",
43823
- factor: 1e3,
43824
- offset: 0
43825
- },
43826
- kg: {
43827
- dimension: "mass",
43828
- factor: 1,
43829
- offset: 0
43830
- },
43831
- g: {
43832
- dimension: "mass",
43833
- factor: .001,
43834
- offset: 0
43835
- },
43836
- lb: {
43837
- dimension: "mass",
43838
- factor: .453592,
43839
- offset: 0
43840
- },
43841
- oz: {
43842
- dimension: "mass",
43843
- factor: .0283495,
43844
- offset: 0
43845
- },
43846
- "%": {
43847
- dimension: "percentage",
43848
- factor: 1,
43849
- offset: 0
43850
- },
43851
- L: {
43852
- dimension: "volume",
43853
- factor: 1,
43854
- offset: 0
43855
- },
43856
- mL: {
43857
- dimension: "volume",
43858
- factor: .001,
43859
- offset: 0
43860
- },
43861
- gal: {
43862
- dimension: "volume",
43863
- factor: 3.785411784,
43864
- offset: 0
43865
- },
43866
- s: {
43867
- dimension: "duration",
43868
- factor: 1,
43869
- offset: 0
43870
- },
43871
- ms: {
43872
- dimension: "duration",
43873
- factor: .001,
43874
- offset: 0
43875
- },
43876
- min: {
43877
- dimension: "duration",
43878
- factor: 60,
43879
- offset: 0
43880
- },
43881
- h: {
43882
- dimension: "duration",
43883
- factor: 3600,
43884
- offset: 0
43885
- },
43886
- d: {
43887
- dimension: "duration",
43888
- factor: 86400,
43889
- offset: 0
43890
- },
43891
- B: {
43892
- dimension: "information",
43893
- factor: 1,
43894
- offset: 0
43895
- },
43896
- KiB: {
43897
- dimension: "information",
43898
- factor: 1024,
43899
- offset: 0
43900
- },
43901
- MiB: {
43902
- dimension: "information",
43903
- factor: 1024 ** 2,
43904
- offset: 0
43905
- },
43906
- GiB: {
43907
- dimension: "information",
43908
- factor: 1024 ** 3,
43909
- offset: 0
43910
- },
43911
- TiB: {
43912
- dimension: "information",
43913
- factor: 1024 ** 4,
43914
- offset: 0
43915
- },
43916
- kB: {
43917
- dimension: "information",
43918
- factor: 1e3,
43919
- offset: 0
43920
- },
43921
- MB: {
43922
- dimension: "information",
43923
- factor: 1e6,
43924
- offset: 0
43925
- },
43926
- GB: {
43927
- dimension: "information",
43928
- factor: 1e9,
43929
- offset: 0
43930
- },
43931
- "°": {
43932
- dimension: "angle",
43933
- factor: 1,
43934
- offset: 0
43935
- },
43936
- dBFS: {
43937
- dimension: "sound-level",
43938
- factor: 1,
43939
- offset: 0
43940
- },
43941
- dBm: {
43942
- dimension: "signal-level",
43943
- factor: 1,
43944
- offset: 0
43945
- },
43946
- mired: {
43947
- dimension: "colour-temperature",
43948
- factor: 1,
43949
- offset: 0
43950
- },
43951
- kbps: {
43952
- dimension: "bitrate",
43953
- factor: 1,
43954
- offset: 0
43955
- },
43956
- Mbps: {
43957
- dimension: "bitrate",
43958
- factor: 1e3,
43959
- offset: 0
43960
- },
43961
- fps: {
43962
- dimension: "rate",
43963
- factor: 1,
43964
- offset: 0
43965
- }
43966
- };
43967
- /** Resolve a unit's `UnitSpec`, or `undefined` when the spelling is unknown. */
43968
- function specFor(unit) {
43969
- return Object.hasOwn(UNIT_TABLE, unit) ? UNIT_TABLE[unit] : void 0;
43970
- }
43971
- /** Value in `spec`'s unit → its dimension's canonical unit. */
43972
- function toCanonical(value, spec) {
43973
- return value * spec.factor + spec.offset;
43974
- }
43975
- /** Canonical-unit value → the unit described by `spec`. */
43976
- function fromCanonical(canonical, spec) {
43977
- return (canonical - spec.offset) / spec.factor;
43978
- }
43979
- /**
43980
- * Graceful variant for the render path: returns the converted value, or
43981
- * `undefined` when the conversion is refused (unknown unit / cross-dimension).
43982
- * Never throws — a render caller falls back to the raw value + source unit.
43983
- */
43984
- function tryConvertUnit(value, from, to) {
43985
- if (from === to) return value;
43986
- const fromSpec = specFor(from);
43987
- if (!fromSpec) return void 0;
43988
- const toSpec = specFor(to);
43989
- if (!toSpec) return void 0;
43990
- if (fromSpec.dimension !== toSpec.dimension) return void 0;
43991
- return fromCanonical(toCanonical(value, fromSpec), toSpec);
43992
- }
43993
- /**
43994
43875
  * A number a person types for a physical quantity — the input side of the
43995
43876
  * value + unit contract (D972).
43996
43877
  *
@@ -45688,26 +45569,23 @@ var SettingsSchemaWithValuesSchema = object({
45688
45569
  var SettingsPatchSchema = record(string(), unknown());
45689
45570
  /** The scope of a scoped-settings call (D986): where the capability declared the values. */
45690
45571
  var ScopedSettingsScopeSchema = _enum(SCOPED_SETTINGS_SCOPES);
45572
+ /** One scoped schema an addon serves: its capability, scope and section ids. */
45573
+ var ScopedSettingsDeclarationSchema = object({
45574
+ cap: string(),
45575
+ scope: ScopedSettingsScopeSchema,
45576
+ sectionIds: array(string())
45577
+ });
45691
45578
  /** Standard success response for update operations. */
45692
45579
  var SettingsUpdateResultSchema = object({ success: literal(true) });
45693
45580
  method(object({
45694
- addonId: string(),
45695
- nodeId: string().optional(),
45696
- overlay: record(string(), unknown()).optional(),
45697
- cap: string().optional()
45698
- }), SettingsSchemaWithValuesSchema.nullable()), method(object({
45699
- addonId: string(),
45700
- nodeId: string().optional(),
45701
- patch: SettingsPatchSchema
45702
- }), SettingsUpdateResultSchema, {
45703
- kind: "mutation",
45704
- auth: "admin"
45705
- }), method(object({
45706
45581
  addonId: string(),
45707
45582
  cap: string(),
45708
45583
  scope: ScopedSettingsScopeSchema,
45709
45584
  nodeId: string().optional()
45710
45585
  }), SettingsSchemaWithValuesSchema.nullable()), method(object({
45586
+ addonId: string(),
45587
+ nodeId: string().optional()
45588
+ }), array(ScopedSettingsDeclarationSchema).nullable()), method(object({
45711
45589
  addonId: string(),
45712
45590
  cap: string(),
45713
45591
  scope: ScopedSettingsScopeSchema,
@@ -45722,9 +45600,6 @@ method(object({
45722
45600
  scope: ScopedSettingsScopeSchema,
45723
45601
  nodeId: string().optional()
45724
45602
  }), record(string(), unknown()).nullable()), method(object({
45725
- addonId: string(),
45726
- nodeId: string().optional()
45727
- }), SettingsSchemaWithValuesSchema.nullable()), method(object({
45728
45603
  addonId: string(),
45729
45604
  nodeId: string().optional(),
45730
45605
  instance: IntegrationInstanceRefSchema
@@ -47287,7 +47162,7 @@ var BackupDestinationInfoSchema = object({
47287
47162
  id: string(),
47288
47163
  /**
47289
47164
  * Manifest id of the owning addon. The Settings button on the
47290
- * destination card opens that addon's `globalSettingsSchema` panel.
47165
+ * destination card opens that addon's scoped settings panel.
47291
47166
  */
47292
47167
  addonId: string(),
47293
47168
  /** Operator-toggled enable flag from the destination-policy table. */
@@ -52764,6 +52639,7 @@ method(InstancePinSchema, DeviceExportStatusSchema), method(_void(), array(Expor
52764
52639
  kind: "mutation",
52765
52640
  auth: "admin"
52766
52641
  });
52642
+ var DeviceAliasSchema = string().max(64).regex(/^[a-z][a-z0-9_]*$/);
52767
52643
  /**
52768
52644
  * A SITE ZONE — a named part of the property that several locations belong to.
52769
52645
  *
@@ -53250,6 +53126,12 @@ var DeviceInfoSchema = object({
53250
53126
  addonId: string(),
53251
53127
  type: _enum(DeviceType),
53252
53128
  name: string(),
53129
+ /** The name a value template uses for this device (`{{ stufa_veranda.temperature }}`),
53130
+ * entity_id style. Generated once from the name at first registration, unique
53131
+ * cluster-wide, editable through `setAlias`, NOT changed by a rename (D1021).
53132
+ * Optional: a record produced by an older build omits it until the boot
53133
+ * backfill has run. */
53134
+ alias: DeviceAliasSchema.optional(),
53253
53135
  /** Operator-organisational location label. `null` when unset. */
53254
53136
  location: string().nullable(),
53255
53137
  /** Soft-disabled flag. */
@@ -53569,6 +53451,25 @@ method(object({
53569
53451
  }), _void(), {
53570
53452
  kind: "mutation",
53571
53453
  auth: "admin"
53454
+ }), method(object({
53455
+ deviceId: number$1(),
53456
+ alias: string()
53457
+ }), discriminatedUnion("ok", [object({
53458
+ ok: literal(true),
53459
+ alias: DeviceAliasSchema
53460
+ }), object({
53461
+ ok: literal(false),
53462
+ reason: _enum([
53463
+ "empty",
53464
+ "too-long",
53465
+ "grammar",
53466
+ "reserved",
53467
+ "taken"
53468
+ ]),
53469
+ takenBy: number$1().optional()
53470
+ })]), {
53471
+ kind: "mutation",
53472
+ auth: "admin"
53572
53473
  }), method(object({
53573
53474
  deviceId: number$1(),
53574
53475
  location: string().nullable()
@@ -67669,6 +67570,11 @@ var NcScheduleSchema = object({
67669
67570
  * as a STATE SUMMARY at the end of each window of `schedule`.
67670
67571
  */
67671
67572
  var NcSystemEventDeliveryModeSchema = _enum(["instant", "summary"]);
67573
+ _enum([
67574
+ "activation",
67575
+ "deactivation",
67576
+ "schedule"
67577
+ ]);
67672
67578
  /**
67673
67579
  * How a summary window is SENT (D698): `rule` (absent) = ONE notification with
67674
67580
  * every section; `section` = one notification per section with something to
@@ -67685,11 +67591,26 @@ var NcStateSummarySplitSchema = _enum(["rule", "section"]);
67685
67591
  * midnight crossing); the send time is each window's END. Refused on the
67686
67592
  * `alarm` family, which stays instant (`systemEventDeliveryProblems`).
67687
67593
  */
67688
- var NcSystemEventDeliverySchema = discriminatedUnion("mode", [object({ mode: literal("instant") }), object({
67689
- mode: literal("summary"),
67690
- schedule: NcScheduleSchema,
67691
- split: NcStateSummarySplitSchema.optional()
67692
- })]);
67594
+ var NcSystemEventDeliverySchema = discriminatedUnion("mode", [
67595
+ object({ mode: literal("instant") }),
67596
+ object({
67597
+ mode: literal("summary"),
67598
+ schedule: NcScheduleSchema,
67599
+ split: NcStateSummarySplitSchema.optional()
67600
+ }),
67601
+ object({
67602
+ mode: literal("modes"),
67603
+ /** The bad edge, and every kind that has a single edge. */
67604
+ onActivation: boolean(),
67605
+ /** The recovery edges of the classes of the selected kinds (derived, never stored per kind). */
67606
+ onDeactivation: boolean(),
67607
+ /** A state summary at the end of each window; absent = no summary. */
67608
+ onSchedule: object({
67609
+ schedule: NcScheduleSchema,
67610
+ grouping: NcStateSummarySplitSchema
67611
+ }).optional()
67612
+ })
67613
+ ]);
67693
67614
  /** Fuzzy plate matcher — OCR noise makes exact match useless (spec row 12/13). */
67694
67615
  var NcPlateMatcherSchema = object({
67695
67616
  /**
@@ -75780,93 +75701,27 @@ var RunningFlipEventDataSchema = object({
75780
75701
  phase: string().nullable()
75781
75702
  });
75782
75703
  var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
75783
- /** Generic Customize target for the running boolean (D936). */
75784
- var runningCustomize = {
75785
- version: 1,
75786
- overridable: [{
75787
- path: "running",
75788
- by: "running"
75789
- }],
75790
- targets: [{
75791
- id: "running",
75792
- cardinality: "scalar",
75793
- vocabulary: {
75794
- cap: "running-state",
75795
- stateField: "running"
75796
- },
75797
- deviceTypes: [
75798
- DeviceType.Washer,
75799
- DeviceType.Dryer,
75800
- DeviceType.Dishwasher,
75801
- DeviceType.Vacuum,
75802
- DeviceType.LawnMower,
75803
- DeviceType.MediaPlayer,
75804
- DeviceType.WaterHeater,
75805
- DeviceType.Humidifier,
75806
- DeviceType.Fan,
75807
- DeviceType.Climate,
75808
- DeviceType.Thermostat,
75809
- DeviceType.PetFeeder,
75810
- DeviceType.Heater
75811
- ],
75812
- apply: "add",
75813
- path: "running",
75814
- sources: [
75815
- {
75816
- kind: "switch",
75817
- transforms: [{ kind: "identity" }]
75818
- },
75819
- {
75820
- kind: "binary",
75821
- transforms: [{ kind: "identity" }, { kind: "invert" }]
75822
- },
75823
- {
75824
- kind: "numeric",
75825
- requiredUnit: "W",
75826
- transforms: [{
75827
- kind: "threshold",
75828
- comparisons: ["gte", "lte"],
75829
- comparison: "gte",
75830
- defaultThreshold: 5,
75831
- defaultStartDwellMs: RUNNING_POWER_START_DELAY_MS,
75832
- defaultStopDwellMs: RUNNING_POWER_STOP_DELAY_MS,
75833
- thresholdUnit: "W"
75834
- }]
75835
- }
75836
- ],
75837
- companions: [
75838
- {
75839
- kind: "constant",
75840
- path: "source",
75841
- value: "assigned",
75842
- when: "always"
75843
- },
75844
- {
75845
- kind: "constant",
75846
- path: "phase",
75847
- value: null,
75848
- when: "add"
75849
- },
75850
- {
75851
- kind: "clock",
75852
- path: "lastFetchedAt",
75853
- when: "always"
75854
- },
75855
- {
75856
- kind: "transition-time",
75857
- path: "since",
75858
- sourceChangedAt: "prefer"
75859
- }
75860
- ],
75861
- sourceReport: {
75862
- status: "assignment-status",
75863
- runtimeField: "source",
75864
- nativeValue: "native",
75865
- assignedValue: "assigned"
75866
- },
75867
- advancedExpression: true
75868
- }]
75869
- };
75704
+ /**
75705
+ * Customize offers "running" only where a job makes sense (D933): a cycle,
75706
+ * a clean, a mow, playback, or another appliance that is on and working.
75707
+ * The cap itself stays on every type — a camera can still report running
75708
+ * natively; it just has no card.
75709
+ */
75710
+ var RUNNING_CUSTOMIZE_DEVICE_TYPES = [
75711
+ DeviceType.Washer,
75712
+ DeviceType.Dryer,
75713
+ DeviceType.Dishwasher,
75714
+ DeviceType.Vacuum,
75715
+ DeviceType.LawnMower,
75716
+ DeviceType.MediaPlayer,
75717
+ DeviceType.WaterHeater,
75718
+ DeviceType.Humidifier,
75719
+ DeviceType.Fan,
75720
+ DeviceType.Climate,
75721
+ DeviceType.Thermostat,
75722
+ DeviceType.PetFeeder,
75723
+ DeviceType.Heater
75724
+ ];
75870
75725
  var runningStateCapability = {
75871
75726
  name: "running-state",
75872
75727
  scope: "device",
@@ -75886,7 +75741,78 @@ var runningStateCapability = {
75886
75741
  durability: "restored",
75887
75742
  history: { fields: { running: { kind: "boolean" } } },
75888
75743
  volatileStateFields: ["lastFetchedAt"],
75889
- customize: runningCustomize
75744
+ customize: {
75745
+ version: 1,
75746
+ overridable: [{
75747
+ path: "running",
75748
+ by: "running"
75749
+ }],
75750
+ targets: [{
75751
+ id: "running",
75752
+ cardinality: "scalar",
75753
+ vocabulary: {
75754
+ cap: "running-state",
75755
+ stateField: "running"
75756
+ },
75757
+ deviceTypes: RUNNING_CUSTOMIZE_DEVICE_TYPES,
75758
+ apply: "add",
75759
+ path: "running",
75760
+ sources: [
75761
+ {
75762
+ kind: "switch",
75763
+ transforms: [{ kind: "identity" }]
75764
+ },
75765
+ {
75766
+ kind: "binary",
75767
+ transforms: [{ kind: "identity" }, { kind: "invert" }]
75768
+ },
75769
+ {
75770
+ kind: "numeric",
75771
+ requiredUnit: "W",
75772
+ transforms: [{
75773
+ kind: "threshold",
75774
+ comparisons: ["gte", "lte"],
75775
+ comparison: "gte",
75776
+ defaultThreshold: 5,
75777
+ defaultStartDwellMs: RUNNING_POWER_START_DELAY_MS,
75778
+ defaultStopDwellMs: RUNNING_POWER_STOP_DELAY_MS,
75779
+ thresholdUnit: "W"
75780
+ }]
75781
+ }
75782
+ ],
75783
+ companions: [
75784
+ {
75785
+ kind: "constant",
75786
+ path: "source",
75787
+ value: "assigned",
75788
+ when: "always"
75789
+ },
75790
+ {
75791
+ kind: "constant",
75792
+ path: "phase",
75793
+ value: null,
75794
+ when: "add"
75795
+ },
75796
+ {
75797
+ kind: "clock",
75798
+ path: "lastFetchedAt",
75799
+ when: "always"
75800
+ },
75801
+ {
75802
+ kind: "transition-time",
75803
+ path: "since",
75804
+ sourceChangedAt: "prefer"
75805
+ }
75806
+ ],
75807
+ sourceReport: {
75808
+ status: "assignment-status",
75809
+ runtimeField: "source",
75810
+ nativeValue: "native",
75811
+ assignedValue: "assigned"
75812
+ },
75813
+ advancedExpression: true
75814
+ }]
75815
+ }
75890
75816
  };
75891
75817
  /**
75892
75818
  * scene-monitor — device-scoped reference-region state cap. An operator marks
@@ -78820,6 +78746,11 @@ var TimedRunUnitSchema = _enum(["s", "min"]);
78820
78746
  _enum(["switch", "pet-fountain"]);
78821
78747
  DeviceType.Heater, DeviceType.PetFountain;
78822
78748
  var TIMED_RUN_DEVICE_TYPES = [DeviceType.Heater, DeviceType.PetFountain];
78749
+ /** One duration, as the one-tap run asks for it. */
78750
+ var TimedRunQuickRunSchema = object({
78751
+ duration: number$1().positive().finite(),
78752
+ unit: TimedRunUnitSchema
78753
+ });
78823
78754
  /** Why a request was not carried out. Typed, so a caller can say it in words. */
78824
78755
  var TimedRunRefusalSchema = _enum([
78825
78756
  "unsupported-device",
@@ -78840,8 +78771,23 @@ var TimedRunStatusSchema = object({
78840
78771
  activeUntil: number$1().nullable(),
78841
78772
  /** Who asked for the run (a user id or an addon id); `null` when nothing is armed or it did not say. */
78842
78773
  requestedBy: string().nullable(),
78774
+ /**
78775
+ * The one-tap run of THIS device: what a "Run" button on any surface starts. `null` when
78776
+ * the device is gone or its type has no timed run; a status from before this field
78777
+ * existed has none, and a surface falls back to the type's default.
78778
+ */
78779
+ quickRun: TimedRunQuickRunSchema.nullable(),
78843
78780
  lastFetchedAt: number$1()
78844
78781
  });
78782
+ /** What the settings form needs: the unit, the bounds and the type's default. */
78783
+ var TimedRunOptionsSchema = object({
78784
+ unit: TimedRunUnitSchema,
78785
+ /** The longest run, in `unit`. */
78786
+ maxDuration: number$1(),
78787
+ defaultDuration: number$1()
78788
+ });
78789
+ /** The one-tap run duration, in the type's unit; `null` returns to the type's default. */
78790
+ var TimedRunSettingsPatchSchema = object({ quickRunDuration: number$1().positive().finite().nullable().optional() });
78845
78791
  var timedRunCapability = {
78846
78792
  name: "timed-run",
78847
78793
  scope: "device",
@@ -78849,7 +78795,24 @@ var timedRunCapability = {
78849
78795
  kind: "wrapper",
78850
78796
  defaultActive: true,
78851
78797
  deviceTypes: TIMED_RUN_DEVICE_TYPES,
78798
+ deviceConfig: { ui: {
78799
+ kind: "derived-form",
78800
+ builderId: "timed-run",
78801
+ tab: "general"
78802
+ } },
78852
78803
  methods: {
78804
+ getOptions: method(object({ deviceId: number$1().int() }), TimedRunOptionsSchema),
78805
+ /**
78806
+ * The one-tap run of this device. A duration above the type's maximum is
78807
+ * REFUSED (thrown), like `runFor`: the maximum is a safety bound.
78808
+ */
78809
+ setSettings: method(object({
78810
+ deviceId: number$1().int(),
78811
+ settings: TimedRunSettingsPatchSchema
78812
+ }), _void(), {
78813
+ kind: "mutation",
78814
+ auth: "admin"
78815
+ }),
78853
78816
  /**
78854
78817
  * Turn the device on and arm its off. A run already armed is replaced (the
78855
78818
  * new deadline wins). Refuses with a typed reason above the type's maximum.
@@ -83550,13 +83513,6 @@ Object.freeze({
83550
83513
  access: "view",
83551
83514
  role: "admin"
83552
83515
  },
83553
- "addonSettings.getGlobalSettings": {
83554
- capName: "addon-settings",
83555
- capScope: "system",
83556
- addonId: null,
83557
- access: "view",
83558
- role: "admin"
83559
- },
83560
83516
  "addonSettings.getIntegrationFormSchema": {
83561
83517
  capName: "addon-settings",
83562
83518
  capScope: "system",
@@ -83564,14 +83520,14 @@ Object.freeze({
83564
83520
  access: "view",
83565
83521
  role: "admin"
83566
83522
  },
83567
- "addonSettings.getIntegrationSettings": {
83523
+ "addonSettings.getScopedSettings": {
83568
83524
  capName: "addon-settings",
83569
83525
  capScope: "system",
83570
83526
  addonId: null,
83571
83527
  access: "view",
83572
83528
  role: "admin"
83573
83529
  },
83574
- "addonSettings.getScopedSettings": {
83530
+ "addonSettings.listScopedSettings": {
83575
83531
  capName: "addon-settings",
83576
83532
  capScope: "system",
83577
83533
  addonId: null,
@@ -83599,13 +83555,6 @@ Object.freeze({
83599
83555
  access: "create",
83600
83556
  role: "admin"
83601
83557
  },
83602
- "addonSettings.updateGlobalSettings": {
83603
- capName: "addon-settings",
83604
- capScope: "system",
83605
- addonId: null,
83606
- access: "create",
83607
- role: "admin"
83608
- },
83609
83558
  "addonSettings.updateScopedSettings": {
83610
83559
  capName: "addon-settings",
83611
83560
  capScope: "system",
@@ -85776,6 +85725,13 @@ Object.freeze({
85776
85725
  access: "create",
85777
85726
  role: "admin"
85778
85727
  },
85728
+ "deviceManager.setAlias": {
85729
+ capName: "device-manager",
85730
+ capScope: "system",
85731
+ addonId: null,
85732
+ access: "create",
85733
+ role: "admin"
85734
+ },
85779
85735
  "deviceManager.setChildLayout": {
85780
85736
  capName: "device-manager",
85781
85737
  capScope: "system",
@@ -92559,6 +92515,13 @@ Object.freeze({
92559
92515
  access: "create",
92560
92516
  role: "viewer"
92561
92517
  },
92518
+ "timedRun.getOptions": {
92519
+ capName: "timed-run",
92520
+ capScope: "device",
92521
+ addonId: null,
92522
+ access: "view",
92523
+ role: "viewer"
92524
+ },
92562
92525
  "timedRun.getStatus": {
92563
92526
  capName: "timed-run",
92564
92527
  capScope: "device",
@@ -92573,6 +92536,13 @@ Object.freeze({
92573
92536
  access: "create",
92574
92537
  role: "viewer"
92575
92538
  },
92539
+ "timedRun.setSettings": {
92540
+ capName: "timed-run",
92541
+ capScope: "device",
92542
+ addonId: null,
92543
+ access: "create",
92544
+ role: "admin"
92545
+ },
92576
92546
  "toast.onToast": {
92577
92547
  capName: "toast",
92578
92548
  capScope: "system",
@@ -93503,6 +93473,7 @@ function offered(received) {
93503
93473
  };
93504
93474
  }
93505
93475
  offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
93476
+ string().min(1).max(4096);
93506
93477
  Object.freeze({
93507
93478
  "accessories.getStatus": [{
93508
93479
  name: "deviceId",
@@ -94186,6 +94157,11 @@ Object.freeze({
94186
94157
  form: "single",
94187
94158
  optional: false
94188
94159
  }],
94160
+ "deviceManager.setAlias": [{
94161
+ name: "deviceId",
94162
+ form: "single",
94163
+ optional: false
94164
+ }],
94189
94165
  "deviceManager.setChildLayout": [{
94190
94166
  name: "deviceId",
94191
94167
  form: "single",
@@ -96250,6 +96226,11 @@ Object.freeze({
96250
96226
  form: "single",
96251
96227
  optional: false
96252
96228
  }],
96229
+ "timedRun.getOptions": [{
96230
+ name: "deviceId",
96231
+ form: "single",
96232
+ optional: false
96233
+ }],
96253
96234
  "timedRun.getStatus": [{
96254
96235
  name: "deviceId",
96255
96236
  form: "single",
@@ -96260,6 +96241,11 @@ Object.freeze({
96260
96241
  form: "single",
96261
96242
  optional: false
96262
96243
  }],
96244
+ "timedRun.setSettings": [{
96245
+ name: "deviceId",
96246
+ form: "single",
96247
+ optional: false
96248
+ }],
96263
96249
  "update.getStatus": [{
96264
96250
  name: "deviceId",
96265
96251
  form: "single",
@@ -97329,6 +97315,7 @@ var STATE_SUMMARY_VARS = [
97329
97315
  [...RULE_TEXT],
97330
97316
  [...RULE_TEXT],
97331
97317
  [...RULE_TEXT],
97318
+ [...RULE_TEXT],
97332
97319
  [...RULE_BODY_ONLY],
97333
97320
  [...RULE_TEXT],
97334
97321
  ([...RULE_TEXT], [...DEVICE_EVENTS]),