@camstack/addon-smtp-nodemailer 1.2.151 → 1.2.153
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/CHANGELOG.md +12 -0
- package/dist/smtp.addon.js +913 -1049
- package/dist/smtp.addon.mjs +913 -1049
- package/package.json +2 -2
package/dist/smtp.addon.js
CHANGED
|
@@ -38,7 +38,7 @@ var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["modu
|
|
|
38
38
|
//#endregion
|
|
39
39
|
let node_crypto = require("node:crypto");
|
|
40
40
|
let node_net = require("node:net");
|
|
41
|
-
//#region ../types/dist/event-category-
|
|
41
|
+
//#region ../types/dist/event-category-78tcBemo.mjs
|
|
42
42
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
43
43
|
EventCategory["SystemBoot"] = "system.boot";
|
|
44
44
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -159,6 +159,23 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
159
159
|
*/
|
|
160
160
|
EventCategory["AddonLoadRecovered"] = "addon.load-recovered";
|
|
161
161
|
/**
|
|
162
|
+
* An addon is RUNNING although its installed package is below what the
|
|
163
|
+
* running server requires (`camstack.requires.addons` of the server, or the
|
|
164
|
+
* addon's own `requires.server`). Raised once per streak by the unsupported-
|
|
165
|
+
* addon tracker, on the hub and on agents; AlertCenter turns it into one
|
|
166
|
+
* operator alert per node and package. The addon is never held back for it.
|
|
167
|
+
*
|
|
168
|
+
* Payload: `{ packageName, addonId, nodeId, installedVersion, requiredMinimum, serverVersion, unmet }`.
|
|
169
|
+
*/
|
|
170
|
+
EventCategory["AddonUnsupportedVersion"] = "addon.unsupported-version";
|
|
171
|
+
/**
|
|
172
|
+
* The package of an {@link AddonUnsupportedVersion} alert reached a supported
|
|
173
|
+
* version, or is no longer installed on the node. AlertCenter dismisses the matching alert.
|
|
174
|
+
*
|
|
175
|
+
* Payload: `{ packageName, addonId, nodeId }`.
|
|
176
|
+
*/
|
|
177
|
+
EventCategory["AddonUnsupportedResolved"] = "addon.unsupported-resolved";
|
|
178
|
+
/**
|
|
162
179
|
* Monitor scheduled the next retry for a failed addon. Transient —
|
|
163
180
|
* surfaced to the UI for live-updating the "next retry in Ns"
|
|
164
181
|
* countdown on the Addons page row, NOT persisted as an alert.
|
|
@@ -269,7 +286,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
269
286
|
EventCategory["ProcessRestarted"] = "process.restarted";
|
|
270
287
|
/**
|
|
271
288
|
* The SET of storage locations changed — one was created, edited, enabled,
|
|
272
|
-
* disabled or deleted through
|
|
289
|
+
* disabled or deleted through the location instances or the forced-delete action.
|
|
273
290
|
*
|
|
274
291
|
* Telemetry, not a transaction (D8/D11): every consumer that re-resolves on
|
|
275
292
|
* it must also converge on its own periodic path, because a dropped event
|
|
@@ -824,7 +841,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
824
841
|
return EventCategory;
|
|
825
842
|
}({});
|
|
826
843
|
//#endregion
|
|
827
|
-
//#region ../types/dist/device-type-
|
|
844
|
+
//#region ../types/dist/device-type-DxCT0krO.mjs
|
|
828
845
|
/**
|
|
829
846
|
import { errMsg } from '@camstack/types'
|
|
830
847
|
* Extract a human-readable message from an unknown error value.
|
|
@@ -986,6 +1003,13 @@ var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
|
986
1003
|
* filters that want "all devices with on-motion behaviour".
|
|
987
1004
|
*/
|
|
988
1005
|
DeviceFeature["MotionTrigger"] = "motion-trigger";
|
|
1006
|
+
/**
|
|
1007
|
+
* Device can be run for a chosen time and then stopped. Mirrors the
|
|
1008
|
+
* `timed-run` wrapper cap — the cap is bound by the core-blocks addon, not by
|
|
1009
|
+
* a driver, so the flag is derived from the device's bindings
|
|
1010
|
+
* (`featuresOfBoundCaps`). Gates the quick-run control in the viewer.
|
|
1011
|
+
*/
|
|
1012
|
+
DeviceFeature["TimedRun"] = "timed-run";
|
|
989
1013
|
/** Light supports rgb-triplet color via `color` cap. */
|
|
990
1014
|
DeviceFeature["LightColorRgb"] = "light-color-rgb";
|
|
991
1015
|
/** Light supports HSV color via `color` cap. */
|
|
@@ -6020,7 +6044,7 @@ var ZodIssueCode = {
|
|
|
6020
6044
|
var ZodFirstPartyTypeKind;
|
|
6021
6045
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
6022
6046
|
//#endregion
|
|
6023
|
-
//#region ../types/dist/sleep-
|
|
6047
|
+
//#region ../types/dist/sleep-7El4r5Bl.mjs
|
|
6024
6048
|
/**
|
|
6025
6049
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6026
6050
|
* window to float samples (D455).
|
|
@@ -6384,6 +6408,59 @@ Object.fromEntries([
|
|
|
6384
6408
|
function isValuelessField(field) {
|
|
6385
6409
|
return field.type === "separator" || field.type === "info" || field.type === "qr-code" || field.type === "button" || field.type === "object-array" || field.type === "widget" || field.type === "addon-action-button" || field.type === "device-action-button" || field.type === "account-sign-in" || field.type === "secret-presence";
|
|
6386
6410
|
}
|
|
6411
|
+
/**
|
|
6412
|
+
* Base collector: flatten a hydrated `ConfigUISchemaWithValues` into
|
|
6413
|
+
* `key → { value, default }`, recursing through `group` and `sub-tabs`
|
|
6414
|
+
* layout fields. Keeping `value` and `default` SEPARATE (rather than
|
|
6415
|
+
* pre-resolving) lets callers both read the effective value AND detect
|
|
6416
|
+
* overrides (`value` differs from `default`). Structural over `unknown`;
|
|
6417
|
+
* malformed input yields an empty map, never throws.
|
|
6418
|
+
*/
|
|
6419
|
+
function collectHydratedFieldEntries(schema) {
|
|
6420
|
+
const out = /* @__PURE__ */ new Map();
|
|
6421
|
+
if (typeof schema !== "object" || schema === null) return out;
|
|
6422
|
+
const sections = schema.sections;
|
|
6423
|
+
if (!Array.isArray(sections)) return out;
|
|
6424
|
+
for (const section of sections) if (typeof section === "object" && section !== null) collectFieldEntriesInto(section.fields, out);
|
|
6425
|
+
return out;
|
|
6426
|
+
}
|
|
6427
|
+
/** Recursive field walker for {@link collectHydratedFieldEntries}. */
|
|
6428
|
+
function collectFieldEntriesInto(fields, into) {
|
|
6429
|
+
if (!Array.isArray(fields)) return;
|
|
6430
|
+
for (const field of fields) {
|
|
6431
|
+
if (typeof field !== "object" || field === null) continue;
|
|
6432
|
+
const type = field.type;
|
|
6433
|
+
if (type === "group") {
|
|
6434
|
+
collectFieldEntriesInto(field.fields, into);
|
|
6435
|
+
continue;
|
|
6436
|
+
}
|
|
6437
|
+
if (type === "sub-tabs") {
|
|
6438
|
+
const tabs = field.tabs;
|
|
6439
|
+
if (Array.isArray(tabs)) {
|
|
6440
|
+
for (const tab of tabs) if (typeof tab === "object" && tab !== null) collectFieldEntriesInto(tab.fields, into);
|
|
6441
|
+
}
|
|
6442
|
+
continue;
|
|
6443
|
+
}
|
|
6444
|
+
const key = field.key;
|
|
6445
|
+
if (typeof key !== "string" || key.length === 0) continue;
|
|
6446
|
+
if (!("value" in field)) continue;
|
|
6447
|
+
into.set(key, {
|
|
6448
|
+
value: field.value,
|
|
6449
|
+
default: field.default
|
|
6450
|
+
});
|
|
6451
|
+
}
|
|
6452
|
+
}
|
|
6453
|
+
/**
|
|
6454
|
+
* Flatten a hydrated settings payload into `key → EFFECTIVE value`
|
|
6455
|
+
* (`value ?? default`). The read-side inverse of `hydrateSchema` for the
|
|
6456
|
+
* common "just give me the resolved values" case. Built on
|
|
6457
|
+
* {@link collectHydratedFieldEntries}.
|
|
6458
|
+
*/
|
|
6459
|
+
function collectHydratedFieldValues(schema) {
|
|
6460
|
+
const out = /* @__PURE__ */ new Map();
|
|
6461
|
+
for (const [key, entry] of collectHydratedFieldEntries(schema)) out.set(key, entry.value ?? entry.default);
|
|
6462
|
+
return out;
|
|
6463
|
+
}
|
|
6387
6464
|
function hydrateSchema(schema, values, options = {}) {
|
|
6388
6465
|
return {
|
|
6389
6466
|
...schema.tabs ? { tabs: [...schema.tabs] } : {},
|
|
@@ -7268,17 +7345,35 @@ var RecordIntegrationInstances = class {
|
|
|
7268
7345
|
...kind !== void 0 ? { kind } : {}
|
|
7269
7346
|
});
|
|
7270
7347
|
if (minted === void 0) throw new Error("createInstance needs an id: this provider does not mint one");
|
|
7348
|
+
const initial = this.hooks.initialBody(name, kind);
|
|
7349
|
+
const patch = this.patchOf(values ?? {});
|
|
7350
|
+
if (Object.keys(patch).length > 0) Object.assign(patch, await this.hooks.validateWrite?.({
|
|
7351
|
+
kind,
|
|
7352
|
+
body: {
|
|
7353
|
+
...initial,
|
|
7354
|
+
...patch
|
|
7355
|
+
}
|
|
7356
|
+
}));
|
|
7271
7357
|
await this.handle.put({
|
|
7272
7358
|
id: minted,
|
|
7273
|
-
data:
|
|
7359
|
+
data: initial
|
|
7274
7360
|
}, { ifRev: 0 });
|
|
7275
|
-
const patch = this.patchOf(values ?? {});
|
|
7276
7361
|
if (Object.keys(patch).length > 0) await this.handle.patch(minted, patch);
|
|
7277
7362
|
await this.hooks.onChanged?.(minted, "created");
|
|
7278
7363
|
return { id: minted };
|
|
7279
7364
|
};
|
|
7280
7365
|
updateInstance = async ({ id, name, values }) => {
|
|
7281
7366
|
const patch = this.patchOf(values);
|
|
7367
|
+
if (this.hooks.validateWrite !== void 0 && Object.keys(patch).length > 0) {
|
|
7368
|
+
const stored = await this.handle.get(id);
|
|
7369
|
+
if (stored !== null) Object.assign(patch, await this.hooks.validateWrite({
|
|
7370
|
+
kind: void 0,
|
|
7371
|
+
body: {
|
|
7372
|
+
...stored.data,
|
|
7373
|
+
...patch
|
|
7374
|
+
}
|
|
7375
|
+
}));
|
|
7376
|
+
}
|
|
7282
7377
|
if (name !== void 0) patch[this.nameField] = name;
|
|
7283
7378
|
await this.handle.patch(id, patch);
|
|
7284
7379
|
await this.hooks.onChanged?.(id, "updated");
|
|
@@ -7589,6 +7684,21 @@ var SCOPED_SETTINGS_SCOPES = [
|
|
|
7589
7684
|
"device-defaults",
|
|
7590
7685
|
"node"
|
|
7591
7686
|
];
|
|
7687
|
+
/** The one refusal of a key a scope did not declare. */
|
|
7688
|
+
function assertDeclaredKeys(keys, declared) {
|
|
7689
|
+
const undeclared = keys.filter((key) => !declared.has(key));
|
|
7690
|
+
if (undeclared.length > 0) throw new Error(`scoped settings: [${undeclared.join(", ")}] not declared for this scope (declared: [${[...declared].join(", ")}])`);
|
|
7691
|
+
}
|
|
7692
|
+
/** Build the handle over an addon's scoped read, write and unset. */
|
|
7693
|
+
function createScopedSettings(deps) {
|
|
7694
|
+
return {
|
|
7695
|
+
async get() {
|
|
7696
|
+
return deps.schema.parse(await deps.read());
|
|
7697
|
+
},
|
|
7698
|
+
patch: (patch) => deps.write(Object.fromEntries(Object.entries(patch))),
|
|
7699
|
+
unset: (keys) => deps.unset(keys)
|
|
7700
|
+
};
|
|
7701
|
+
}
|
|
7592
7702
|
/** A write to a secret path could not be stored in the keychain, so it was refused. */
|
|
7593
7703
|
var KeychainWriteRefusedError = class extends Error {
|
|
7594
7704
|
fieldPath;
|
|
@@ -8164,7 +8274,16 @@ function createHandle(raw, opts) {
|
|
|
8164
8274
|
return blob;
|
|
8165
8275
|
}
|
|
8166
8276
|
},
|
|
8167
|
-
writeAddonStore: writeAddon
|
|
8277
|
+
writeAddonStore: writeAddon,
|
|
8278
|
+
removeClearedKeys: (keys) => serialize("addon", async () => {
|
|
8279
|
+
const stored = await readStoredAddonBlob(raw);
|
|
8280
|
+
index.seen("addon", stored);
|
|
8281
|
+
const removable = keys.filter((key) => collectSecretMarkerRefs(stored[key]).length === 0);
|
|
8282
|
+
if (removable.length === 0) return;
|
|
8283
|
+
const patch = Object.fromEntries(removable.map((key) => [key, void 0]));
|
|
8284
|
+
await raw.writeAddonStore(patch);
|
|
8285
|
+
index.wrote("addon", patch);
|
|
8286
|
+
})
|
|
8168
8287
|
};
|
|
8169
8288
|
}
|
|
8170
8289
|
/** The context the addon sees, plus the private raw view and write outcome. */
|
|
@@ -8294,7 +8413,7 @@ function boundOf(list) {
|
|
|
8294
8413
|
* Base class for CamStack addons. Eliminates settings boilerplate:
|
|
8295
8414
|
*
|
|
8296
8415
|
* - Typed `config` property with automatic resolution from store + defaults
|
|
8297
|
-
* -
|
|
8416
|
+
* - the scoped settings API (`clusterSettings` / `nodeSettings` / `deviceDefaults`) auto-implemented
|
|
8298
8417
|
* - `getAddonSettings()` / `updateAddonSettings()` auto-implemented
|
|
8299
8418
|
* - `getDeviceSettings()` / `updateDeviceSettings()` auto-implemented
|
|
8300
8419
|
* - `ctx` accessor for the AddonContext (no manual `this.ctxRef` storage)
|
|
@@ -8304,7 +8423,7 @@ function boundOf(list) {
|
|
|
8304
8423
|
* Subclasses override:
|
|
8305
8424
|
* - `onInitialize()` — addon-specific init logic, return ProviderRegistration[]
|
|
8306
8425
|
* - `onShutdown()` — cleanup
|
|
8307
|
-
* - `
|
|
8426
|
+
* - `clusterSettingsSchema()` / `nodeSettingsSchema()` / `deviceSettingsSchema()` — UI schemas
|
|
8308
8427
|
*
|
|
8309
8428
|
* @example
|
|
8310
8429
|
* ```ts
|
|
@@ -8318,7 +8437,7 @@ function boundOf(list) {
|
|
|
8318
8437
|
* super({ maxRetries: 3, endpoint: 'http://localhost' })
|
|
8319
8438
|
* }
|
|
8320
8439
|
*
|
|
8321
|
-
* protected
|
|
8440
|
+
* protected clusterSettingsSchema() {
|
|
8322
8441
|
* return this.schema({
|
|
8323
8442
|
* sections: [{
|
|
8324
8443
|
* id: 'main', title: 'Settings',
|
|
@@ -8361,7 +8480,7 @@ var BaseAddon = class {
|
|
|
8361
8480
|
defaults;
|
|
8362
8481
|
/**
|
|
8363
8482
|
* Hidden-state paths that hold secrets (D787) — values the addon writes
|
|
8364
|
-
* itself (`
|
|
8483
|
+
* itself (`state()`, the scoped writers) that no form field declares.
|
|
8365
8484
|
* Stored in the keychain exactly like a `password` field. Syntax:
|
|
8366
8485
|
* `'snapshotSigningKey'`, `'identity.pincode'`, `'tokens[userId].accessToken'`
|
|
8367
8486
|
* (`key[<id field>]` addresses array items by id, never by index).
|
|
@@ -8371,7 +8490,7 @@ var BaseAddon = class {
|
|
|
8371
8490
|
/**
|
|
8372
8491
|
* D986 M4: the scoped schemas this addon declared, resolved once per capability
|
|
8373
8492
|
* (`loadScopedSchemas`) so the sync readers (`perNodeKeys`, the secret tree, the restart check)
|
|
8374
|
-
* see them. Empty until loaded
|
|
8493
|
+
* see them. Empty until loaded.
|
|
8375
8494
|
*/
|
|
8376
8495
|
_scopedByCap = /* @__PURE__ */ new Map();
|
|
8377
8496
|
_nodeKeysByCap = /* @__PURE__ */ new Map();
|
|
@@ -8557,7 +8676,7 @@ var BaseAddon = class {
|
|
|
8557
8676
|
/** Addon-specific cleanup. Override if needed. */
|
|
8558
8677
|
async onShutdown() {}
|
|
8559
8678
|
/**
|
|
8560
|
-
* Called after config is resolved during
|
|
8679
|
+
* Called after config is resolved during a settings write.
|
|
8561
8680
|
* Override to react to config changes (e.g. restart a sampler, reconnect a service).
|
|
8562
8681
|
* Not called during initialize() — use onInitialize() for initial setup.
|
|
8563
8682
|
*/
|
|
@@ -8586,82 +8705,12 @@ var BaseAddon = class {
|
|
|
8586
8705
|
scopedSettingsCapabilities() {
|
|
8587
8706
|
return [];
|
|
8588
8707
|
}
|
|
8589
|
-
/** Override to provide global-level settings UI schema. */
|
|
8590
|
-
globalSettingsSchema(_cap) {
|
|
8591
|
-
return null;
|
|
8592
|
-
}
|
|
8593
8708
|
/** Override to provide device-level settings UI schema. */
|
|
8594
8709
|
deviceSettingsSchema() {
|
|
8595
8710
|
return null;
|
|
8596
8711
|
}
|
|
8597
8712
|
/**
|
|
8598
|
-
*
|
|
8599
|
-
* ARE the configuration of its integration.
|
|
8600
|
-
*
|
|
8601
|
-
* Return the `ConfigSection.id`s, from {@link globalSettingsSchema}, that an
|
|
8602
|
-
* operator should find on the addon's integration page (System →
|
|
8603
|
-
* Integrations → <name>) rather than only in the cluster-wide list of every
|
|
8604
|
-
* addon. Empty (the default) means the addon has no integration-level
|
|
8605
|
-
* settings and no such surface is offered — this is opt-in, because whether
|
|
8606
|
-
* an addon's configuration IS its integration's configuration depends on the
|
|
8607
|
-
* nature of the integration.
|
|
8608
|
-
*
|
|
8609
|
-
* WHAT THIS IS NOT. It is not a scope. The selected sections keep living in
|
|
8610
|
-
* the ONE global schema, in the ONE addon store, written by the ONE
|
|
8611
|
-
* `updateGlobalSettings` path. There is deliberately no
|
|
8612
|
-
* `updateIntegrationSettings`: a second write path is how a surface acquires
|
|
8613
|
-
* a second store key, and this repo has shipped that twice (`btmPath@hub`,
|
|
8614
|
-
* D266). Selecting sections cannot introduce a key that selecting cannot.
|
|
8615
|
-
*
|
|
8616
|
-
* WHY IT IS A LIST OF SECTION IDS AND NOT A MARKER ON THE SECTION.
|
|
8617
|
-
* `ConfigFieldBase` used to carry `scope?: 'device' | 'global'` and it was
|
|
8618
|
-
* removed with the reason recorded at
|
|
8619
|
-
* `packages/types/src/interfaces/config-ui.ts:249` — *"a field's scope is
|
|
8620
|
-
* determined by WHICH schema it lives in, not by a field-level marker."* A
|
|
8621
|
-
* marker sprinkled across sections also has to borrow a field that already
|
|
8622
|
-
* means something else; borrowing `section.tab` put the literal word
|
|
8623
|
-
* "integration" into an operator-facing tab bar, because `tab` means "how to
|
|
8624
|
-
* GROUP this visually" and cannot also mean "where this lives" (D269
|
|
8625
|
-
* supersedes D268). One declaration, in one place, next to the schema whose
|
|
8626
|
-
* ids it names.
|
|
8627
|
-
*/
|
|
8628
|
-
integrationSettingSections() {
|
|
8629
|
-
return [];
|
|
8630
|
-
}
|
|
8631
|
-
async getGlobalSettings(overlay, cap, nodeId) {
|
|
8632
|
-
await this.loadScopedSchemas(cap);
|
|
8633
|
-
const schema = this.globalSettingsSchema(cap) ?? this.scopedFormSchema(cap);
|
|
8634
|
-
if (!schema) return { sections: [] };
|
|
8635
|
-
const projected = await this.readRawProjectedStore(nodeId, cap);
|
|
8636
|
-
return hydrateSchema(schema, overlay ? await this.overlayKeepingMarkers(projected, overlay) : projected, { inlineSecretsAsViews: true });
|
|
8637
|
-
}
|
|
8638
|
-
/**
|
|
8639
|
-
* The integration-level view of this addon's settings: exactly the sections
|
|
8640
|
-
* named by {@link integrationSettingSections}, hydrated from the SAME store
|
|
8641
|
-
* `getGlobalSettings` reads, and narrowed to cluster-scoped fields.
|
|
8642
|
-
*
|
|
8643
|
-
* Returns `null` when the addon declared nothing — an addon that opts out has
|
|
8644
|
-
* no integration settings surface at all, rather than an empty one that reads
|
|
8645
|
-
* as a failed load.
|
|
8646
|
-
*
|
|
8647
|
-
* Three properties hold BY CONSTRUCTION, which is why they are here in core
|
|
8648
|
-
* and not in whichever UI happens to render this:
|
|
8649
|
-
*
|
|
8650
|
-
* 1. **One key.** The payload is a SUBSET of the global schema, so a field
|
|
8651
|
-
* shown here is the same field, with the same bare key, that the addon's
|
|
8652
|
-
* own page shows. There is no integration-specific writer — callers save
|
|
8653
|
-
* through `updateGlobalSettings` — so a second store key is unreachable,
|
|
8654
|
-
* not merely discouraged.
|
|
8655
|
-
* 2. **No node scope.** `perNode: true` fields are DROPPED. Their store key
|
|
8656
|
-
* is `<key>@<nodeId>` and an integration is not a node; whichever node
|
|
8657
|
-
* such a field silently picked would be a wrong answer for the operator
|
|
8658
|
-
* who opened the page (D266).
|
|
8659
|
-
* 3. **No silent typo.** A declared id that names no section throws. The
|
|
8660
|
-
* alternative — skip it — turns a rename into a surface that quietly
|
|
8661
|
-
* empties, which looks exactly like an addon with nothing to configure.
|
|
8662
|
-
*/
|
|
8663
|
-
/**
|
|
8664
|
-
* The form schema of ONE integration instance, or `null` to use {@link globalSettingsSchema}.
|
|
8713
|
+
* The form schema of ONE integration instance, or `null` to use the scoped form.
|
|
8665
8714
|
*
|
|
8666
8715
|
* Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
|
|
8667
8716
|
* needs its connection fields, the default integration the addon's own sections. It is the
|
|
@@ -8709,37 +8758,178 @@ var BaseAddon = class {
|
|
|
8709
8758
|
}
|
|
8710
8759
|
}
|
|
8711
8760
|
/**
|
|
8761
|
+
* Hook: values layered over the stored ones when the FORM of one scope is served
|
|
8762
|
+
* ({@link getScopedSettings}) — a preview that derives dependent options without writing.
|
|
8763
|
+
* Never applied to {@link ScopedSettings.get} or to a write. `null` ⇒ no overlay.
|
|
8764
|
+
*/
|
|
8765
|
+
async scopedSettingsOverlay(_scope, _cap, _nodeId) {
|
|
8766
|
+
return null;
|
|
8767
|
+
}
|
|
8768
|
+
/**
|
|
8769
|
+
* Hook: a write of one scope changed stored values (not called when the store reports no change,
|
|
8770
|
+
* e.g. the write-back of a stored secret). `keys` are the bare field keys of the write, node keys included.
|
|
8771
|
+
*/
|
|
8772
|
+
async onScopedSettingsChanged(_scope, _cap, _keys) {}
|
|
8773
|
+
/** Typed handle over the CLUSTER settings `cap` declares (`clusterSettingsSchema`). */
|
|
8774
|
+
clusterSettings(cap, schema) {
|
|
8775
|
+
return this.scopedHandle("cluster", cap, schema);
|
|
8776
|
+
}
|
|
8777
|
+
/** Typed handle over the fleet defaults of the per-device settings `cap` declares. */
|
|
8778
|
+
deviceDefaults(cap, schema) {
|
|
8779
|
+
return this.scopedHandle("device-defaults", cap, schema);
|
|
8780
|
+
}
|
|
8781
|
+
/**
|
|
8782
|
+
* Typed handle over the settings `cap` owns PER NODE. `nodeId` omitted ⇒ the local node. A node
|
|
8783
|
+
* with no row yields the schema defaults — never a bare-key fallback.
|
|
8784
|
+
*/
|
|
8785
|
+
nodeSettings(cap, schema, nodeId) {
|
|
8786
|
+
return this.scopedHandle("node", cap, schema, nodeId);
|
|
8787
|
+
}
|
|
8788
|
+
/**
|
|
8789
|
+
* {@link state} for a value that is kept per node: stored under `<key>@<nodeId>`, and the
|
|
8790
|
+
* settings store carries `nodeId` in the row data (D986 §1), so a forgotten node's rows go in one
|
|
8791
|
+
* central delete. `nodeId` omitted ⇒ the local node.
|
|
8792
|
+
*/
|
|
8793
|
+
nodeState(key, schema, fallback, nodeId) {
|
|
8794
|
+
this._declaredStateKeys.add(key);
|
|
8795
|
+
return createDurableState({
|
|
8796
|
+
key: nodeScopedKey(key, nodeId ?? this._ctx?.kernel?.localNodeId ?? ""),
|
|
8797
|
+
schema,
|
|
8798
|
+
fallback,
|
|
8799
|
+
read: async () => this.resolveStoredSecrets(await this.readAddonStoreWithRetry()),
|
|
8800
|
+
write: async (patch) => {
|
|
8801
|
+
await this._ctx?.settings?.writeAddonStore(patch);
|
|
8802
|
+
},
|
|
8803
|
+
onParseError: (k, e) => this._ctx?.logger?.warn?.(`durable-state: stored "${k}" failed validation — using fallback`, { meta: {
|
|
8804
|
+
addonId: this._ctx?.id,
|
|
8805
|
+
key: k,
|
|
8806
|
+
error: String(e)
|
|
8807
|
+
} })
|
|
8808
|
+
});
|
|
8809
|
+
}
|
|
8810
|
+
/** The loaded schema `cap` declares for `scope`, or `null`. */
|
|
8811
|
+
async declaredScopedSchema(scope, cap) {
|
|
8812
|
+
await this.loadScopedSchemas(cap);
|
|
8813
|
+
return this.loadedScopedSchemas(cap).find((entry) => entry.scope === scope)?.schema ?? null;
|
|
8814
|
+
}
|
|
8815
|
+
async requireScopedSchema(scope, cap) {
|
|
8816
|
+
const schema = await this.declaredScopedSchema(scope, cap);
|
|
8817
|
+
if (schema === null) throw new Error(`${this.constructor.name}: cap "${cap}" declares no ${scope} settings`);
|
|
8818
|
+
return schema;
|
|
8819
|
+
}
|
|
8820
|
+
scopedKeys(schema) {
|
|
8821
|
+
return new Set(schema.sections.flatMap((section) => collectValueFieldKeys(section.fields)));
|
|
8822
|
+
}
|
|
8823
|
+
/** `store` narrowed to the keys `schema` declares. */
|
|
8824
|
+
narrowToScope(store, schema) {
|
|
8825
|
+
const keys = this.scopedKeys(schema);
|
|
8826
|
+
return Object.fromEntries(Object.entries(store).filter(([key]) => keys.has(key)));
|
|
8827
|
+
}
|
|
8828
|
+
scopedHandle(scope, cap, schema, nodeId) {
|
|
8829
|
+
return createScopedSettings({
|
|
8830
|
+
schema,
|
|
8831
|
+
read: async () => {
|
|
8832
|
+
const declared = await this.requireScopedSchema(scope, cap);
|
|
8833
|
+
const stored = this.narrowToScope(await this.resolveGlobalStore(nodeId, cap), declared);
|
|
8834
|
+
const effective = collectHydratedFieldValues(hydrateSchema(declared, stored));
|
|
8835
|
+
return {
|
|
8836
|
+
...Object.fromEntries([...effective].filter(([, value]) => value !== void 0)),
|
|
8837
|
+
...stored
|
|
8838
|
+
};
|
|
8839
|
+
},
|
|
8840
|
+
write: (patch) => this.writeScoped(scope, cap, patch, nodeId),
|
|
8841
|
+
unset: (keys) => this.unsetScoped(scope, cap, keys, nodeId)
|
|
8842
|
+
});
|
|
8843
|
+
}
|
|
8844
|
+
/** The one write path of the scoped API: declared keys only, then the global patch. */
|
|
8845
|
+
async writeScoped(scope, cap, patch, nodeId) {
|
|
8846
|
+
assertDeclaredKeys(Object.keys(patch), this.scopedKeys(await this.requireScopedSchema(scope, cap)));
|
|
8847
|
+
if (await this.applyGlobalPatch(patch, scope === "node" ? nodeId : void 0, cap)) await this.onScopedSettingsChanged(scope, cap, Object.keys(patch));
|
|
8848
|
+
}
|
|
8849
|
+
/**
|
|
8850
|
+
* Remove declared keys of one scope. A secret goes through {@link clearSecrets} — its keychain
|
|
8851
|
+
* value is released exactly as there — and the emptied row is then removed; every other key is
|
|
8852
|
+
* removed by an `undefined` patch (which a secret transform would read as "keep").
|
|
8853
|
+
*/
|
|
8854
|
+
async unsetScoped(scope, cap, keys, nodeId) {
|
|
8855
|
+
assertDeclaredKeys(keys, this.scopedKeys(await this.requireScopedSchema(scope, cap)));
|
|
8856
|
+
const target = scope === "node" ? nodeId : void 0;
|
|
8857
|
+
const tree = this.addonSecretTree();
|
|
8858
|
+
const secretKeys = keys.filter((key) => tree.has(key));
|
|
8859
|
+
const plainKeys = keys.filter((key) => !tree.has(key));
|
|
8860
|
+
let changed = false;
|
|
8861
|
+
if (plainKeys.length > 0) {
|
|
8862
|
+
const patch = Object.fromEntries(plainKeys.map((key) => [key, void 0]));
|
|
8863
|
+
changed = await this.applyGlobalPatch(patch, target, cap) || changed;
|
|
8864
|
+
}
|
|
8865
|
+
if (secretKeys.length > 0) {
|
|
8866
|
+
await this.clearSecretKeys(secretKeys, target, cap);
|
|
8867
|
+
const node = normalizeNodeId(target ?? this._ctx?.kernel?.localNodeId);
|
|
8868
|
+
const rows = secretKeys.map((key) => scope === "node" ? nodeScopedKey(key, node) : key);
|
|
8869
|
+
if (this._secretSettings !== null) await this._secretSettings.removeClearedKeys(rows);
|
|
8870
|
+
else await this._ctx?.settings?.writeAddonStore(Object.fromEntries(rows.map((row) => [row, void 0])));
|
|
8871
|
+
changed = true;
|
|
8872
|
+
}
|
|
8873
|
+
if (changed) await this.onScopedSettingsChanged(scope, cap, [...keys]);
|
|
8874
|
+
}
|
|
8875
|
+
/**
|
|
8876
|
+
* The hydrated form of one scope of one capability's settings (any
|
|
8877
|
+
* {@link scopedSettingsOverlay} applied), or `null` when the capability declares nothing there.
|
|
8878
|
+
*/
|
|
8879
|
+
async getScopedSettings(scope, cap, nodeId) {
|
|
8880
|
+
const schema = await this.declaredScopedSchema(scope, cap);
|
|
8881
|
+
if (schema === null) return null;
|
|
8882
|
+
const stored = this.narrowToScope(await this.readRawProjectedStore(nodeId, cap), schema);
|
|
8883
|
+
const overlay = await this.scopedSettingsOverlay(scope, cap, nodeId);
|
|
8884
|
+
return hydrateSchema(schema, overlay ? await this.overlayKeepingMarkers(stored, overlay) : stored, { inlineSecretsAsViews: true });
|
|
8885
|
+
}
|
|
8886
|
+
/**
|
|
8887
|
+
* The scoped schemas this addon serves: one entry per loaded (capability, scope), capabilities
|
|
8888
|
+
* in declaration order, scopes in {@link SCOPED_SETTINGS_SCOPES} order. `[]` when it declares
|
|
8889
|
+
* nothing.
|
|
8890
|
+
*/
|
|
8891
|
+
async listScopedSettings() {
|
|
8892
|
+
await this.loadScopedSchemas();
|
|
8893
|
+
return [...this._scopedByCap].flatMap(([cap, entries]) => entries.map((entry) => ({
|
|
8894
|
+
cap,
|
|
8895
|
+
scope: entry.scope,
|
|
8896
|
+
sectionIds: entry.schema.sections.map((section) => section.id)
|
|
8897
|
+
})));
|
|
8898
|
+
}
|
|
8899
|
+
/** The OPERATOR's write of declared keys of one scope (D787 secret semantics). */
|
|
8900
|
+
async updateScopedSettings(scope, cap, patch, nodeId) {
|
|
8901
|
+
this._operatorWriteDepth++;
|
|
8902
|
+
try {
|
|
8903
|
+
await this.writeScoped(scope, cap, patch, nodeId);
|
|
8904
|
+
} finally {
|
|
8905
|
+
this._operatorWriteDepth--;
|
|
8906
|
+
}
|
|
8907
|
+
}
|
|
8908
|
+
/**
|
|
8909
|
+
* The effective values (`stored ?? default`) of one scope, a secret as its `set` view — never
|
|
8910
|
+
* its value. `null` when the capability declares nothing for the scope.
|
|
8911
|
+
*/
|
|
8912
|
+
async readScopedValues(scope, cap, nodeId) {
|
|
8913
|
+
const schema = await this.declaredScopedSchema(scope, cap);
|
|
8914
|
+
if (schema === null) return null;
|
|
8915
|
+
const form = hydrateSchema(schema, this.narrowToScope(await this.readRawProjectedStore(nodeId, cap), schema), { inlineSecretsAsViews: true });
|
|
8916
|
+
return Object.fromEntries([...collectHydratedFieldValues(form)].filter(([, value]) => value !== void 0));
|
|
8917
|
+
}
|
|
8918
|
+
/**
|
|
8712
8919
|
* What the create wizard and the integration edit page render for one instance: the addon's
|
|
8713
8920
|
* per-instance schema when it declares one, else its global schema (what they always showed).
|
|
8714
8921
|
*/
|
|
8715
8922
|
async getIntegrationFormSchema(instance, nodeId) {
|
|
8716
8923
|
const scoped = await this.integrationFormSchema(instance);
|
|
8717
|
-
if (scoped === null) return this.
|
|
8924
|
+
if (scoped === null) return this.scopedForm(nodeId);
|
|
8718
8925
|
return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
|
|
8719
8926
|
}
|
|
8720
|
-
|
|
8721
|
-
|
|
8722
|
-
|
|
8723
|
-
const schema = this.
|
|
8724
|
-
if (!schema)
|
|
8725
|
-
|
|
8726
|
-
const sections = [];
|
|
8727
|
-
for (const id of declared) {
|
|
8728
|
-
const section = byId.get(id);
|
|
8729
|
-
if (!section) throw new Error(`${this.constructor.name}: integrationSettingSections() names unknown section "${id}". Known sections: [${[...byId.keys()].join(", ")}].`);
|
|
8730
|
-
const fields = dropPerNodeFields(section.fields);
|
|
8731
|
-
if (fields.length === 0) continue;
|
|
8732
|
-
sections.push({
|
|
8733
|
-
...section,
|
|
8734
|
-
fields
|
|
8735
|
-
});
|
|
8736
|
-
}
|
|
8737
|
-
if (sections.length === 0) return null;
|
|
8738
|
-
const projected = await this.readRawProjectedStore(nodeId);
|
|
8739
|
-
return hydrateSchema({
|
|
8740
|
-
...schema,
|
|
8741
|
-
sections
|
|
8742
|
-
}, projected, { inlineSecretsAsViews: true });
|
|
8927
|
+
/** The form of the scoped schemas this addon declared, hydrated from its store. */
|
|
8928
|
+
async scopedForm(nodeId) {
|
|
8929
|
+
await this.loadScopedSchemas();
|
|
8930
|
+
const schema = this.scopedFormSchema();
|
|
8931
|
+
if (!schema) return { sections: [] };
|
|
8932
|
+
return hydrateSchema(schema, await this.readRawProjectedStore(nodeId), { inlineSecretsAsViews: true });
|
|
8743
8933
|
}
|
|
8744
8934
|
/**
|
|
8745
8935
|
* The raw addon store PROJECTED onto the target node's bare per-node keys:
|
|
@@ -8748,8 +8938,8 @@ var BaseAddon = class {
|
|
|
8748
8938
|
* bare fallback), all `@`-scoped and stray bare per-node keys are dropped.
|
|
8749
8939
|
* A no-op passthrough when the schema declares no `perNode` field.
|
|
8750
8940
|
*
|
|
8751
|
-
* This is the sanctioned way for
|
|
8752
|
-
* the store for custom
|
|
8941
|
+
* This is the sanctioned way for an addon that needs
|
|
8942
|
+
* the store for custom logic (option narrowing, value snapping) to
|
|
8753
8943
|
* read it per-node — never `ctx.settings.readAddonStore()` directly.
|
|
8754
8944
|
* `nodeId` omitted ⇒ the local node (node-blind injection from ctx).
|
|
8755
8945
|
*
|
|
@@ -8801,7 +8991,7 @@ var BaseAddon = class {
|
|
|
8801
8991
|
}
|
|
8802
8992
|
/**
|
|
8803
8993
|
* Whether ONE global key of this addon's store was written, read three-way
|
|
8804
|
-
* (D651). For a question a hydrated view cannot answer:
|
|
8994
|
+
* (D651). For a question a hydrated view cannot answer: a hydrated form
|
|
8805
8995
|
* reports `value ?? default`, so "the operator chose the default" and "nobody
|
|
8806
8996
|
* chose" look the same, and a failed read looks like both. A `perNode` key is
|
|
8807
8997
|
* not supported here: its stored name is scoped.
|
|
@@ -8835,7 +9025,7 @@ var BaseAddon = class {
|
|
|
8835
9025
|
}
|
|
8836
9026
|
/**
|
|
8837
9027
|
* The OPERATOR's write — a settings form or an admin API call, dispatched by
|
|
8838
|
-
* the kernel.
|
|
9028
|
+
* the kernel. The one in-process write of the addon blob that is not a scoped write; a secret
|
|
8839
9029
|
* the operator sends is stored as sent even when it equals a pre-keychain
|
|
8840
9030
|
* inline value: the operator re-entering a password is a change, an addon
|
|
8841
9031
|
* writing back what it read is not (D787).
|
|
@@ -8848,9 +9038,6 @@ var BaseAddon = class {
|
|
|
8848
9038
|
this._operatorWriteDepth--;
|
|
8849
9039
|
}
|
|
8850
9040
|
}
|
|
8851
|
-
async updateGlobalSettings(patch, nodeId) {
|
|
8852
|
-
await this.applyGlobalPatch(patch, nodeId);
|
|
8853
|
-
}
|
|
8854
9041
|
/**
|
|
8855
9042
|
* REMOVE stored secrets — their keychain values and their markers (D787).
|
|
8856
9043
|
*
|
|
@@ -8860,6 +9047,9 @@ var BaseAddon = class {
|
|
|
8860
9047
|
* a keychain (an older kernel) it writes `''`, as such code always did.
|
|
8861
9048
|
*/
|
|
8862
9049
|
async clearSecrets(keys, nodeId) {
|
|
9050
|
+
await this.clearSecretKeys(keys, nodeId);
|
|
9051
|
+
}
|
|
9052
|
+
async clearSecretKeys(keys, nodeId, cap) {
|
|
8863
9053
|
const tree = this.addonSecretTree();
|
|
8864
9054
|
const keychain = this._ctx?.secrets !== void 0;
|
|
8865
9055
|
const stored = keychain ? await this.readAddonStoreWithRetry() : {};
|
|
@@ -8872,25 +9062,26 @@ var BaseAddon = class {
|
|
|
8872
9062
|
const keychainStored = tree.has(key) || collectSecretMarkerRefs(stored[key]).length > 0;
|
|
8873
9063
|
patch[key] = keychain && keychainStored ? SECRET_CLEAR : "";
|
|
8874
9064
|
}
|
|
8875
|
-
await this.applyGlobalPatch(patch, nodeId);
|
|
9065
|
+
await this.applyGlobalPatch(patch, nodeId, cap);
|
|
8876
9066
|
}
|
|
8877
|
-
|
|
8878
|
-
|
|
8879
|
-
|
|
9067
|
+
/** Resolves `true` when the write changed stored values. */
|
|
9068
|
+
async applyGlobalPatch(barePatch, nodeId, cap) {
|
|
9069
|
+
await this.loadScopedSchemas(cap);
|
|
9070
|
+
const keys = this.perNodeKeys(cap);
|
|
8880
9071
|
const localNode = normalizeNodeId(this._ctx?.kernel?.localNodeId);
|
|
8881
9072
|
const target = normalizeNodeId(nodeId ?? this._ctx?.kernel?.localNodeId);
|
|
8882
9073
|
const scoped = keys.size > 0 ? scopePatch(barePatch, keys, target) : barePatch;
|
|
8883
9074
|
const handle = this._secretSettings;
|
|
8884
9075
|
if (handle !== null) {
|
|
8885
9076
|
const { changed } = await handle.writeAddonStore(scoped);
|
|
8886
|
-
if (!changed) return;
|
|
9077
|
+
if (!changed) return false;
|
|
8887
9078
|
} else await this._ctx?.settings?.writeAddonStore(scoped);
|
|
8888
|
-
if (target !== localNode) return;
|
|
9079
|
+
if (target !== localNode) return true;
|
|
8889
9080
|
await this.resolveConfig();
|
|
8890
9081
|
await this.onConfigChanged();
|
|
8891
9082
|
this.emitLifecycle(EventCategory.AddonUpdated, { level: "global" });
|
|
8892
|
-
|
|
8893
|
-
|
|
9083
|
+
this.maybeAutoRestart(Object.keys(barePatch), this.loadedScopedSchemas().map((entry) => entry.schema));
|
|
9084
|
+
return true;
|
|
8894
9085
|
}
|
|
8895
9086
|
/**
|
|
8896
9087
|
* The set of field keys the global settings schema declares `perNode: true`
|
|
@@ -8927,10 +9118,7 @@ var BaseAddon = class {
|
|
|
8927
9118
|
this._nodeKeysByCap = /* @__PURE__ */ new Map();
|
|
8928
9119
|
this._addonSecretTree = null;
|
|
8929
9120
|
}
|
|
8930
|
-
/**
|
|
8931
|
-
* The form the settings API serves while an addon declares no {@link globalSettingsSchema}: the
|
|
8932
|
-
* sections of its scoped schemas, so dropping the old hook does not blank the form.
|
|
8933
|
-
*/
|
|
9121
|
+
/** The form of an addon's scoped schemas: their sections, each shown once. */
|
|
8934
9122
|
scopedFormSchema(cap) {
|
|
8935
9123
|
const byId = /* @__PURE__ */ new Map();
|
|
8936
9124
|
for (const entry of this.loadedScopedSchemas(cap)) for (const section of entry.schema.sections) if (!byId.has(section.id)) byId.set(section.id, section);
|
|
@@ -8942,8 +9130,7 @@ var BaseAddon = class {
|
|
|
8942
9130
|
return [...this._scopedByCap.values()].flat();
|
|
8943
9131
|
}
|
|
8944
9132
|
/**
|
|
8945
|
-
* The field keys that are stored per node: every field of a {@link nodeSettingsSchema}
|
|
8946
|
-
* the fields the legacy {@link globalSettingsSchema} still marks `perNode: true`. Derived once
|
|
9133
|
+
* The field keys that are stored per node: every field of a {@link nodeSettingsSchema}. Derived once
|
|
8947
9134
|
* per `cap` argument and memoized (schemas are static declarations). Empty set ⇒ every
|
|
8948
9135
|
* per-node code path is bypassed and the settings API behaves like the node-agnostic one.
|
|
8949
9136
|
* Call {@link loadScopedSchemas} first (the async seams do).
|
|
@@ -8952,8 +9139,7 @@ var BaseAddon = class {
|
|
|
8952
9139
|
const cacheKey = cap ?? "";
|
|
8953
9140
|
const cached = this._nodeKeysByCap.get(cacheKey);
|
|
8954
9141
|
if (cached) return cached;
|
|
8955
|
-
const
|
|
8956
|
-
const keys = new Set(legacy ? legacy.sections.flatMap((section) => collectPerNodeFieldKeys(section.fields)) : []);
|
|
9142
|
+
const keys = /* @__PURE__ */ new Set();
|
|
8957
9143
|
for (const { scope, schema } of this.loadedScopedSchemas(cap)) {
|
|
8958
9144
|
if (scope !== "node") continue;
|
|
8959
9145
|
for (const section of schema.sections) for (const key of collectValueFieldKeys(section.fields)) keys.add(key);
|
|
@@ -9171,8 +9357,6 @@ var BaseAddon = class {
|
|
|
9171
9357
|
}
|
|
9172
9358
|
declaredKeySet() {
|
|
9173
9359
|
const keys = new Set(Object.keys(this.defaults));
|
|
9174
|
-
const schema = this.globalSettingsSchema();
|
|
9175
|
-
if (schema) for (const section of schema.sections) for (const key of collectFieldKeys(section.fields)) keys.add(key);
|
|
9176
9360
|
for (const { schema: scoped } of this.loadedScopedSchemas()) for (const section of scoped.sections) for (const key of collectFieldKeys(section.fields)) keys.add(key);
|
|
9177
9361
|
for (const key of this._declaredStateKeys) keys.add(key);
|
|
9178
9362
|
for (const path of this.secretStatePaths) {
|
|
@@ -9270,7 +9454,7 @@ var BaseAddon = class {
|
|
|
9270
9454
|
/** The addon store's secret tree: schema fields by TYPE, plus `secretStatePaths`. */
|
|
9271
9455
|
addonSecretTree() {
|
|
9272
9456
|
if (this._addonSecretTree === null) {
|
|
9273
|
-
const tree = new Map(
|
|
9457
|
+
const tree = /* @__PURE__ */ new Map();
|
|
9274
9458
|
for (const { schema } of this.loadedScopedSchemas()) for (const [key, node] of secretTreeFromSchema(schema)) tree.set(key, node);
|
|
9275
9459
|
this._addonSecretTree = mergeSecretStatePaths(tree, this.secretStatePaths);
|
|
9276
9460
|
}
|
|
@@ -9482,47 +9666,6 @@ function classifyStoreError(err) {
|
|
|
9482
9666
|
if (TRANSPORT_PHRASES.some((f) => message.includes(f))) return "transport";
|
|
9483
9667
|
return "permanent";
|
|
9484
9668
|
}
|
|
9485
|
-
/**
|
|
9486
|
-
* Collect the keys of every field marked `perNode: true`, recursing into
|
|
9487
|
-
* layout containers (`group` fields and `sub-tabs` tabs) the same way
|
|
9488
|
-
* `hydrateSchema` does. Valueless structural fields (separator/info/…)
|
|
9489
|
-
* don't declare `perNode` and are excluded by the `in` narrowing.
|
|
9490
|
-
*/
|
|
9491
|
-
/**
|
|
9492
|
-
* The same fields with every `perNode: true` one removed, recursing into layout
|
|
9493
|
-
* containers exactly as {@link collectPerNodeFieldKeys} does. A container left
|
|
9494
|
-
* with no child is dropped rather than rendered empty.
|
|
9495
|
-
*
|
|
9496
|
-
* Used by `getIntegrationSettings`: an integration is not a node, so a field
|
|
9497
|
-
* whose store key is `<key>@<nodeId>` has no node to belong to there.
|
|
9498
|
-
*/
|
|
9499
|
-
function dropPerNodeFields(fields) {
|
|
9500
|
-
const kept = [];
|
|
9501
|
-
for (const field of fields) {
|
|
9502
|
-
if (field.type === "group") {
|
|
9503
|
-
const inner = dropPerNodeFields(field.fields);
|
|
9504
|
-
if (inner.length > 0) kept.push({
|
|
9505
|
-
...field,
|
|
9506
|
-
fields: inner
|
|
9507
|
-
});
|
|
9508
|
-
continue;
|
|
9509
|
-
}
|
|
9510
|
-
if (field.type === "sub-tabs") {
|
|
9511
|
-
const tabs = field.tabs.map((tab) => ({
|
|
9512
|
-
...tab,
|
|
9513
|
-
fields: dropPerNodeFields(tab.fields)
|
|
9514
|
-
})).filter((tab) => tab.fields.length > 0);
|
|
9515
|
-
if (tabs.length > 0) kept.push({
|
|
9516
|
-
...field,
|
|
9517
|
-
tabs
|
|
9518
|
-
});
|
|
9519
|
-
continue;
|
|
9520
|
-
}
|
|
9521
|
-
if ("perNode" in field && field.perNode === true) continue;
|
|
9522
|
-
kept.push(field);
|
|
9523
|
-
}
|
|
9524
|
-
return kept;
|
|
9525
|
-
}
|
|
9526
9669
|
/** The keys of the value-holding fields, recursing into layout containers. */
|
|
9527
9670
|
function collectValueFieldKeys(fields) {
|
|
9528
9671
|
const collected = [];
|
|
@@ -9555,21 +9698,6 @@ function collectFieldKeys(fields) {
|
|
|
9555
9698
|
}
|
|
9556
9699
|
return collected;
|
|
9557
9700
|
}
|
|
9558
|
-
function collectPerNodeFieldKeys(fields) {
|
|
9559
|
-
const collected = [];
|
|
9560
|
-
for (const field of fields) {
|
|
9561
|
-
if (field.type === "group") {
|
|
9562
|
-
collected.push(...collectPerNodeFieldKeys(field.fields));
|
|
9563
|
-
continue;
|
|
9564
|
-
}
|
|
9565
|
-
if (field.type === "sub-tabs") {
|
|
9566
|
-
for (const tab of field.tabs) collected.push(...collectPerNodeFieldKeys(tab.fields));
|
|
9567
|
-
continue;
|
|
9568
|
-
}
|
|
9569
|
-
if ("perNode" in field && field.perNode === true) collected.push(field.key);
|
|
9570
|
-
}
|
|
9571
|
-
return collected;
|
|
9572
|
-
}
|
|
9573
9701
|
/**
|
|
9574
9702
|
* Normalize an `ICamstackAddon.initialize()` return value into the
|
|
9575
9703
|
* `AddonInitResult` envelope. Arrays are wrapped into `{ providers }`;
|
|
@@ -10620,7 +10748,6 @@ var CAP_NAMES = Object.freeze([
|
|
|
10620
10748
|
"notifier",
|
|
10621
10749
|
"numeric-sensor",
|
|
10622
10750
|
"oauth-integration",
|
|
10623
|
-
"oidc-connections",
|
|
10624
10751
|
"osd",
|
|
10625
10752
|
"osd-manager",
|
|
10626
10753
|
"pet-feeder",
|
|
@@ -12327,13 +12454,25 @@ Object.freeze({
|
|
|
12327
12454
|
"path": "temperature",
|
|
12328
12455
|
"valueType": "number"
|
|
12329
12456
|
}],
|
|
12330
|
-
"timed-run": [
|
|
12331
|
-
|
|
12332
|
-
|
|
12333
|
-
|
|
12334
|
-
|
|
12335
|
-
|
|
12336
|
-
|
|
12457
|
+
"timed-run": [
|
|
12458
|
+
{
|
|
12459
|
+
"path": "activeUntil",
|
|
12460
|
+
"valueType": "number"
|
|
12461
|
+
},
|
|
12462
|
+
{
|
|
12463
|
+
"path": "requestedBy",
|
|
12464
|
+
"valueType": "string"
|
|
12465
|
+
},
|
|
12466
|
+
{
|
|
12467
|
+
"path": "quickRun.duration",
|
|
12468
|
+
"valueType": "number"
|
|
12469
|
+
},
|
|
12470
|
+
{
|
|
12471
|
+
"path": "quickRun.unit",
|
|
12472
|
+
"valueType": "enum",
|
|
12473
|
+
"enumValues": ["s", "min"]
|
|
12474
|
+
}
|
|
12475
|
+
],
|
|
12337
12476
|
"update": [
|
|
12338
12477
|
{
|
|
12339
12478
|
"path": "currentVersion",
|
|
@@ -12512,8 +12651,7 @@ Object.freeze({
|
|
|
12512
12651
|
"device-provider": { "reloadDevice": 18e4 },
|
|
12513
12652
|
"llm": {
|
|
12514
12653
|
"generate": 6e5,
|
|
12515
|
-
"generateVision": 6e5
|
|
12516
|
-
"testProfile": 6e5
|
|
12654
|
+
"generateVision": 6e5
|
|
12517
12655
|
},
|
|
12518
12656
|
"llm-runtime": {
|
|
12519
12657
|
"complete": 6e5,
|
|
@@ -12572,7 +12710,7 @@ function userError(code, params, englishFallback) {
|
|
|
12572
12710
|
return new CamstackError(code, params, englishFallback);
|
|
12573
12711
|
}
|
|
12574
12712
|
//#endregion
|
|
12575
|
-
//#region ../types/dist/composition-
|
|
12713
|
+
//#region ../types/dist/composition-Bx0JvKUU.mjs
|
|
12576
12714
|
/**
|
|
12577
12715
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
12578
12716
|
*
|
|
@@ -13734,6 +13872,387 @@ var NodeColorIdSchema = _enum([
|
|
|
13734
13872
|
"node-h"
|
|
13735
13873
|
]);
|
|
13736
13874
|
//#endregion
|
|
13875
|
+
//#region ../types/dist/convert-BAzH15HU.mjs
|
|
13876
|
+
/**
|
|
13877
|
+
* Frozen unit → spec table. `•` in the doc marks each dimension's canonical
|
|
13878
|
+
* unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
|
|
13879
|
+
* `factor = 5/9`, `offset = -160/9` (kept as exact expressions, not rounded
|
|
13880
|
+
* decimals). K derives from `°C = K − 273.15`.
|
|
13881
|
+
*/
|
|
13882
|
+
var UNIT_TABLE = {
|
|
13883
|
+
"°C": {
|
|
13884
|
+
dimension: "temperature",
|
|
13885
|
+
factor: 1,
|
|
13886
|
+
offset: 0
|
|
13887
|
+
},
|
|
13888
|
+
"°F": {
|
|
13889
|
+
dimension: "temperature",
|
|
13890
|
+
factor: 5 / 9,
|
|
13891
|
+
offset: -160 / 9
|
|
13892
|
+
},
|
|
13893
|
+
K: {
|
|
13894
|
+
dimension: "temperature",
|
|
13895
|
+
factor: 1,
|
|
13896
|
+
offset: -273.15
|
|
13897
|
+
},
|
|
13898
|
+
hPa: {
|
|
13899
|
+
dimension: "pressure",
|
|
13900
|
+
factor: 1,
|
|
13901
|
+
offset: 0
|
|
13902
|
+
},
|
|
13903
|
+
kPa: {
|
|
13904
|
+
dimension: "pressure",
|
|
13905
|
+
factor: 10,
|
|
13906
|
+
offset: 0
|
|
13907
|
+
},
|
|
13908
|
+
Pa: {
|
|
13909
|
+
dimension: "pressure",
|
|
13910
|
+
factor: .01,
|
|
13911
|
+
offset: 0
|
|
13912
|
+
},
|
|
13913
|
+
mbar: {
|
|
13914
|
+
dimension: "pressure",
|
|
13915
|
+
factor: 1,
|
|
13916
|
+
offset: 0
|
|
13917
|
+
},
|
|
13918
|
+
bar: {
|
|
13919
|
+
dimension: "pressure",
|
|
13920
|
+
factor: 1e3,
|
|
13921
|
+
offset: 0
|
|
13922
|
+
},
|
|
13923
|
+
inHg: {
|
|
13924
|
+
dimension: "pressure",
|
|
13925
|
+
factor: 33.8639,
|
|
13926
|
+
offset: 0
|
|
13927
|
+
},
|
|
13928
|
+
mmHg: {
|
|
13929
|
+
dimension: "pressure",
|
|
13930
|
+
factor: 1.33322,
|
|
13931
|
+
offset: 0
|
|
13932
|
+
},
|
|
13933
|
+
psi: {
|
|
13934
|
+
dimension: "pressure",
|
|
13935
|
+
factor: 68.9476,
|
|
13936
|
+
offset: 0
|
|
13937
|
+
},
|
|
13938
|
+
"m/s": {
|
|
13939
|
+
dimension: "speed",
|
|
13940
|
+
factor: 1,
|
|
13941
|
+
offset: 0
|
|
13942
|
+
},
|
|
13943
|
+
"km/h": {
|
|
13944
|
+
dimension: "speed",
|
|
13945
|
+
factor: 1 / 3.6,
|
|
13946
|
+
offset: 0
|
|
13947
|
+
},
|
|
13948
|
+
mph: {
|
|
13949
|
+
dimension: "speed",
|
|
13950
|
+
factor: .44704,
|
|
13951
|
+
offset: 0
|
|
13952
|
+
},
|
|
13953
|
+
kn: {
|
|
13954
|
+
dimension: "speed",
|
|
13955
|
+
factor: .514444,
|
|
13956
|
+
offset: 0
|
|
13957
|
+
},
|
|
13958
|
+
"mm/h": {
|
|
13959
|
+
dimension: "precipitation-rate",
|
|
13960
|
+
factor: 1,
|
|
13961
|
+
offset: 0
|
|
13962
|
+
},
|
|
13963
|
+
"in/h": {
|
|
13964
|
+
dimension: "precipitation-rate",
|
|
13965
|
+
factor: 25.4,
|
|
13966
|
+
offset: 0
|
|
13967
|
+
},
|
|
13968
|
+
m: {
|
|
13969
|
+
dimension: "length",
|
|
13970
|
+
factor: 1,
|
|
13971
|
+
offset: 0
|
|
13972
|
+
},
|
|
13973
|
+
mm: {
|
|
13974
|
+
dimension: "length",
|
|
13975
|
+
factor: .001,
|
|
13976
|
+
offset: 0
|
|
13977
|
+
},
|
|
13978
|
+
cm: {
|
|
13979
|
+
dimension: "length",
|
|
13980
|
+
factor: .01,
|
|
13981
|
+
offset: 0
|
|
13982
|
+
},
|
|
13983
|
+
km: {
|
|
13984
|
+
dimension: "length",
|
|
13985
|
+
factor: 1e3,
|
|
13986
|
+
offset: 0
|
|
13987
|
+
},
|
|
13988
|
+
in: {
|
|
13989
|
+
dimension: "length",
|
|
13990
|
+
factor: .0254,
|
|
13991
|
+
offset: 0
|
|
13992
|
+
},
|
|
13993
|
+
ft: {
|
|
13994
|
+
dimension: "length",
|
|
13995
|
+
factor: .3048,
|
|
13996
|
+
offset: 0
|
|
13997
|
+
},
|
|
13998
|
+
mi: {
|
|
13999
|
+
dimension: "length",
|
|
14000
|
+
factor: 1609.344,
|
|
14001
|
+
offset: 0
|
|
14002
|
+
},
|
|
14003
|
+
"m²": {
|
|
14004
|
+
dimension: "area",
|
|
14005
|
+
factor: 1,
|
|
14006
|
+
offset: 0
|
|
14007
|
+
},
|
|
14008
|
+
lx: {
|
|
14009
|
+
dimension: "illuminance",
|
|
14010
|
+
factor: 1,
|
|
14011
|
+
offset: 0
|
|
14012
|
+
},
|
|
14013
|
+
"W/m²": {
|
|
14014
|
+
dimension: "irradiance",
|
|
14015
|
+
factor: 1,
|
|
14016
|
+
offset: 0
|
|
14017
|
+
},
|
|
14018
|
+
W: {
|
|
14019
|
+
dimension: "power",
|
|
14020
|
+
factor: 1,
|
|
14021
|
+
offset: 0
|
|
14022
|
+
},
|
|
14023
|
+
kW: {
|
|
14024
|
+
dimension: "power",
|
|
14025
|
+
factor: 1e3,
|
|
14026
|
+
offset: 0
|
|
14027
|
+
},
|
|
14028
|
+
VA: {
|
|
14029
|
+
dimension: "apparent-power",
|
|
14030
|
+
factor: 1,
|
|
14031
|
+
offset: 0
|
|
14032
|
+
},
|
|
14033
|
+
Wh: {
|
|
14034
|
+
dimension: "energy",
|
|
14035
|
+
factor: 1,
|
|
14036
|
+
offset: 0
|
|
14037
|
+
},
|
|
14038
|
+
kWh: {
|
|
14039
|
+
dimension: "energy",
|
|
14040
|
+
factor: 1e3,
|
|
14041
|
+
offset: 0
|
|
14042
|
+
},
|
|
14043
|
+
MWh: {
|
|
14044
|
+
dimension: "energy",
|
|
14045
|
+
factor: 1e6,
|
|
14046
|
+
offset: 0
|
|
14047
|
+
},
|
|
14048
|
+
V: {
|
|
14049
|
+
dimension: "voltage",
|
|
14050
|
+
factor: 1,
|
|
14051
|
+
offset: 0
|
|
14052
|
+
},
|
|
14053
|
+
mV: {
|
|
14054
|
+
dimension: "voltage",
|
|
14055
|
+
factor: .001,
|
|
14056
|
+
offset: 0
|
|
14057
|
+
},
|
|
14058
|
+
A: {
|
|
14059
|
+
dimension: "current",
|
|
14060
|
+
factor: 1,
|
|
14061
|
+
offset: 0
|
|
14062
|
+
},
|
|
14063
|
+
mA: {
|
|
14064
|
+
dimension: "current",
|
|
14065
|
+
factor: .001,
|
|
14066
|
+
offset: 0
|
|
14067
|
+
},
|
|
14068
|
+
ppm: {
|
|
14069
|
+
dimension: "concentration-volume",
|
|
14070
|
+
factor: 1,
|
|
14071
|
+
offset: 0
|
|
14072
|
+
},
|
|
14073
|
+
ppb: {
|
|
14074
|
+
dimension: "concentration-volume",
|
|
14075
|
+
factor: .001,
|
|
14076
|
+
offset: 0
|
|
14077
|
+
},
|
|
14078
|
+
"µg/m³": {
|
|
14079
|
+
dimension: "concentration-mass",
|
|
14080
|
+
factor: 1,
|
|
14081
|
+
offset: 0
|
|
14082
|
+
},
|
|
14083
|
+
"mg/m³": {
|
|
14084
|
+
dimension: "concentration-mass",
|
|
14085
|
+
factor: 1e3,
|
|
14086
|
+
offset: 0
|
|
14087
|
+
},
|
|
14088
|
+
kg: {
|
|
14089
|
+
dimension: "mass",
|
|
14090
|
+
factor: 1,
|
|
14091
|
+
offset: 0
|
|
14092
|
+
},
|
|
14093
|
+
g: {
|
|
14094
|
+
dimension: "mass",
|
|
14095
|
+
factor: .001,
|
|
14096
|
+
offset: 0
|
|
14097
|
+
},
|
|
14098
|
+
lb: {
|
|
14099
|
+
dimension: "mass",
|
|
14100
|
+
factor: .453592,
|
|
14101
|
+
offset: 0
|
|
14102
|
+
},
|
|
14103
|
+
oz: {
|
|
14104
|
+
dimension: "mass",
|
|
14105
|
+
factor: .0283495,
|
|
14106
|
+
offset: 0
|
|
14107
|
+
},
|
|
14108
|
+
"%": {
|
|
14109
|
+
dimension: "percentage",
|
|
14110
|
+
factor: 1,
|
|
14111
|
+
offset: 0
|
|
14112
|
+
},
|
|
14113
|
+
L: {
|
|
14114
|
+
dimension: "volume",
|
|
14115
|
+
factor: 1,
|
|
14116
|
+
offset: 0
|
|
14117
|
+
},
|
|
14118
|
+
mL: {
|
|
14119
|
+
dimension: "volume",
|
|
14120
|
+
factor: .001,
|
|
14121
|
+
offset: 0
|
|
14122
|
+
},
|
|
14123
|
+
gal: {
|
|
14124
|
+
dimension: "volume",
|
|
14125
|
+
factor: 3.785411784,
|
|
14126
|
+
offset: 0
|
|
14127
|
+
},
|
|
14128
|
+
s: {
|
|
14129
|
+
dimension: "duration",
|
|
14130
|
+
factor: 1,
|
|
14131
|
+
offset: 0
|
|
14132
|
+
},
|
|
14133
|
+
ms: {
|
|
14134
|
+
dimension: "duration",
|
|
14135
|
+
factor: .001,
|
|
14136
|
+
offset: 0
|
|
14137
|
+
},
|
|
14138
|
+
min: {
|
|
14139
|
+
dimension: "duration",
|
|
14140
|
+
factor: 60,
|
|
14141
|
+
offset: 0
|
|
14142
|
+
},
|
|
14143
|
+
h: {
|
|
14144
|
+
dimension: "duration",
|
|
14145
|
+
factor: 3600,
|
|
14146
|
+
offset: 0
|
|
14147
|
+
},
|
|
14148
|
+
d: {
|
|
14149
|
+
dimension: "duration",
|
|
14150
|
+
factor: 86400,
|
|
14151
|
+
offset: 0
|
|
14152
|
+
},
|
|
14153
|
+
B: {
|
|
14154
|
+
dimension: "information",
|
|
14155
|
+
factor: 1,
|
|
14156
|
+
offset: 0
|
|
14157
|
+
},
|
|
14158
|
+
KiB: {
|
|
14159
|
+
dimension: "information",
|
|
14160
|
+
factor: 1024,
|
|
14161
|
+
offset: 0
|
|
14162
|
+
},
|
|
14163
|
+
MiB: {
|
|
14164
|
+
dimension: "information",
|
|
14165
|
+
factor: 1024 ** 2,
|
|
14166
|
+
offset: 0
|
|
14167
|
+
},
|
|
14168
|
+
GiB: {
|
|
14169
|
+
dimension: "information",
|
|
14170
|
+
factor: 1024 ** 3,
|
|
14171
|
+
offset: 0
|
|
14172
|
+
},
|
|
14173
|
+
TiB: {
|
|
14174
|
+
dimension: "information",
|
|
14175
|
+
factor: 1024 ** 4,
|
|
14176
|
+
offset: 0
|
|
14177
|
+
},
|
|
14178
|
+
kB: {
|
|
14179
|
+
dimension: "information",
|
|
14180
|
+
factor: 1e3,
|
|
14181
|
+
offset: 0
|
|
14182
|
+
},
|
|
14183
|
+
MB: {
|
|
14184
|
+
dimension: "information",
|
|
14185
|
+
factor: 1e6,
|
|
14186
|
+
offset: 0
|
|
14187
|
+
},
|
|
14188
|
+
GB: {
|
|
14189
|
+
dimension: "information",
|
|
14190
|
+
factor: 1e9,
|
|
14191
|
+
offset: 0
|
|
14192
|
+
},
|
|
14193
|
+
"°": {
|
|
14194
|
+
dimension: "angle",
|
|
14195
|
+
factor: 1,
|
|
14196
|
+
offset: 0
|
|
14197
|
+
},
|
|
14198
|
+
dBFS: {
|
|
14199
|
+
dimension: "sound-level",
|
|
14200
|
+
factor: 1,
|
|
14201
|
+
offset: 0
|
|
14202
|
+
},
|
|
14203
|
+
dBm: {
|
|
14204
|
+
dimension: "signal-level",
|
|
14205
|
+
factor: 1,
|
|
14206
|
+
offset: 0
|
|
14207
|
+
},
|
|
14208
|
+
mired: {
|
|
14209
|
+
dimension: "colour-temperature",
|
|
14210
|
+
factor: 1,
|
|
14211
|
+
offset: 0
|
|
14212
|
+
},
|
|
14213
|
+
kbps: {
|
|
14214
|
+
dimension: "bitrate",
|
|
14215
|
+
factor: 1,
|
|
14216
|
+
offset: 0
|
|
14217
|
+
},
|
|
14218
|
+
Mbps: {
|
|
14219
|
+
dimension: "bitrate",
|
|
14220
|
+
factor: 1e3,
|
|
14221
|
+
offset: 0
|
|
14222
|
+
},
|
|
14223
|
+
fps: {
|
|
14224
|
+
dimension: "rate",
|
|
14225
|
+
factor: 1,
|
|
14226
|
+
offset: 0
|
|
14227
|
+
}
|
|
14228
|
+
};
|
|
14229
|
+
/** Resolve a unit's `UnitSpec`, or `undefined` when the spelling is unknown. */
|
|
14230
|
+
function specFor(unit) {
|
|
14231
|
+
return Object.hasOwn(UNIT_TABLE, unit) ? UNIT_TABLE[unit] : void 0;
|
|
14232
|
+
}
|
|
14233
|
+
/** Value in `spec`'s unit → its dimension's canonical unit. */
|
|
14234
|
+
function toCanonical(value, spec) {
|
|
14235
|
+
return value * spec.factor + spec.offset;
|
|
14236
|
+
}
|
|
14237
|
+
/** Canonical-unit value → the unit described by `spec`. */
|
|
14238
|
+
function fromCanonical(canonical, spec) {
|
|
14239
|
+
return (canonical - spec.offset) / spec.factor;
|
|
14240
|
+
}
|
|
14241
|
+
/**
|
|
14242
|
+
* Graceful variant for the render path: returns the converted value, or
|
|
14243
|
+
* `undefined` when the conversion is refused (unknown unit / cross-dimension).
|
|
14244
|
+
* Never throws — a render caller falls back to the raw value + source unit.
|
|
14245
|
+
*/
|
|
14246
|
+
function tryConvertUnit(value, from, to) {
|
|
14247
|
+
if (from === to) return value;
|
|
14248
|
+
const fromSpec = specFor(from);
|
|
14249
|
+
if (!fromSpec) return void 0;
|
|
14250
|
+
const toSpec = specFor(to);
|
|
14251
|
+
if (!toSpec) return void 0;
|
|
14252
|
+
if (fromSpec.dimension !== toSpec.dimension) return void 0;
|
|
14253
|
+
return fromCanonical(toCanonical(value, fromSpec), toSpec);
|
|
14254
|
+
}
|
|
14255
|
+
//#endregion
|
|
13737
14256
|
//#region ../types/dist/index.mjs
|
|
13738
14257
|
/**
|
|
13739
14258
|
* The `smtp-inbound` broker kind (D999): a mailbox a device can send mail to.
|
|
@@ -14038,17 +14557,18 @@ function composeInstanceKinds(parts, base) {
|
|
|
14038
14557
|
* message to what the kind supports — callers never special-case a service.
|
|
14039
14558
|
*
|
|
14040
14559
|
* DESIGN DECISIONS (locked):
|
|
14041
|
-
* -
|
|
14042
|
-
*
|
|
14043
|
-
*
|
|
14044
|
-
*
|
|
14045
|
-
*
|
|
14046
|
-
*
|
|
14047
|
-
*
|
|
14048
|
-
*
|
|
14049
|
-
*
|
|
14050
|
-
* routable. `send` / `testTarget` /
|
|
14051
|
-
* `
|
|
14560
|
+
* - A target is an INSTANCE of this function cap (epic #440, step 6): the
|
|
14561
|
+
* providers serve their targets as `integration-instances` records, one
|
|
14562
|
+
* record kind per target kind, and the admin lists, adds, edits, switches
|
|
14563
|
+
* and deletes them through that cap. This cap keeps what an instance cannot
|
|
14564
|
+
* say: the kind catalogue (`listTargetKinds`: capabilities, delivery
|
|
14565
|
+
* parameters, brand icon), dispatch (`send`, `testTarget`) and the form
|
|
14566
|
+
* helpers (`discoverTargets`, `probeTargetConfig`).
|
|
14567
|
+
* - `listTargetKinds` / `discoverTargets` return arrays → the generated
|
|
14568
|
+
* cap-mount auto-`concatCollection`-fans them across every registered
|
|
14569
|
+
* provider so one catalog is routable. `send` / `testTarget` /
|
|
14570
|
+
* `probeTargetConfig` route to ONE provider by the `addonId` the generated
|
|
14571
|
+
* collection router extracts from the call input.
|
|
14052
14572
|
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
14053
14573
|
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
14054
14574
|
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
@@ -14293,7 +14813,7 @@ var TargetKindCapsSchema = object({
|
|
|
14293
14813
|
* the union is large and not meant for runtime validation here; the exported
|
|
14294
14814
|
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
14295
14815
|
*/
|
|
14296
|
-
var ConfigSchemaPassthrough$
|
|
14816
|
+
var ConfigSchemaPassthrough$3 = unknown();
|
|
14297
14817
|
var TargetKindSchema = object({
|
|
14298
14818
|
kind: string(),
|
|
14299
14819
|
label: string(),
|
|
@@ -14330,7 +14850,7 @@ var TargetKindSchema = object({
|
|
|
14330
14850
|
* its raster path, which is the safe default for an unknown image.
|
|
14331
14851
|
*/
|
|
14332
14852
|
iconMediaType: string().optional(),
|
|
14333
|
-
configSchema: ConfigSchemaPassthrough$
|
|
14853
|
+
configSchema: ConfigSchemaPassthrough$3,
|
|
14334
14854
|
/**
|
|
14335
14855
|
* The config keys that decide WHERE this kind's secrets are sent (server,
|
|
14336
14856
|
* base URL, instance, chat, recipient). A save that changes any of them
|
|
@@ -14352,9 +14872,11 @@ var TargetKindSchema = object({
|
|
|
14352
14872
|
caps: TargetKindCapsSchema
|
|
14353
14873
|
});
|
|
14354
14874
|
/**
|
|
14355
|
-
* A
|
|
14356
|
-
*
|
|
14357
|
-
*
|
|
14875
|
+
* A target as a provider's own code sees it (the notification-center bridge, the
|
|
14876
|
+
* send path): the flat record body split into the name, the switch and the
|
|
14877
|
+
* kind's fields. `config` holds secrets; a reader that serves it to a client
|
|
14878
|
+
* REDACTS secret fields (a presence marker only) — never round-trip a stored
|
|
14879
|
+
* secret to the UI.
|
|
14358
14880
|
*/
|
|
14359
14881
|
var TargetSchema = object({
|
|
14360
14882
|
id: string(),
|
|
@@ -14397,13 +14919,13 @@ var ProbeTargetConfigResultSchema = object({
|
|
|
14397
14919
|
stateInstance: string().optional(),
|
|
14398
14920
|
error: string().optional()
|
|
14399
14921
|
});
|
|
14400
|
-
method(object({}), array(TargetKindSchema)), method(object({
|
|
14922
|
+
method(object({}), array(TargetKindSchema)), method(object({
|
|
14401
14923
|
kind: string(),
|
|
14402
14924
|
config: record(string(), unknown()).optional(),
|
|
14403
14925
|
/**
|
|
14404
14926
|
* When editing / duplicating, the blank password field never round-trips
|
|
14405
14927
|
* the stored token. Pass the source target id so the provider can restore
|
|
14406
|
-
* secrets server-side before dialling
|
|
14928
|
+
* secrets server-side before dialling.
|
|
14407
14929
|
*/
|
|
14408
14930
|
targetId: string().optional()
|
|
14409
14931
|
}), array(DiscoveredTargetSchema), { auth: "admin" }), method(object({
|
|
@@ -14426,27 +14948,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
|
|
|
14426
14948
|
}), TestResultSchema, {
|
|
14427
14949
|
kind: "mutation",
|
|
14428
14950
|
auth: "admin"
|
|
14429
|
-
}), method(object({
|
|
14430
|
-
target: TargetSchema,
|
|
14431
|
-
/**
|
|
14432
|
-
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
14433
|
-
* existing row. The UI never holds the stored token; blank / redacted
|
|
14434
|
-
* password fields are restored from this source (D634 still applies if
|
|
14435
|
-
* destinations diverge without a re-typed secret).
|
|
14436
|
-
*/
|
|
14437
|
-
cloneSecretsFrom: string().optional()
|
|
14438
|
-
}), TargetSchema, {
|
|
14439
|
-
kind: "mutation",
|
|
14440
|
-
auth: "admin"
|
|
14441
|
-
}), method(object({ targetId: string() }), _void(), {
|
|
14442
|
-
kind: "mutation",
|
|
14443
|
-
auth: "admin"
|
|
14444
|
-
}), method(object({
|
|
14445
|
-
targetId: string(),
|
|
14446
|
-
enabled: boolean()
|
|
14447
|
-
}), _void(), {
|
|
14448
|
-
kind: "mutation",
|
|
14449
|
-
auth: "admin"
|
|
14450
14951
|
});
|
|
14451
14952
|
looseObject({
|
|
14452
14953
|
name: string().min(1),
|
|
@@ -22714,7 +23215,6 @@ var SYSTEM_CAP_VOCABULARY = {
|
|
|
22714
23215
|
"notification-output": system("notification delivery — reached through notifier devices and rules"),
|
|
22715
23216
|
"notification-rules": system("notification rules — authored on their own page"),
|
|
22716
23217
|
"oauth-integration": system(IDENTITY),
|
|
22717
|
-
"oidc-connections": system(IDENTITY),
|
|
22718
23218
|
"osd-manager": system(PIPELINE),
|
|
22719
23219
|
"pipeline-executor": system(PIPELINE),
|
|
22720
23220
|
"pipeline-orchestrator": system(PIPELINE),
|
|
@@ -42735,6 +43235,7 @@ var ExpressionBindingSourceSchema = union([
|
|
|
42735
43235
|
object({
|
|
42736
43236
|
kind: literal("global"),
|
|
42737
43237
|
sourceStableId: string(),
|
|
43238
|
+
addonId: string().optional(),
|
|
42738
43239
|
cap: string(),
|
|
42739
43240
|
fieldPath: string()
|
|
42740
43241
|
})
|
|
@@ -42801,385 +43302,6 @@ var SourceInfoSchema = object({
|
|
|
42801
43302
|
raw: record(string(), unknown()).optional()
|
|
42802
43303
|
});
|
|
42803
43304
|
/**
|
|
42804
|
-
* Frozen unit → spec table. `•` in the doc marks each dimension's canonical
|
|
42805
|
-
* unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
|
|
42806
|
-
* `factor = 5/9`, `offset = -160/9` (kept as exact expressions, not rounded
|
|
42807
|
-
* decimals). K derives from `°C = K − 273.15`.
|
|
42808
|
-
*/
|
|
42809
|
-
var UNIT_TABLE = {
|
|
42810
|
-
"°C": {
|
|
42811
|
-
dimension: "temperature",
|
|
42812
|
-
factor: 1,
|
|
42813
|
-
offset: 0
|
|
42814
|
-
},
|
|
42815
|
-
"°F": {
|
|
42816
|
-
dimension: "temperature",
|
|
42817
|
-
factor: 5 / 9,
|
|
42818
|
-
offset: -160 / 9
|
|
42819
|
-
},
|
|
42820
|
-
K: {
|
|
42821
|
-
dimension: "temperature",
|
|
42822
|
-
factor: 1,
|
|
42823
|
-
offset: -273.15
|
|
42824
|
-
},
|
|
42825
|
-
hPa: {
|
|
42826
|
-
dimension: "pressure",
|
|
42827
|
-
factor: 1,
|
|
42828
|
-
offset: 0
|
|
42829
|
-
},
|
|
42830
|
-
kPa: {
|
|
42831
|
-
dimension: "pressure",
|
|
42832
|
-
factor: 10,
|
|
42833
|
-
offset: 0
|
|
42834
|
-
},
|
|
42835
|
-
Pa: {
|
|
42836
|
-
dimension: "pressure",
|
|
42837
|
-
factor: .01,
|
|
42838
|
-
offset: 0
|
|
42839
|
-
},
|
|
42840
|
-
mbar: {
|
|
42841
|
-
dimension: "pressure",
|
|
42842
|
-
factor: 1,
|
|
42843
|
-
offset: 0
|
|
42844
|
-
},
|
|
42845
|
-
bar: {
|
|
42846
|
-
dimension: "pressure",
|
|
42847
|
-
factor: 1e3,
|
|
42848
|
-
offset: 0
|
|
42849
|
-
},
|
|
42850
|
-
inHg: {
|
|
42851
|
-
dimension: "pressure",
|
|
42852
|
-
factor: 33.8639,
|
|
42853
|
-
offset: 0
|
|
42854
|
-
},
|
|
42855
|
-
mmHg: {
|
|
42856
|
-
dimension: "pressure",
|
|
42857
|
-
factor: 1.33322,
|
|
42858
|
-
offset: 0
|
|
42859
|
-
},
|
|
42860
|
-
psi: {
|
|
42861
|
-
dimension: "pressure",
|
|
42862
|
-
factor: 68.9476,
|
|
42863
|
-
offset: 0
|
|
42864
|
-
},
|
|
42865
|
-
"m/s": {
|
|
42866
|
-
dimension: "speed",
|
|
42867
|
-
factor: 1,
|
|
42868
|
-
offset: 0
|
|
42869
|
-
},
|
|
42870
|
-
"km/h": {
|
|
42871
|
-
dimension: "speed",
|
|
42872
|
-
factor: 1 / 3.6,
|
|
42873
|
-
offset: 0
|
|
42874
|
-
},
|
|
42875
|
-
mph: {
|
|
42876
|
-
dimension: "speed",
|
|
42877
|
-
factor: .44704,
|
|
42878
|
-
offset: 0
|
|
42879
|
-
},
|
|
42880
|
-
kn: {
|
|
42881
|
-
dimension: "speed",
|
|
42882
|
-
factor: .514444,
|
|
42883
|
-
offset: 0
|
|
42884
|
-
},
|
|
42885
|
-
"mm/h": {
|
|
42886
|
-
dimension: "precipitation-rate",
|
|
42887
|
-
factor: 1,
|
|
42888
|
-
offset: 0
|
|
42889
|
-
},
|
|
42890
|
-
"in/h": {
|
|
42891
|
-
dimension: "precipitation-rate",
|
|
42892
|
-
factor: 25.4,
|
|
42893
|
-
offset: 0
|
|
42894
|
-
},
|
|
42895
|
-
m: {
|
|
42896
|
-
dimension: "length",
|
|
42897
|
-
factor: 1,
|
|
42898
|
-
offset: 0
|
|
42899
|
-
},
|
|
42900
|
-
mm: {
|
|
42901
|
-
dimension: "length",
|
|
42902
|
-
factor: .001,
|
|
42903
|
-
offset: 0
|
|
42904
|
-
},
|
|
42905
|
-
cm: {
|
|
42906
|
-
dimension: "length",
|
|
42907
|
-
factor: .01,
|
|
42908
|
-
offset: 0
|
|
42909
|
-
},
|
|
42910
|
-
km: {
|
|
42911
|
-
dimension: "length",
|
|
42912
|
-
factor: 1e3,
|
|
42913
|
-
offset: 0
|
|
42914
|
-
},
|
|
42915
|
-
in: {
|
|
42916
|
-
dimension: "length",
|
|
42917
|
-
factor: .0254,
|
|
42918
|
-
offset: 0
|
|
42919
|
-
},
|
|
42920
|
-
ft: {
|
|
42921
|
-
dimension: "length",
|
|
42922
|
-
factor: .3048,
|
|
42923
|
-
offset: 0
|
|
42924
|
-
},
|
|
42925
|
-
mi: {
|
|
42926
|
-
dimension: "length",
|
|
42927
|
-
factor: 1609.344,
|
|
42928
|
-
offset: 0
|
|
42929
|
-
},
|
|
42930
|
-
"m²": {
|
|
42931
|
-
dimension: "area",
|
|
42932
|
-
factor: 1,
|
|
42933
|
-
offset: 0
|
|
42934
|
-
},
|
|
42935
|
-
lx: {
|
|
42936
|
-
dimension: "illuminance",
|
|
42937
|
-
factor: 1,
|
|
42938
|
-
offset: 0
|
|
42939
|
-
},
|
|
42940
|
-
"W/m²": {
|
|
42941
|
-
dimension: "irradiance",
|
|
42942
|
-
factor: 1,
|
|
42943
|
-
offset: 0
|
|
42944
|
-
},
|
|
42945
|
-
W: {
|
|
42946
|
-
dimension: "power",
|
|
42947
|
-
factor: 1,
|
|
42948
|
-
offset: 0
|
|
42949
|
-
},
|
|
42950
|
-
kW: {
|
|
42951
|
-
dimension: "power",
|
|
42952
|
-
factor: 1e3,
|
|
42953
|
-
offset: 0
|
|
42954
|
-
},
|
|
42955
|
-
VA: {
|
|
42956
|
-
dimension: "apparent-power",
|
|
42957
|
-
factor: 1,
|
|
42958
|
-
offset: 0
|
|
42959
|
-
},
|
|
42960
|
-
Wh: {
|
|
42961
|
-
dimension: "energy",
|
|
42962
|
-
factor: 1,
|
|
42963
|
-
offset: 0
|
|
42964
|
-
},
|
|
42965
|
-
kWh: {
|
|
42966
|
-
dimension: "energy",
|
|
42967
|
-
factor: 1e3,
|
|
42968
|
-
offset: 0
|
|
42969
|
-
},
|
|
42970
|
-
MWh: {
|
|
42971
|
-
dimension: "energy",
|
|
42972
|
-
factor: 1e6,
|
|
42973
|
-
offset: 0
|
|
42974
|
-
},
|
|
42975
|
-
V: {
|
|
42976
|
-
dimension: "voltage",
|
|
42977
|
-
factor: 1,
|
|
42978
|
-
offset: 0
|
|
42979
|
-
},
|
|
42980
|
-
mV: {
|
|
42981
|
-
dimension: "voltage",
|
|
42982
|
-
factor: .001,
|
|
42983
|
-
offset: 0
|
|
42984
|
-
},
|
|
42985
|
-
A: {
|
|
42986
|
-
dimension: "current",
|
|
42987
|
-
factor: 1,
|
|
42988
|
-
offset: 0
|
|
42989
|
-
},
|
|
42990
|
-
mA: {
|
|
42991
|
-
dimension: "current",
|
|
42992
|
-
factor: .001,
|
|
42993
|
-
offset: 0
|
|
42994
|
-
},
|
|
42995
|
-
ppm: {
|
|
42996
|
-
dimension: "concentration-volume",
|
|
42997
|
-
factor: 1,
|
|
42998
|
-
offset: 0
|
|
42999
|
-
},
|
|
43000
|
-
ppb: {
|
|
43001
|
-
dimension: "concentration-volume",
|
|
43002
|
-
factor: .001,
|
|
43003
|
-
offset: 0
|
|
43004
|
-
},
|
|
43005
|
-
"µg/m³": {
|
|
43006
|
-
dimension: "concentration-mass",
|
|
43007
|
-
factor: 1,
|
|
43008
|
-
offset: 0
|
|
43009
|
-
},
|
|
43010
|
-
"mg/m³": {
|
|
43011
|
-
dimension: "concentration-mass",
|
|
43012
|
-
factor: 1e3,
|
|
43013
|
-
offset: 0
|
|
43014
|
-
},
|
|
43015
|
-
kg: {
|
|
43016
|
-
dimension: "mass",
|
|
43017
|
-
factor: 1,
|
|
43018
|
-
offset: 0
|
|
43019
|
-
},
|
|
43020
|
-
g: {
|
|
43021
|
-
dimension: "mass",
|
|
43022
|
-
factor: .001,
|
|
43023
|
-
offset: 0
|
|
43024
|
-
},
|
|
43025
|
-
lb: {
|
|
43026
|
-
dimension: "mass",
|
|
43027
|
-
factor: .453592,
|
|
43028
|
-
offset: 0
|
|
43029
|
-
},
|
|
43030
|
-
oz: {
|
|
43031
|
-
dimension: "mass",
|
|
43032
|
-
factor: .0283495,
|
|
43033
|
-
offset: 0
|
|
43034
|
-
},
|
|
43035
|
-
"%": {
|
|
43036
|
-
dimension: "percentage",
|
|
43037
|
-
factor: 1,
|
|
43038
|
-
offset: 0
|
|
43039
|
-
},
|
|
43040
|
-
L: {
|
|
43041
|
-
dimension: "volume",
|
|
43042
|
-
factor: 1,
|
|
43043
|
-
offset: 0
|
|
43044
|
-
},
|
|
43045
|
-
mL: {
|
|
43046
|
-
dimension: "volume",
|
|
43047
|
-
factor: .001,
|
|
43048
|
-
offset: 0
|
|
43049
|
-
},
|
|
43050
|
-
gal: {
|
|
43051
|
-
dimension: "volume",
|
|
43052
|
-
factor: 3.785411784,
|
|
43053
|
-
offset: 0
|
|
43054
|
-
},
|
|
43055
|
-
s: {
|
|
43056
|
-
dimension: "duration",
|
|
43057
|
-
factor: 1,
|
|
43058
|
-
offset: 0
|
|
43059
|
-
},
|
|
43060
|
-
ms: {
|
|
43061
|
-
dimension: "duration",
|
|
43062
|
-
factor: .001,
|
|
43063
|
-
offset: 0
|
|
43064
|
-
},
|
|
43065
|
-
min: {
|
|
43066
|
-
dimension: "duration",
|
|
43067
|
-
factor: 60,
|
|
43068
|
-
offset: 0
|
|
43069
|
-
},
|
|
43070
|
-
h: {
|
|
43071
|
-
dimension: "duration",
|
|
43072
|
-
factor: 3600,
|
|
43073
|
-
offset: 0
|
|
43074
|
-
},
|
|
43075
|
-
d: {
|
|
43076
|
-
dimension: "duration",
|
|
43077
|
-
factor: 86400,
|
|
43078
|
-
offset: 0
|
|
43079
|
-
},
|
|
43080
|
-
B: {
|
|
43081
|
-
dimension: "information",
|
|
43082
|
-
factor: 1,
|
|
43083
|
-
offset: 0
|
|
43084
|
-
},
|
|
43085
|
-
KiB: {
|
|
43086
|
-
dimension: "information",
|
|
43087
|
-
factor: 1024,
|
|
43088
|
-
offset: 0
|
|
43089
|
-
},
|
|
43090
|
-
MiB: {
|
|
43091
|
-
dimension: "information",
|
|
43092
|
-
factor: 1024 ** 2,
|
|
43093
|
-
offset: 0
|
|
43094
|
-
},
|
|
43095
|
-
GiB: {
|
|
43096
|
-
dimension: "information",
|
|
43097
|
-
factor: 1024 ** 3,
|
|
43098
|
-
offset: 0
|
|
43099
|
-
},
|
|
43100
|
-
TiB: {
|
|
43101
|
-
dimension: "information",
|
|
43102
|
-
factor: 1024 ** 4,
|
|
43103
|
-
offset: 0
|
|
43104
|
-
},
|
|
43105
|
-
kB: {
|
|
43106
|
-
dimension: "information",
|
|
43107
|
-
factor: 1e3,
|
|
43108
|
-
offset: 0
|
|
43109
|
-
},
|
|
43110
|
-
MB: {
|
|
43111
|
-
dimension: "information",
|
|
43112
|
-
factor: 1e6,
|
|
43113
|
-
offset: 0
|
|
43114
|
-
},
|
|
43115
|
-
GB: {
|
|
43116
|
-
dimension: "information",
|
|
43117
|
-
factor: 1e9,
|
|
43118
|
-
offset: 0
|
|
43119
|
-
},
|
|
43120
|
-
"°": {
|
|
43121
|
-
dimension: "angle",
|
|
43122
|
-
factor: 1,
|
|
43123
|
-
offset: 0
|
|
43124
|
-
},
|
|
43125
|
-
dBFS: {
|
|
43126
|
-
dimension: "sound-level",
|
|
43127
|
-
factor: 1,
|
|
43128
|
-
offset: 0
|
|
43129
|
-
},
|
|
43130
|
-
dBm: {
|
|
43131
|
-
dimension: "signal-level",
|
|
43132
|
-
factor: 1,
|
|
43133
|
-
offset: 0
|
|
43134
|
-
},
|
|
43135
|
-
mired: {
|
|
43136
|
-
dimension: "colour-temperature",
|
|
43137
|
-
factor: 1,
|
|
43138
|
-
offset: 0
|
|
43139
|
-
},
|
|
43140
|
-
kbps: {
|
|
43141
|
-
dimension: "bitrate",
|
|
43142
|
-
factor: 1,
|
|
43143
|
-
offset: 0
|
|
43144
|
-
},
|
|
43145
|
-
Mbps: {
|
|
43146
|
-
dimension: "bitrate",
|
|
43147
|
-
factor: 1e3,
|
|
43148
|
-
offset: 0
|
|
43149
|
-
},
|
|
43150
|
-
fps: {
|
|
43151
|
-
dimension: "rate",
|
|
43152
|
-
factor: 1,
|
|
43153
|
-
offset: 0
|
|
43154
|
-
}
|
|
43155
|
-
};
|
|
43156
|
-
/** Resolve a unit's `UnitSpec`, or `undefined` when the spelling is unknown. */
|
|
43157
|
-
function specFor(unit) {
|
|
43158
|
-
return Object.hasOwn(UNIT_TABLE, unit) ? UNIT_TABLE[unit] : void 0;
|
|
43159
|
-
}
|
|
43160
|
-
/** Value in `spec`'s unit → its dimension's canonical unit. */
|
|
43161
|
-
function toCanonical(value, spec) {
|
|
43162
|
-
return value * spec.factor + spec.offset;
|
|
43163
|
-
}
|
|
43164
|
-
/** Canonical-unit value → the unit described by `spec`. */
|
|
43165
|
-
function fromCanonical(canonical, spec) {
|
|
43166
|
-
return (canonical - spec.offset) / spec.factor;
|
|
43167
|
-
}
|
|
43168
|
-
/**
|
|
43169
|
-
* Graceful variant for the render path: returns the converted value, or
|
|
43170
|
-
* `undefined` when the conversion is refused (unknown unit / cross-dimension).
|
|
43171
|
-
* Never throws — a render caller falls back to the raw value + source unit.
|
|
43172
|
-
*/
|
|
43173
|
-
function tryConvertUnit(value, from, to) {
|
|
43174
|
-
if (from === to) return value;
|
|
43175
|
-
const fromSpec = specFor(from);
|
|
43176
|
-
if (!fromSpec) return void 0;
|
|
43177
|
-
const toSpec = specFor(to);
|
|
43178
|
-
if (!toSpec) return void 0;
|
|
43179
|
-
if (fromSpec.dimension !== toSpec.dimension) return void 0;
|
|
43180
|
-
return fromCanonical(toCanonical(value, fromSpec), toSpec);
|
|
43181
|
-
}
|
|
43182
|
-
/**
|
|
43183
43305
|
* A number a person types for a physical quantity — the input side of the
|
|
43184
43306
|
* value + unit contract (D972).
|
|
43185
43307
|
*
|
|
@@ -44856,15 +44978,28 @@ var SettingsSchemaWithValuesSchema = object({
|
|
|
44856
44978
|
});
|
|
44857
44979
|
/** Patch object — keys are field names, values are the new field values. */
|
|
44858
44980
|
var SettingsPatchSchema = record(string(), unknown());
|
|
44981
|
+
/** The scope of a scoped-settings call (D986): where the capability declared the values. */
|
|
44982
|
+
var ScopedSettingsScopeSchema = _enum(SCOPED_SETTINGS_SCOPES);
|
|
44983
|
+
/** One scoped schema an addon serves: its capability, scope and section ids. */
|
|
44984
|
+
var ScopedSettingsDeclarationSchema = object({
|
|
44985
|
+
cap: string(),
|
|
44986
|
+
scope: ScopedSettingsScopeSchema,
|
|
44987
|
+
sectionIds: array(string())
|
|
44988
|
+
});
|
|
44859
44989
|
/** Standard success response for update operations. */
|
|
44860
44990
|
var SettingsUpdateResultSchema = object({ success: literal(true) });
|
|
44861
44991
|
method(object({
|
|
44862
44992
|
addonId: string(),
|
|
44863
|
-
|
|
44864
|
-
|
|
44865
|
-
|
|
44993
|
+
cap: string(),
|
|
44994
|
+
scope: ScopedSettingsScopeSchema,
|
|
44995
|
+
nodeId: string().optional()
|
|
44866
44996
|
}), SettingsSchemaWithValuesSchema.nullable()), method(object({
|
|
44867
44997
|
addonId: string(),
|
|
44998
|
+
nodeId: string().optional()
|
|
44999
|
+
}), array(ScopedSettingsDeclarationSchema).nullable()), method(object({
|
|
45000
|
+
addonId: string(),
|
|
45001
|
+
cap: string(),
|
|
45002
|
+
scope: ScopedSettingsScopeSchema,
|
|
44868
45003
|
nodeId: string().optional(),
|
|
44869
45004
|
patch: SettingsPatchSchema
|
|
44870
45005
|
}), SettingsUpdateResultSchema, {
|
|
@@ -44872,8 +45007,10 @@ method(object({
|
|
|
44872
45007
|
auth: "admin"
|
|
44873
45008
|
}), method(object({
|
|
44874
45009
|
addonId: string(),
|
|
45010
|
+
cap: string(),
|
|
45011
|
+
scope: ScopedSettingsScopeSchema,
|
|
44875
45012
|
nodeId: string().optional()
|
|
44876
|
-
}),
|
|
45013
|
+
}), record(string(), unknown()).nullable()), method(object({
|
|
44877
45014
|
addonId: string(),
|
|
44878
45015
|
nodeId: string().optional(),
|
|
44879
45016
|
instance: IntegrationInstanceRefSchema
|
|
@@ -46213,7 +46350,7 @@ var BackupDestinationInfoSchema = object({
|
|
|
46213
46350
|
id: string(),
|
|
46214
46351
|
/**
|
|
46215
46352
|
* Manifest id of the owning addon. The Settings button on the
|
|
46216
|
-
* destination card opens that addon's
|
|
46353
|
+
* destination card opens that addon's scoped settings panel.
|
|
46217
46354
|
*/
|
|
46218
46355
|
addonId: string(),
|
|
46219
46356
|
/** Operator-toggled enable flag from the destination-policy table. */
|
|
@@ -50683,6 +50820,7 @@ method(InstancePinSchema, DeviceExportStatusSchema), method(_void(), array(Expor
|
|
|
50683
50820
|
kind: "mutation",
|
|
50684
50821
|
auth: "admin"
|
|
50685
50822
|
});
|
|
50823
|
+
var DeviceAliasSchema = string().max(64).regex(/^[a-z][a-z0-9_]*$/);
|
|
50686
50824
|
/**
|
|
50687
50825
|
* A SITE ZONE — a named part of the property that several locations belong to.
|
|
50688
50826
|
*
|
|
@@ -51076,6 +51214,12 @@ var DeviceInfoSchema = object({
|
|
|
51076
51214
|
addonId: string(),
|
|
51077
51215
|
type: _enum(DeviceType),
|
|
51078
51216
|
name: string(),
|
|
51217
|
+
/** The name a value template uses for this device (`{{ stufa_veranda.temperature }}`),
|
|
51218
|
+
* entity_id style. Generated once from the name at first registration, unique
|
|
51219
|
+
* cluster-wide, editable through `setAlias`, NOT changed by a rename (D1021).
|
|
51220
|
+
* Optional: a record produced by an older build omits it until the boot
|
|
51221
|
+
* backfill has run. */
|
|
51222
|
+
alias: DeviceAliasSchema.optional(),
|
|
51079
51223
|
/** Operator-organisational location label. `null` when unset. */
|
|
51080
51224
|
location: string().nullable(),
|
|
51081
51225
|
/** Soft-disabled flag. */
|
|
@@ -51395,6 +51539,25 @@ method(object({
|
|
|
51395
51539
|
}), _void(), {
|
|
51396
51540
|
kind: "mutation",
|
|
51397
51541
|
auth: "admin"
|
|
51542
|
+
}), method(object({
|
|
51543
|
+
deviceId: number(),
|
|
51544
|
+
alias: string()
|
|
51545
|
+
}), discriminatedUnion("ok", [object({
|
|
51546
|
+
ok: literal(true),
|
|
51547
|
+
alias: DeviceAliasSchema
|
|
51548
|
+
}), object({
|
|
51549
|
+
ok: literal(false),
|
|
51550
|
+
reason: _enum([
|
|
51551
|
+
"empty",
|
|
51552
|
+
"too-long",
|
|
51553
|
+
"grammar",
|
|
51554
|
+
"reserved",
|
|
51555
|
+
"taken"
|
|
51556
|
+
]),
|
|
51557
|
+
takenBy: number().optional()
|
|
51558
|
+
})]), {
|
|
51559
|
+
kind: "mutation",
|
|
51560
|
+
auth: "admin"
|
|
51398
51561
|
}), method(object({
|
|
51399
51562
|
deviceId: number(),
|
|
51400
51563
|
location: string().nullable()
|
|
@@ -54420,7 +54583,7 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
|
|
|
54420
54583
|
* or the redaction token KEEPS the stored secret; `{ $secretClear: true }`
|
|
54421
54584
|
* clears it.
|
|
54422
54585
|
*/
|
|
54423
|
-
var ConfigSchemaPassthrough$
|
|
54586
|
+
var ConfigSchemaPassthrough$2 = custom();
|
|
54424
54587
|
var IntegrationInstanceIdSchema = string().min(1);
|
|
54425
54588
|
var IntegrationInstanceModeSchema = _enum(["single", "multiple"]);
|
|
54426
54589
|
/**
|
|
@@ -54466,7 +54629,16 @@ var IntegrationInstanceKindSchema = object({
|
|
|
54466
54629
|
/** Relative hub path to start an interactive account link of an instance of this kind. */
|
|
54467
54630
|
connectPath: string().min(1).optional(),
|
|
54468
54631
|
/** Relative hub path to disconnect that account. */
|
|
54469
|
-
disconnectPath: string().min(1).optional()
|
|
54632
|
+
disconnectPath: string().min(1).optional(),
|
|
54633
|
+
/**
|
|
54634
|
+
* Parts of the edit dialog the flat form cannot draw (a node picker, a model source), named by a
|
|
54635
|
+
* GENERIC widget id the client maps to a component; a client that knows none of them shows none.
|
|
54636
|
+
* `connection` widgets write connection values, `model` widgets own the model choice.
|
|
54637
|
+
*/
|
|
54638
|
+
widgets: array(object({
|
|
54639
|
+
id: string().min(1),
|
|
54640
|
+
placement: _enum(["connection", "model"])
|
|
54641
|
+
})).optional()
|
|
54470
54642
|
});
|
|
54471
54643
|
/**
|
|
54472
54644
|
* How devices of an instance are found. `none`: the operator adds them by hand; `lan`: the addon
|
|
@@ -54571,7 +54743,7 @@ var integrationInstancesCapability = {
|
|
|
54571
54743
|
id: IntegrationInstanceIdSchema.nullable(),
|
|
54572
54744
|
/** The kind of the create form (`id: null`) of a provider with several. */
|
|
54573
54745
|
kind: string().min(1).optional()
|
|
54574
|
-
}), ConfigSchemaPassthrough$
|
|
54746
|
+
}), ConfigSchemaPassthrough$2, { auth: "admin" }),
|
|
54575
54747
|
listInstances: method(_void(), array(IntegrationInstanceSchema).readonly(), { auth: "admin" }),
|
|
54576
54748
|
getInstance: method(object({ id: IntegrationInstanceIdSchema }), IntegrationInstanceSchema.nullable(), { auth: "admin" }),
|
|
54577
54749
|
/**
|
|
@@ -55522,12 +55694,12 @@ var LlmModelInfoSchema = object({
|
|
|
55522
55694
|
});
|
|
55523
55695
|
/**
|
|
55524
55696
|
* The provider-specific part of a profile, validated by the provider that owns
|
|
55525
|
-
* the kind (
|
|
55697
|
+
* the kind (saving an instance refuses what it does not accept). A field its
|
|
55526
55698
|
* `connectionSchema` declares `type: 'password'` is a secret: it is held in the
|
|
55527
55699
|
* keychain, never in the row, and reads back as the redaction marker.
|
|
55528
55700
|
*/
|
|
55529
55701
|
var LlmProviderConfigSchema = record(string(), unknown());
|
|
55530
|
-
|
|
55702
|
+
object({
|
|
55531
55703
|
id: string(),
|
|
55532
55704
|
name: string(),
|
|
55533
55705
|
/** The provider-declared kind (`LlmProfileKindDescriptor.kind`). */
|
|
@@ -55621,8 +55793,8 @@ var LlmProviderWidgetSchema = object({
|
|
|
55621
55793
|
/** ConfigUISchema tree passed through untyped on the wire (the
|
|
55622
55794
|
* notification-output `ConfigSchemaPassthrough` precedent at
|
|
55623
55795
|
* notification-output.cap.ts:151); the exported TS type re-tightens it. */
|
|
55624
|
-
var ConfigSchemaPassthrough$
|
|
55625
|
-
|
|
55796
|
+
var ConfigSchemaPassthrough$1 = unknown();
|
|
55797
|
+
object({
|
|
55626
55798
|
kind: LlmProfileKindSchema,
|
|
55627
55799
|
label: string(),
|
|
55628
55800
|
/** A generic icon name (`cloud`, `plug`, `cpu`) — never a glyph or a logo. */
|
|
@@ -55630,9 +55802,9 @@ var LlmProfileKindDescriptorSchema = object({
|
|
|
55630
55802
|
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
55631
55803
|
addonId: string(),
|
|
55632
55804
|
/** The provider's own fields (`providerConfig`); `password` fields are keychain-held. */
|
|
55633
|
-
connectionSchema: ConfigSchemaPassthrough$
|
|
55805
|
+
connectionSchema: ConfigSchemaPassthrough$1,
|
|
55634
55806
|
/** Provider fields that belong under "Advanced" (extra headers, runtime tuning). */
|
|
55635
|
-
advancedSchema: ConfigSchemaPassthrough$
|
|
55807
|
+
advancedSchema: ConfigSchemaPassthrough$1.optional(),
|
|
55636
55808
|
/** The kind's defaults; a model from `listModels` may override any of them. */
|
|
55637
55809
|
features: LlmModelFeaturesSchema,
|
|
55638
55810
|
/** `false` = the provider stamps `supportsVision` itself (from what a node reports). */
|
|
@@ -55761,20 +55933,7 @@ method(LlmGenerateBaseInputSchema, LlmGenerateResultSchema, {
|
|
|
55761
55933
|
}), method(object({
|
|
55762
55934
|
addonId: string().optional(),
|
|
55763
55935
|
requestId: string()
|
|
55764
|
-
}), _void(), { kind: "mutation" }), method(
|
|
55765
|
-
kind: "mutation",
|
|
55766
|
-
auth: "admin"
|
|
55767
|
-
}), method(RawSecretMigrationInputSchema, RawSecretMigrationReportSchema, {
|
|
55768
|
-
kind: "mutation",
|
|
55769
|
-
auth: "admin"
|
|
55770
|
-
}), method(ProfileRefInputSchema, _void(), {
|
|
55771
|
-
kind: "mutation",
|
|
55772
|
-
auth: "admin"
|
|
55773
|
-
}), method(ProfileRefInputSchema, LlmGenerateResultSchema, {
|
|
55774
|
-
kind: "mutation",
|
|
55775
|
-
auth: "admin",
|
|
55776
|
-
timeoutMs: AI_CAP_TRANSPORT_TIMEOUT_MS
|
|
55777
|
-
}), method(LlmListModelsInputSchema, LlmListModelsResultSchema, {
|
|
55936
|
+
}), _void(), { kind: "mutation" }), method(LlmListModelsInputSchema, LlmListModelsResultSchema, {
|
|
55778
55937
|
kind: "mutation",
|
|
55779
55938
|
auth: "admin"
|
|
55780
55939
|
}), method(object({}), array(LlmDefaultSchema)), method(object({
|
|
@@ -56769,20 +56928,7 @@ method(_void(), MeshStatusSchema), method(object({
|
|
|
56769
56928
|
/** Optional hostname override the host should advertise once joined. */
|
|
56770
56929
|
hostname: string().optional() }), object({
|
|
56771
56930
|
/** Authentication URL the operator should open in a browser. */
|
|
56772
|
-
loginUrl: string() }), { kind: "mutation" }), method(_void(), object({ left: literal(true) }), { kind: "mutation" }), method(_void(), object({ loggedOut: literal(true) }), { kind: "mutation" }), method(_void(), object({ peers: array(MeshPeerSchema).readonly() }))
|
|
56773
|
-
/** Optional auth key — when provided, probes the key validity
|
|
56774
|
-
* against the provider's API. Omit when already joined to
|
|
56775
|
-
* just ping the daemon. */
|
|
56776
|
-
authKey: string().optional() }), object({
|
|
56777
|
-
ok: boolean(),
|
|
56778
|
-
/** Provider-side identifier resolved by the probe (tailnet
|
|
56779
|
-
* name for Tailscale, network id for ZeroTier, etc.). */
|
|
56780
|
-
tenant: string().optional(),
|
|
56781
|
-
/** Daemon binary version, when reachable. */
|
|
56782
|
-
daemonVersion: string().optional(),
|
|
56783
|
-
/** Human-readable error when `ok: false`. */
|
|
56784
|
-
error: string().optional()
|
|
56785
|
-
}), { kind: "mutation" });
|
|
56931
|
+
loginUrl: string() }), { kind: "mutation" }), method(_void(), object({ left: literal(true) }), { kind: "mutation" }), method(_void(), object({ loggedOut: literal(true) }), { kind: "mutation" }), method(_void(), object({ peers: array(MeshPeerSchema).readonly() }));
|
|
56786
56932
|
object({
|
|
56787
56933
|
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
56788
56934
|
lastFetchedAt: number()
|
|
@@ -64143,6 +64289,11 @@ var NcScheduleSchema = object({
|
|
|
64143
64289
|
* as a STATE SUMMARY at the end of each window of `schedule`.
|
|
64144
64290
|
*/
|
|
64145
64291
|
var NcSystemEventDeliveryModeSchema = _enum(["instant", "summary"]);
|
|
64292
|
+
_enum([
|
|
64293
|
+
"activation",
|
|
64294
|
+
"deactivation",
|
|
64295
|
+
"schedule"
|
|
64296
|
+
]);
|
|
64146
64297
|
/**
|
|
64147
64298
|
* How a summary window is SENT (D698): `rule` (absent) = ONE notification with
|
|
64148
64299
|
* every section; `section` = one notification per section with something to
|
|
@@ -64159,11 +64310,26 @@ var NcStateSummarySplitSchema = _enum(["rule", "section"]);
|
|
|
64159
64310
|
* midnight crossing); the send time is each window's END. Refused on the
|
|
64160
64311
|
* `alarm` family, which stays instant (`systemEventDeliveryProblems`).
|
|
64161
64312
|
*/
|
|
64162
|
-
var NcSystemEventDeliverySchema = discriminatedUnion("mode", [
|
|
64163
|
-
mode: literal("
|
|
64164
|
-
|
|
64165
|
-
|
|
64166
|
-
|
|
64313
|
+
var NcSystemEventDeliverySchema = discriminatedUnion("mode", [
|
|
64314
|
+
object({ mode: literal("instant") }),
|
|
64315
|
+
object({
|
|
64316
|
+
mode: literal("summary"),
|
|
64317
|
+
schedule: NcScheduleSchema,
|
|
64318
|
+
split: NcStateSummarySplitSchema.optional()
|
|
64319
|
+
}),
|
|
64320
|
+
object({
|
|
64321
|
+
mode: literal("modes"),
|
|
64322
|
+
/** The bad edge, and every kind that has a single edge. */
|
|
64323
|
+
onActivation: boolean(),
|
|
64324
|
+
/** The recovery edges of the classes of the selected kinds (derived, never stored per kind). */
|
|
64325
|
+
onDeactivation: boolean(),
|
|
64326
|
+
/** A state summary at the end of each window; absent = no summary. */
|
|
64327
|
+
onSchedule: object({
|
|
64328
|
+
schedule: NcScheduleSchema,
|
|
64329
|
+
grouping: NcStateSummarySplitSchema
|
|
64330
|
+
}).optional()
|
|
64331
|
+
})
|
|
64332
|
+
]);
|
|
64167
64333
|
/** Fuzzy plate matcher — OCR noise makes exact match useless (spec row 12/13). */
|
|
64168
64334
|
var NcPlateMatcherSchema = object({
|
|
64169
64335
|
/**
|
|
@@ -66440,61 +66606,6 @@ var OauthIntegrationDescriptorSchema = object({
|
|
|
66440
66606
|
});
|
|
66441
66607
|
method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
|
|
66442
66608
|
/**
|
|
66443
|
-
* `oidc-connections` — CRUD for IdP rows under `auth-oidc` (D828 sibling).
|
|
66444
|
-
*
|
|
66445
|
-
* One hub-only singleton (`auth-oidc`). The Settings UI is a DataTable +
|
|
66446
|
-
* ItemFormDialog; there is no `editable-array` in `globalSettingsSchema`.
|
|
66447
|
-
* Operator-chosen `id` is the URL slug (`/addon/auth-oidc/<id>/…`) and is
|
|
66448
|
-
* immutable after create.
|
|
66449
|
-
*/
|
|
66450
|
-
var ConfigSchemaPassthrough$1 = unknown();
|
|
66451
|
-
var OidcConnectionSchema = object({
|
|
66452
|
-
id: string().min(1),
|
|
66453
|
-
displayName: string(),
|
|
66454
|
-
icon: string(),
|
|
66455
|
-
issuerUrl: string(),
|
|
66456
|
-
clientId: string(),
|
|
66457
|
-
/** Client id + secret present — never the secret value. */
|
|
66458
|
-
configured: boolean(),
|
|
66459
|
-
/**
|
|
66460
|
-
* Values for the connection form schema. `clientSecret` is a keychain
|
|
66461
|
-
* {@link SecretFieldView} or `null` / `''`, never plaintext (D789).
|
|
66462
|
-
*/
|
|
66463
|
-
formValues: record(string(), unknown()).optional()
|
|
66464
|
-
});
|
|
66465
|
-
/**
|
|
66466
|
-
* Patch one connection. Omitted or empty `clientSecret` keeps the stored
|
|
66467
|
-
* secret (D787). `{ $secretClear: true }` clears it. `id` is never renamed.
|
|
66468
|
-
*/
|
|
66469
|
-
var OidcConnectionUpdateInputSchema = object({
|
|
66470
|
-
id: string().min(1),
|
|
66471
|
-
displayName: string().min(1),
|
|
66472
|
-
icon: string().optional(),
|
|
66473
|
-
issuerUrl: string().optional(),
|
|
66474
|
-
clientId: string().optional(),
|
|
66475
|
-
clientSecret: union([string(), object({ $secretClear: literal(true) })]).optional(),
|
|
66476
|
-
redirectUri: string().optional(),
|
|
66477
|
-
scopes: string().optional(),
|
|
66478
|
-
usernameClaim: _enum([
|
|
66479
|
-
"preferred_username",
|
|
66480
|
-
"email",
|
|
66481
|
-
"sub"
|
|
66482
|
-
]).optional()
|
|
66483
|
-
});
|
|
66484
|
-
method(object({}), ConfigSchemaPassthrough$1, { auth: "admin" }), method(object({}), array(OidcConnectionSchema).readonly(), { auth: "admin" }), method(object({
|
|
66485
|
-
id: string().min(1).regex(/^[a-z0-9][a-z0-9-]{0,63}$/, "id must be a lowercase slug"),
|
|
66486
|
-
displayName: string().min(1)
|
|
66487
|
-
}), object({ id: string() }), {
|
|
66488
|
-
kind: "mutation",
|
|
66489
|
-
auth: "admin"
|
|
66490
|
-
}), method(OidcConnectionUpdateInputSchema, object({ ok: literal(true) }), {
|
|
66491
|
-
kind: "mutation",
|
|
66492
|
-
auth: "admin"
|
|
66493
|
-
}), method(object({ id: string().min(1) }), object({ ok: literal(true) }), {
|
|
66494
|
-
kind: "mutation",
|
|
66495
|
-
auth: "admin"
|
|
66496
|
-
});
|
|
66497
|
-
/**
|
|
66498
66609
|
* Generic on-screen-display (video overlay) cap. Each camera exposes
|
|
66499
66610
|
* a firmware-defined list of overlays (channel name, timestamp,
|
|
66500
66611
|
* watermark, logo, …); the cap models them as a homogeneous array of
|
|
@@ -72680,21 +72791,6 @@ method(object({
|
|
|
72680
72791
|
*/
|
|
72681
72792
|
ttlSec: union([number().int().positive(), literal("never")]).optional()
|
|
72682
72793
|
}), object({ token: string() }), { auth: "admin" }), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" });
|
|
72683
|
-
var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
|
|
72684
|
-
providerId: string().min(1),
|
|
72685
|
-
displayName: string().min(1),
|
|
72686
|
-
configSchema: unknown(),
|
|
72687
|
-
nodeLocal: boolean(),
|
|
72688
|
-
shouldSaveDiskSpace: literal(true),
|
|
72689
|
-
minFreePercent: number().min(0).max(100)
|
|
72690
|
-
}), object({
|
|
72691
|
-
providerId: string().min(1),
|
|
72692
|
-
displayName: string().min(1),
|
|
72693
|
-
configSchema: unknown(),
|
|
72694
|
-
nodeLocal: boolean(),
|
|
72695
|
-
shouldSaveDiskSpace: literal(false),
|
|
72696
|
-
minFreePercent: literal(null)
|
|
72697
|
-
})]);
|
|
72698
72794
|
method(object({
|
|
72699
72795
|
location: StorageLocationRefSchema,
|
|
72700
72796
|
relativePath: string()
|
|
@@ -72756,42 +72852,7 @@ method(object({
|
|
|
72756
72852
|
}), _instanceof(Uint8Array), { auth: "admin" }), method(object({ downloadId: string() }), _void(), {
|
|
72757
72853
|
kind: "mutation",
|
|
72758
72854
|
auth: "admin"
|
|
72759
|
-
}), method(object({ type: StorageLocationTypeSchema.optional() }), array(StorageLocationSchema).readonly()), method(_void(), array(StorageLocationDeclarationSchema).readonly()), method(
|
|
72760
|
-
createdAt: true,
|
|
72761
|
-
updatedAt: true
|
|
72762
|
-
}), StorageLocationSchema, {
|
|
72763
|
-
kind: "mutation",
|
|
72764
|
-
auth: "admin"
|
|
72765
|
-
}), method(object({
|
|
72766
|
-
id: string(),
|
|
72767
|
-
force: boolean().optional()
|
|
72768
|
-
}), _void(), {
|
|
72769
|
-
kind: "mutation",
|
|
72770
|
-
auth: "admin"
|
|
72771
|
-
}), method(_void(), array(StorageDrainProgressSchema).readonly()), method(object({ id: string() }), object({
|
|
72772
|
-
ok: boolean(),
|
|
72773
|
-
error: string().optional()
|
|
72774
|
-
}), { auth: "admin" }), method(_void(), array(ProviderListEntrySchema).readonly()), method(object({
|
|
72775
|
-
providerId: string(),
|
|
72776
|
-
/**
|
|
72777
|
-
* The location this config is an UNSAVED edit of, when there is one.
|
|
72778
|
-
*
|
|
72779
|
-
* `listLocations` replaces every declared secret with the redaction
|
|
72780
|
-
* sentinel, so the edit modal's form state holds the sentinel for any
|
|
72781
|
-
* credential the operator did not retype — and posting that here
|
|
72782
|
-
* without a way to resolve it makes the provider try to authenticate
|
|
72783
|
-
* as `__camstack_redacted__` and report the operator's own working
|
|
72784
|
-
* password as wrong. Given this id, the orchestrator restores each
|
|
72785
|
-
* sentinel from the stored config (same rule as `upsertLocation`)
|
|
72786
|
-
* before dispatching. Omitted by the "Add location" wizard, where
|
|
72787
|
-
* every value was typed just now and nothing is stored yet.
|
|
72788
|
-
*/
|
|
72789
|
-
locationId: string().optional(),
|
|
72790
|
-
config: record(string(), unknown())
|
|
72791
|
-
}), object({
|
|
72792
|
-
ok: boolean(),
|
|
72793
|
-
error: string().optional()
|
|
72794
|
-
}), { auth: "admin" });
|
|
72855
|
+
}), method(object({ type: StorageLocationTypeSchema.optional() }), array(StorageLocationSchema).readonly()), method(_void(), array(StorageLocationDeclarationSchema).readonly()), method(_void(), array(StorageDrainProgressSchema).readonly());
|
|
72795
72856
|
/** One table of the settings database. */
|
|
72796
72857
|
var StorageTableSchema = object({
|
|
72797
72858
|
/** The table's full name, e.g. `recorder:addon-settings` or `addon-device-settings`. */
|
|
@@ -74022,7 +74083,7 @@ var TerminalInstanceInfoSchema = object({
|
|
|
74022
74083
|
/**
|
|
74023
74084
|
* False while the node the instance is bound to is not in the cluster
|
|
74024
74085
|
* topology (forgotten, renamed, re-paired). The instance is kept; the
|
|
74025
|
-
* operator re-points it
|
|
74086
|
+
* operator re-points it on the Terminal page.
|
|
74026
74087
|
*/
|
|
74027
74088
|
nodeInCluster: boolean(),
|
|
74028
74089
|
profileId: string(),
|
|
@@ -74060,41 +74121,7 @@ var TerminalOutputBatchSchema = object({
|
|
|
74060
74121
|
snapshot: string().optional(),
|
|
74061
74122
|
events: array(TerminalOutputEventSchema).readonly()
|
|
74062
74123
|
});
|
|
74063
|
-
method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(
|
|
74064
|
-
targetNodeId: string().min(1),
|
|
74065
|
-
profileId: string().min(1),
|
|
74066
|
-
name: string().trim().min(1).max(160).optional(),
|
|
74067
|
-
executable: string().max(1024).optional(),
|
|
74068
|
-
args: array(string().max(2048)).max(64).optional(),
|
|
74069
|
-
cwd: string().max(1024).optional(),
|
|
74070
|
-
environment: array(string().max(4096)).max(64).optional(),
|
|
74071
|
-
profileSettings: ProfileSettingsBagSchema.optional()
|
|
74072
|
-
}), TerminalInstanceInfoSchema, {
|
|
74073
|
-
kind: "mutation",
|
|
74074
|
-
auth: "admin"
|
|
74075
|
-
}), method(object({
|
|
74076
|
-
instanceId: string().min(1),
|
|
74077
|
-
/** Re-point the instance to another node; the profile must exist there. */
|
|
74078
|
-
targetNodeId: string().min(1).max(256).optional(),
|
|
74079
|
-
name: string().trim().min(1).max(160).optional(),
|
|
74080
|
-
executable: string().max(1024).optional(),
|
|
74081
|
-
args: array(string().max(2048)).max(64).optional(),
|
|
74082
|
-
cwd: string().max(1024).optional(),
|
|
74083
|
-
environment: array(string().max(4096)).max(64).optional(),
|
|
74084
|
-
profileSettings: ProfileSettingsBagSchema.optional()
|
|
74085
|
-
}), TerminalInstanceInfoSchema, {
|
|
74086
|
-
kind: "mutation",
|
|
74087
|
-
auth: "admin"
|
|
74088
|
-
}), method(object({ instanceId: string().min(1) }), _void(), {
|
|
74089
|
-
kind: "mutation",
|
|
74090
|
-
auth: "admin"
|
|
74091
|
-
}), method(object({
|
|
74092
|
-
instanceId: string().min(1),
|
|
74093
|
-
enabled: boolean()
|
|
74094
|
-
}), TerminalInstanceInfoSchema, {
|
|
74095
|
-
kind: "mutation",
|
|
74096
|
-
auth: "admin"
|
|
74097
|
-
}), method(_void(), array(TerminalLegacyCameraSchema).readonly(), { auth: "admin" }), method(object({
|
|
74124
|
+
method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalLegacyCameraSchema).readonly(), { auth: "admin" }), method(object({
|
|
74098
74125
|
stableId: string().min(1),
|
|
74099
74126
|
name: string().trim().min(1).max(160).optional()
|
|
74100
74127
|
}), TerminalInstanceInfoSchema, {
|
|
@@ -74163,6 +74190,11 @@ var TimedRunUnitSchema = _enum(["s", "min"]);
|
|
|
74163
74190
|
_enum(["switch", "pet-fountain"]);
|
|
74164
74191
|
DeviceType.Heater, DeviceType.PetFountain;
|
|
74165
74192
|
DeviceType.Heater, DeviceType.PetFountain;
|
|
74193
|
+
/** One duration, as the one-tap run asks for it. */
|
|
74194
|
+
var TimedRunQuickRunSchema = object({
|
|
74195
|
+
duration: number().positive().finite(),
|
|
74196
|
+
unit: TimedRunUnitSchema
|
|
74197
|
+
});
|
|
74166
74198
|
/** Why a request was not carried out. Typed, so a caller can say it in words. */
|
|
74167
74199
|
var TimedRunRefusalSchema = _enum([
|
|
74168
74200
|
"unsupported-device",
|
|
@@ -74183,9 +74215,30 @@ object({
|
|
|
74183
74215
|
activeUntil: number().nullable(),
|
|
74184
74216
|
/** Who asked for the run (a user id or an addon id); `null` when nothing is armed or it did not say. */
|
|
74185
74217
|
requestedBy: string().nullable(),
|
|
74218
|
+
/**
|
|
74219
|
+
* The one-tap run of THIS device: what a "Run" button on any surface starts. `null` when
|
|
74220
|
+
* the device is gone or its type has no timed run; a status from before this field
|
|
74221
|
+
* existed has none, and a surface falls back to the type's default.
|
|
74222
|
+
*/
|
|
74223
|
+
quickRun: TimedRunQuickRunSchema.nullable(),
|
|
74186
74224
|
lastFetchedAt: number()
|
|
74187
74225
|
});
|
|
74188
|
-
|
|
74226
|
+
/** What the settings form needs: the unit, the bounds and the type's default. */
|
|
74227
|
+
var TimedRunOptionsSchema = object({
|
|
74228
|
+
unit: TimedRunUnitSchema,
|
|
74229
|
+
/** The longest run, in `unit`. */
|
|
74230
|
+
maxDuration: number(),
|
|
74231
|
+
defaultDuration: number()
|
|
74232
|
+
});
|
|
74233
|
+
/** The one-tap run duration, in the type's unit; `null` returns to the type's default. */
|
|
74234
|
+
var TimedRunSettingsPatchSchema = object({ quickRunDuration: number().positive().finite().nullable().optional() });
|
|
74235
|
+
method(object({ deviceId: number().int() }), TimedRunOptionsSchema), method(object({
|
|
74236
|
+
deviceId: number().int(),
|
|
74237
|
+
settings: TimedRunSettingsPatchSchema
|
|
74238
|
+
}), _void(), {
|
|
74239
|
+
kind: "mutation",
|
|
74240
|
+
auth: "admin"
|
|
74241
|
+
}), method(object({
|
|
74189
74242
|
deviceId: number().int(),
|
|
74190
74243
|
duration: number().positive().finite(),
|
|
74191
74244
|
unit: TimedRunUnitSchema
|
|
@@ -76891,21 +76944,28 @@ Object.freeze({
|
|
|
76891
76944
|
access: "view",
|
|
76892
76945
|
role: "admin"
|
|
76893
76946
|
},
|
|
76894
|
-
"addonSettings.
|
|
76947
|
+
"addonSettings.getIntegrationFormSchema": {
|
|
76948
|
+
capName: "addon-settings",
|
|
76949
|
+
capScope: "system",
|
|
76950
|
+
addonId: null,
|
|
76951
|
+
access: "view",
|
|
76952
|
+
role: "admin"
|
|
76953
|
+
},
|
|
76954
|
+
"addonSettings.getScopedSettings": {
|
|
76895
76955
|
capName: "addon-settings",
|
|
76896
76956
|
capScope: "system",
|
|
76897
76957
|
addonId: null,
|
|
76898
76958
|
access: "view",
|
|
76899
76959
|
role: "admin"
|
|
76900
76960
|
},
|
|
76901
|
-
"addonSettings.
|
|
76961
|
+
"addonSettings.listScopedSettings": {
|
|
76902
76962
|
capName: "addon-settings",
|
|
76903
76963
|
capScope: "system",
|
|
76904
76964
|
addonId: null,
|
|
76905
76965
|
access: "view",
|
|
76906
76966
|
role: "admin"
|
|
76907
76967
|
},
|
|
76908
|
-
"addonSettings.
|
|
76968
|
+
"addonSettings.readScopedValues": {
|
|
76909
76969
|
capName: "addon-settings",
|
|
76910
76970
|
capScope: "system",
|
|
76911
76971
|
addonId: null,
|
|
@@ -76926,7 +76986,7 @@ Object.freeze({
|
|
|
76926
76986
|
access: "create",
|
|
76927
76987
|
role: "admin"
|
|
76928
76988
|
},
|
|
76929
|
-
"addonSettings.
|
|
76989
|
+
"addonSettings.updateScopedSettings": {
|
|
76930
76990
|
capName: "addon-settings",
|
|
76931
76991
|
capScope: "system",
|
|
76932
76992
|
addonId: null,
|
|
@@ -79096,6 +79156,13 @@ Object.freeze({
|
|
|
79096
79156
|
access: "create",
|
|
79097
79157
|
role: "admin"
|
|
79098
79158
|
},
|
|
79159
|
+
"deviceManager.setAlias": {
|
|
79160
|
+
capName: "device-manager",
|
|
79161
|
+
capScope: "system",
|
|
79162
|
+
addonId: null,
|
|
79163
|
+
access: "create",
|
|
79164
|
+
role: "admin"
|
|
79165
|
+
},
|
|
79099
79166
|
"deviceManager.setChildLayout": {
|
|
79100
79167
|
capName: "device-manager",
|
|
79101
79168
|
capScope: "system",
|
|
@@ -80384,13 +80451,6 @@ Object.freeze({
|
|
|
80384
80451
|
access: "delete",
|
|
80385
80452
|
role: "admin"
|
|
80386
80453
|
},
|
|
80387
|
-
"llm.deleteProfile": {
|
|
80388
|
-
capName: "llm",
|
|
80389
|
-
capScope: "system",
|
|
80390
|
-
addonId: null,
|
|
80391
|
-
access: "delete",
|
|
80392
|
-
role: "admin"
|
|
80393
|
-
},
|
|
80394
80454
|
"llm.generate": {
|
|
80395
80455
|
capName: "llm",
|
|
80396
80456
|
capScope: "system",
|
|
@@ -80454,20 +80514,6 @@ Object.freeze({
|
|
|
80454
80514
|
access: "view",
|
|
80455
80515
|
role: "admin"
|
|
80456
80516
|
},
|
|
80457
|
-
"llm.listProfileKinds": {
|
|
80458
|
-
capName: "llm",
|
|
80459
|
-
capScope: "system",
|
|
80460
|
-
addonId: null,
|
|
80461
|
-
access: "view",
|
|
80462
|
-
role: "admin"
|
|
80463
|
-
},
|
|
80464
|
-
"llm.listProfiles": {
|
|
80465
|
-
capName: "llm",
|
|
80466
|
-
capScope: "system",
|
|
80467
|
-
addonId: null,
|
|
80468
|
-
access: "view",
|
|
80469
|
-
role: "admin"
|
|
80470
|
-
},
|
|
80471
80517
|
"llm.listRuntimeNodes": {
|
|
80472
80518
|
capName: "llm",
|
|
80473
80519
|
capScope: "system",
|
|
@@ -80475,13 +80521,6 @@ Object.freeze({
|
|
|
80475
80521
|
access: "view",
|
|
80476
80522
|
role: "admin"
|
|
80477
80523
|
},
|
|
80478
|
-
"llm.migrateRawSecrets": {
|
|
80479
|
-
capName: "llm",
|
|
80480
|
-
capScope: "system",
|
|
80481
|
-
addonId: null,
|
|
80482
|
-
access: "create",
|
|
80483
|
-
role: "admin"
|
|
80484
|
-
},
|
|
80485
80524
|
"llm.resolveModelRef": {
|
|
80486
80525
|
capName: "llm",
|
|
80487
80526
|
capScope: "system",
|
|
@@ -80510,20 +80549,6 @@ Object.freeze({
|
|
|
80510
80549
|
access: "create",
|
|
80511
80550
|
role: "admin"
|
|
80512
80551
|
},
|
|
80513
|
-
"llm.testProfile": {
|
|
80514
|
-
capName: "llm",
|
|
80515
|
-
capScope: "system",
|
|
80516
|
-
addonId: null,
|
|
80517
|
-
access: "create",
|
|
80518
|
-
role: "admin"
|
|
80519
|
-
},
|
|
80520
|
-
"llm.upsertProfile": {
|
|
80521
|
-
capName: "llm",
|
|
80522
|
-
capScope: "system",
|
|
80523
|
-
addonId: null,
|
|
80524
|
-
access: "create",
|
|
80525
|
-
role: "admin"
|
|
80526
|
-
},
|
|
80527
80552
|
"llmRuntime.appleAvailability": {
|
|
80528
80553
|
capName: "llm-runtime",
|
|
80529
80554
|
capScope: "system",
|
|
@@ -81028,13 +81053,6 @@ Object.freeze({
|
|
|
81028
81053
|
access: "create",
|
|
81029
81054
|
role: "admin"
|
|
81030
81055
|
},
|
|
81031
|
-
"meshNetwork.testConnection": {
|
|
81032
|
-
capName: "mesh-network",
|
|
81033
|
-
capScope: "system",
|
|
81034
|
-
addonId: null,
|
|
81035
|
-
access: "create",
|
|
81036
|
-
role: "admin"
|
|
81037
|
-
},
|
|
81038
81056
|
"meter.getStatus": {
|
|
81039
81057
|
capName: "meter",
|
|
81040
81058
|
capScope: "device",
|
|
@@ -81693,13 +81711,6 @@ Object.freeze({
|
|
|
81693
81711
|
access: "create",
|
|
81694
81712
|
role: "admin"
|
|
81695
81713
|
},
|
|
81696
|
-
"notificationOutput.deleteTarget": {
|
|
81697
|
-
capName: "notification-output",
|
|
81698
|
-
capScope: "system",
|
|
81699
|
-
addonId: null,
|
|
81700
|
-
access: "delete",
|
|
81701
|
-
role: "admin"
|
|
81702
|
-
},
|
|
81703
81714
|
"notificationOutput.discoverTargets": {
|
|
81704
81715
|
capName: "notification-output",
|
|
81705
81716
|
capScope: "system",
|
|
@@ -81707,13 +81718,6 @@ Object.freeze({
|
|
|
81707
81718
|
access: "view",
|
|
81708
81719
|
role: "admin"
|
|
81709
81720
|
},
|
|
81710
|
-
"notificationOutput.getTarget": {
|
|
81711
|
-
capName: "notification-output",
|
|
81712
|
-
capScope: "system",
|
|
81713
|
-
addonId: null,
|
|
81714
|
-
access: "view",
|
|
81715
|
-
role: "admin"
|
|
81716
|
-
},
|
|
81717
81721
|
"notificationOutput.listTargetKinds": {
|
|
81718
81722
|
capName: "notification-output",
|
|
81719
81723
|
capScope: "system",
|
|
@@ -81721,13 +81725,6 @@ Object.freeze({
|
|
|
81721
81725
|
access: "view",
|
|
81722
81726
|
role: "admin"
|
|
81723
81727
|
},
|
|
81724
|
-
"notificationOutput.listTargets": {
|
|
81725
|
-
capName: "notification-output",
|
|
81726
|
-
capScope: "system",
|
|
81727
|
-
addonId: null,
|
|
81728
|
-
access: "view",
|
|
81729
|
-
role: "admin"
|
|
81730
|
-
},
|
|
81731
81728
|
"notificationOutput.probeTargetConfig": {
|
|
81732
81729
|
capName: "notification-output",
|
|
81733
81730
|
capScope: "system",
|
|
@@ -81742,13 +81739,6 @@ Object.freeze({
|
|
|
81742
81739
|
access: "create",
|
|
81743
81740
|
role: "admin"
|
|
81744
81741
|
},
|
|
81745
|
-
"notificationOutput.setTargetEnabled": {
|
|
81746
|
-
capName: "notification-output",
|
|
81747
|
-
capScope: "system",
|
|
81748
|
-
addonId: null,
|
|
81749
|
-
access: "create",
|
|
81750
|
-
role: "admin"
|
|
81751
|
-
},
|
|
81752
81742
|
"notificationOutput.testTarget": {
|
|
81753
81743
|
capName: "notification-output",
|
|
81754
81744
|
capScope: "system",
|
|
@@ -81756,13 +81746,6 @@ Object.freeze({
|
|
|
81756
81746
|
access: "create",
|
|
81757
81747
|
role: "admin"
|
|
81758
81748
|
},
|
|
81759
|
-
"notificationOutput.upsertTarget": {
|
|
81760
|
-
capName: "notification-output",
|
|
81761
|
-
capScope: "system",
|
|
81762
|
-
addonId: null,
|
|
81763
|
-
access: "create",
|
|
81764
|
-
role: "admin"
|
|
81765
|
-
},
|
|
81766
81749
|
"notificationRules.activateAlarmProfile": {
|
|
81767
81750
|
capName: "notification-rules",
|
|
81768
81751
|
capScope: "system",
|
|
@@ -82022,41 +82005,6 @@ Object.freeze({
|
|
|
82022
82005
|
access: "view",
|
|
82023
82006
|
role: "admin"
|
|
82024
82007
|
},
|
|
82025
|
-
"oidcConnections.connectionFormSchema": {
|
|
82026
|
-
capName: "oidc-connections",
|
|
82027
|
-
capScope: "system",
|
|
82028
|
-
addonId: null,
|
|
82029
|
-
access: "view",
|
|
82030
|
-
role: "admin"
|
|
82031
|
-
},
|
|
82032
|
-
"oidcConnections.createConnection": {
|
|
82033
|
-
capName: "oidc-connections",
|
|
82034
|
-
capScope: "system",
|
|
82035
|
-
addonId: null,
|
|
82036
|
-
access: "create",
|
|
82037
|
-
role: "admin"
|
|
82038
|
-
},
|
|
82039
|
-
"oidcConnections.deleteConnection": {
|
|
82040
|
-
capName: "oidc-connections",
|
|
82041
|
-
capScope: "system",
|
|
82042
|
-
addonId: null,
|
|
82043
|
-
access: "delete",
|
|
82044
|
-
role: "admin"
|
|
82045
|
-
},
|
|
82046
|
-
"oidcConnections.listConnections": {
|
|
82047
|
-
capName: "oidc-connections",
|
|
82048
|
-
capScope: "system",
|
|
82049
|
-
addonId: null,
|
|
82050
|
-
access: "view",
|
|
82051
|
-
role: "admin"
|
|
82052
|
-
},
|
|
82053
|
-
"oidcConnections.updateConnection": {
|
|
82054
|
-
capName: "oidc-connections",
|
|
82055
|
-
capScope: "system",
|
|
82056
|
-
addonId: null,
|
|
82057
|
-
access: "create",
|
|
82058
|
-
role: "admin"
|
|
82059
|
-
},
|
|
82060
82008
|
"osd.getStatus": {
|
|
82061
82009
|
capName: "osd",
|
|
82062
82010
|
capScope: "device",
|
|
@@ -85088,13 +85036,6 @@ Object.freeze({
|
|
|
85088
85036
|
access: "delete",
|
|
85089
85037
|
role: "admin"
|
|
85090
85038
|
},
|
|
85091
|
-
"storage.deleteLocation": {
|
|
85092
|
-
capName: "storage",
|
|
85093
|
-
capScope: "system",
|
|
85094
|
-
addonId: null,
|
|
85095
|
-
access: "delete",
|
|
85096
|
-
role: "admin"
|
|
85097
|
-
},
|
|
85098
85039
|
"storage.endDownload": {
|
|
85099
85040
|
capName: "storage",
|
|
85100
85041
|
capScope: "system",
|
|
@@ -85151,13 +85092,6 @@ Object.freeze({
|
|
|
85151
85092
|
access: "view",
|
|
85152
85093
|
role: "admin"
|
|
85153
85094
|
},
|
|
85154
|
-
"storage.listProviders": {
|
|
85155
|
-
capName: "storage",
|
|
85156
|
-
capScope: "system",
|
|
85157
|
-
addonId: null,
|
|
85158
|
-
access: "view",
|
|
85159
|
-
role: "admin"
|
|
85160
|
-
},
|
|
85161
85095
|
"storage.read": {
|
|
85162
85096
|
capName: "storage",
|
|
85163
85097
|
capScope: "system",
|
|
@@ -85179,27 +85113,6 @@ Object.freeze({
|
|
|
85179
85113
|
access: "view",
|
|
85180
85114
|
role: "admin"
|
|
85181
85115
|
},
|
|
85182
|
-
"storage.testConfig": {
|
|
85183
|
-
capName: "storage",
|
|
85184
|
-
capScope: "system",
|
|
85185
|
-
addonId: null,
|
|
85186
|
-
access: "view",
|
|
85187
|
-
role: "admin"
|
|
85188
|
-
},
|
|
85189
|
-
"storage.testLocation": {
|
|
85190
|
-
capName: "storage",
|
|
85191
|
-
capScope: "system",
|
|
85192
|
-
addonId: null,
|
|
85193
|
-
access: "view",
|
|
85194
|
-
role: "admin"
|
|
85195
|
-
},
|
|
85196
|
-
"storage.upsertLocation": {
|
|
85197
|
-
capName: "storage",
|
|
85198
|
-
capScope: "system",
|
|
85199
|
-
addonId: null,
|
|
85200
|
-
access: "create",
|
|
85201
|
-
role: "admin"
|
|
85202
|
-
},
|
|
85203
85116
|
"storage.write": {
|
|
85204
85117
|
capName: "storage",
|
|
85205
85118
|
capScope: "system",
|
|
@@ -85977,27 +85890,6 @@ Object.freeze({
|
|
|
85977
85890
|
access: "create",
|
|
85978
85891
|
role: "admin"
|
|
85979
85892
|
},
|
|
85980
|
-
"terminalSession.createInstance": {
|
|
85981
|
-
capName: "terminal-session",
|
|
85982
|
-
capScope: "system",
|
|
85983
|
-
addonId: null,
|
|
85984
|
-
access: "create",
|
|
85985
|
-
role: "admin"
|
|
85986
|
-
},
|
|
85987
|
-
"terminalSession.deleteInstance": {
|
|
85988
|
-
capName: "terminal-session",
|
|
85989
|
-
capScope: "system",
|
|
85990
|
-
addonId: null,
|
|
85991
|
-
access: "delete",
|
|
85992
|
-
role: "admin"
|
|
85993
|
-
},
|
|
85994
|
-
"terminalSession.listInstances": {
|
|
85995
|
-
capName: "terminal-session",
|
|
85996
|
-
capScope: "system",
|
|
85997
|
-
addonId: null,
|
|
85998
|
-
access: "view",
|
|
85999
|
-
role: "admin"
|
|
86000
|
-
},
|
|
86001
85893
|
"terminalSession.listLegacyCameras": {
|
|
86002
85894
|
capName: "terminal-session",
|
|
86003
85895
|
capScope: "system",
|
|
@@ -86040,20 +85932,6 @@ Object.freeze({
|
|
|
86040
85932
|
access: "create",
|
|
86041
85933
|
role: "admin"
|
|
86042
85934
|
},
|
|
86043
|
-
"terminalSession.setInstanceEnabled": {
|
|
86044
|
-
capName: "terminal-session",
|
|
86045
|
-
capScope: "system",
|
|
86046
|
-
addonId: null,
|
|
86047
|
-
access: "create",
|
|
86048
|
-
role: "admin"
|
|
86049
|
-
},
|
|
86050
|
-
"terminalSession.updateInstance": {
|
|
86051
|
-
capName: "terminal-session",
|
|
86052
|
-
capScope: "system",
|
|
86053
|
-
addonId: null,
|
|
86054
|
-
access: "create",
|
|
86055
|
-
role: "admin"
|
|
86056
|
-
},
|
|
86057
85935
|
"terminalSession.writeInput": {
|
|
86058
85936
|
capName: "terminal-session",
|
|
86059
85937
|
capScope: "system",
|
|
@@ -86068,6 +85946,13 @@ Object.freeze({
|
|
|
86068
85946
|
access: "create",
|
|
86069
85947
|
role: "viewer"
|
|
86070
85948
|
},
|
|
85949
|
+
"timedRun.getOptions": {
|
|
85950
|
+
capName: "timed-run",
|
|
85951
|
+
capScope: "device",
|
|
85952
|
+
addonId: null,
|
|
85953
|
+
access: "view",
|
|
85954
|
+
role: "viewer"
|
|
85955
|
+
},
|
|
86071
85956
|
"timedRun.getStatus": {
|
|
86072
85957
|
capName: "timed-run",
|
|
86073
85958
|
capScope: "device",
|
|
@@ -86082,6 +85967,13 @@ Object.freeze({
|
|
|
86082
85967
|
access: "create",
|
|
86083
85968
|
role: "viewer"
|
|
86084
85969
|
},
|
|
85970
|
+
"timedRun.setSettings": {
|
|
85971
|
+
capName: "timed-run",
|
|
85972
|
+
capScope: "device",
|
|
85973
|
+
addonId: null,
|
|
85974
|
+
access: "create",
|
|
85975
|
+
role: "admin"
|
|
85976
|
+
},
|
|
86085
85977
|
"toast.onToast": {
|
|
86086
85978
|
capName: "toast",
|
|
86087
85979
|
capScope: "system",
|
|
@@ -87012,6 +86904,7 @@ function offered(received) {
|
|
|
87012
86904
|
};
|
|
87013
86905
|
}
|
|
87014
86906
|
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
86907
|
+
string().min(1).max(4096);
|
|
87015
86908
|
Object.freeze({
|
|
87016
86909
|
"accessories.getStatus": [{
|
|
87017
86910
|
name: "deviceId",
|
|
@@ -87695,6 +87588,11 @@ Object.freeze({
|
|
|
87695
87588
|
form: "single",
|
|
87696
87589
|
optional: false
|
|
87697
87590
|
}],
|
|
87591
|
+
"deviceManager.setAlias": [{
|
|
87592
|
+
name: "deviceId",
|
|
87593
|
+
form: "single",
|
|
87594
|
+
optional: false
|
|
87595
|
+
}],
|
|
87698
87596
|
"deviceManager.setChildLayout": [{
|
|
87699
87597
|
name: "deviceId",
|
|
87700
87598
|
form: "single",
|
|
@@ -89759,6 +89657,11 @@ Object.freeze({
|
|
|
89759
89657
|
form: "single",
|
|
89760
89658
|
optional: false
|
|
89761
89659
|
}],
|
|
89660
|
+
"timedRun.getOptions": [{
|
|
89661
|
+
name: "deviceId",
|
|
89662
|
+
form: "single",
|
|
89663
|
+
optional: false
|
|
89664
|
+
}],
|
|
89762
89665
|
"timedRun.getStatus": [{
|
|
89763
89666
|
name: "deviceId",
|
|
89764
89667
|
form: "single",
|
|
@@ -89769,6 +89672,11 @@ Object.freeze({
|
|
|
89769
89672
|
form: "single",
|
|
89770
89673
|
optional: false
|
|
89771
89674
|
}],
|
|
89675
|
+
"timedRun.setSettings": [{
|
|
89676
|
+
name: "deviceId",
|
|
89677
|
+
form: "single",
|
|
89678
|
+
optional: false
|
|
89679
|
+
}],
|
|
89772
89680
|
"update.getStatus": [{
|
|
89773
89681
|
name: "deviceId",
|
|
89774
89682
|
form: "single",
|
|
@@ -90631,6 +90539,7 @@ var STATE_SUMMARY_VARS = [
|
|
|
90631
90539
|
[...RULE_TEXT],
|
|
90632
90540
|
[...RULE_TEXT],
|
|
90633
90541
|
[...RULE_TEXT],
|
|
90542
|
+
[...RULE_TEXT],
|
|
90634
90543
|
[...RULE_BODY_ONLY],
|
|
90635
90544
|
[...RULE_TEXT],
|
|
90636
90545
|
([...RULE_TEXT], [...DEVICE_EVENTS]),
|
|
@@ -145985,17 +145894,6 @@ function scrub(message, secret) {
|
|
|
145985
145894
|
function mintRelayId() {
|
|
145986
145895
|
return `relay-${(0, node_crypto.randomUUID)().slice(0, 8)}`;
|
|
145987
145896
|
}
|
|
145988
|
-
/** The keys the settings page edits: the relay's connection fields. */
|
|
145989
|
-
var RELAY_FORM_KEYS = new Set([
|
|
145990
|
-
"host",
|
|
145991
|
-
"port",
|
|
145992
|
-
"secure",
|
|
145993
|
-
"username",
|
|
145994
|
-
"password",
|
|
145995
|
-
"fromAddress",
|
|
145996
|
-
"fromName"
|
|
145997
|
-
]);
|
|
145998
|
-
var DEFAULT_RELAY_NAME = "Email (SMTP)";
|
|
145999
145897
|
var RELAY_LIST_MAX = 200;
|
|
146000
145898
|
function hasText(value) {
|
|
146001
145899
|
return typeof value === "string" && value.length > 0;
|
|
@@ -146248,44 +146146,10 @@ var SmtpNodemailerAddon = class extends BaseAddon {
|
|
|
146248
146146
|
const rows = (await records.kind(smtpRelaysKind).query({ limit: RELAY_LIST_MAX })).records;
|
|
146249
146147
|
return (rows.find((row) => row.data.host.length > 0) ?? rows[0])?.id;
|
|
146250
146148
|
}
|
|
146251
|
-
/** The relay form.
|
|
146149
|
+
/** The relay form. */
|
|
146252
146150
|
async integrationFormSchema(_instance) {
|
|
146253
146151
|
return this.relayForm();
|
|
146254
146152
|
}
|
|
146255
|
-
async getGlobalSettings() {
|
|
146256
|
-
const schema = this.relayForm();
|
|
146257
|
-
if (this.instances === null) return hydrateSchema(schema, {}, { inlineSecretsAsViews: true });
|
|
146258
|
-
const id = await this.firstRelayId();
|
|
146259
|
-
return hydrateSchema(schema, (id === void 0 ? null : await this.instances.readResolved(id))?.body ?? {}, { inlineSecretsAsViews: true });
|
|
146260
|
-
}
|
|
146261
|
-
async updateGlobalSettingsAsOperator(patch) {
|
|
146262
|
-
await this.writeDefaultRelay(patch);
|
|
146263
|
-
}
|
|
146264
|
-
async updateGlobalSettings(patch) {
|
|
146265
|
-
await this.writeDefaultRelay(patch);
|
|
146266
|
-
}
|
|
146267
|
-
/** Write the form's values onto the default relay, creating it on the first save. */
|
|
146268
|
-
async writeDefaultRelay(patch) {
|
|
146269
|
-
if (this.instances === null) throw new Error("smtp-nodemailer is not initialised");
|
|
146270
|
-
const values = Object.fromEntries(Object.entries(patch).filter(([key]) => RELAY_FORM_KEYS.has(key)));
|
|
146271
|
-
const existing = await this.firstRelayId();
|
|
146272
|
-
if (existing !== void 0) {
|
|
146273
|
-
await this.instances.updateInstance({
|
|
146274
|
-
id: existing,
|
|
146275
|
-
values
|
|
146276
|
-
});
|
|
146277
|
-
return;
|
|
146278
|
-
}
|
|
146279
|
-
const id = mintRelayId();
|
|
146280
|
-
await this.instances.createInstance({
|
|
146281
|
-
id,
|
|
146282
|
-
name: DEFAULT_RELAY_NAME
|
|
146283
|
-
});
|
|
146284
|
-
await this.instances.updateInstance({
|
|
146285
|
-
id,
|
|
146286
|
-
values
|
|
146287
|
-
});
|
|
146288
|
-
}
|
|
146289
146153
|
/** Probe a relay (EHLO + AUTH) with the form's values, falling back to the stored ones. */
|
|
146290
146154
|
async probe(id, values) {
|
|
146291
146155
|
const stored = id !== null && this.instances !== null ? await this.instances.getResolved(id) : null;
|