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