@camstack/addon-smtp-nodemailer 1.2.151 → 1.2.152

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.
@@ -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-BmPm98n0.mjs
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 `storage.upsertLocation` / `deleteLocation`.
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
@@ -6020,7 +6037,7 @@ var ZodIssueCode = {
6020
6037
  var ZodFirstPartyTypeKind;
6021
6038
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
6022
6039
  //#endregion
6023
- //#region ../types/dist/sleep-D7ZKm4nb.mjs
6040
+ //#region ../types/dist/sleep-CQP-REJp.mjs
6024
6041
  /**
6025
6042
  * The audio chunk plane's byte format, and the ONE expansion from a coded
6026
6043
  * window to float samples (D455).
@@ -6384,6 +6401,59 @@ Object.fromEntries([
6384
6401
  function isValuelessField(field) {
6385
6402
  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
6403
  }
6404
+ /**
6405
+ * Base collector: flatten a hydrated `ConfigUISchemaWithValues` into
6406
+ * `key → { value, default }`, recursing through `group` and `sub-tabs`
6407
+ * layout fields. Keeping `value` and `default` SEPARATE (rather than
6408
+ * pre-resolving) lets callers both read the effective value AND detect
6409
+ * overrides (`value` differs from `default`). Structural over `unknown`;
6410
+ * malformed input yields an empty map, never throws.
6411
+ */
6412
+ function collectHydratedFieldEntries(schema) {
6413
+ const out = /* @__PURE__ */ new Map();
6414
+ if (typeof schema !== "object" || schema === null) return out;
6415
+ const sections = schema.sections;
6416
+ if (!Array.isArray(sections)) return out;
6417
+ for (const section of sections) if (typeof section === "object" && section !== null) collectFieldEntriesInto(section.fields, out);
6418
+ return out;
6419
+ }
6420
+ /** Recursive field walker for {@link collectHydratedFieldEntries}. */
6421
+ function collectFieldEntriesInto(fields, into) {
6422
+ if (!Array.isArray(fields)) return;
6423
+ for (const field of fields) {
6424
+ if (typeof field !== "object" || field === null) continue;
6425
+ const type = field.type;
6426
+ if (type === "group") {
6427
+ collectFieldEntriesInto(field.fields, into);
6428
+ continue;
6429
+ }
6430
+ if (type === "sub-tabs") {
6431
+ const tabs = field.tabs;
6432
+ if (Array.isArray(tabs)) {
6433
+ for (const tab of tabs) if (typeof tab === "object" && tab !== null) collectFieldEntriesInto(tab.fields, into);
6434
+ }
6435
+ continue;
6436
+ }
6437
+ const key = field.key;
6438
+ if (typeof key !== "string" || key.length === 0) continue;
6439
+ if (!("value" in field)) continue;
6440
+ into.set(key, {
6441
+ value: field.value,
6442
+ default: field.default
6443
+ });
6444
+ }
6445
+ }
6446
+ /**
6447
+ * Flatten a hydrated settings payload into `key → EFFECTIVE value`
6448
+ * (`value ?? default`). The read-side inverse of `hydrateSchema` for the
6449
+ * common "just give me the resolved values" case. Built on
6450
+ * {@link collectHydratedFieldEntries}.
6451
+ */
6452
+ function collectHydratedFieldValues(schema) {
6453
+ const out = /* @__PURE__ */ new Map();
6454
+ for (const [key, entry] of collectHydratedFieldEntries(schema)) out.set(key, entry.value ?? entry.default);
6455
+ return out;
6456
+ }
6387
6457
  function hydrateSchema(schema, values, options = {}) {
6388
6458
  return {
6389
6459
  ...schema.tabs ? { tabs: [...schema.tabs] } : {},
@@ -7268,17 +7338,35 @@ var RecordIntegrationInstances = class {
7268
7338
  ...kind !== void 0 ? { kind } : {}
7269
7339
  });
7270
7340
  if (minted === void 0) throw new Error("createInstance needs an id: this provider does not mint one");
7341
+ const initial = this.hooks.initialBody(name, kind);
7342
+ const patch = this.patchOf(values ?? {});
7343
+ if (Object.keys(patch).length > 0) Object.assign(patch, await this.hooks.validateWrite?.({
7344
+ kind,
7345
+ body: {
7346
+ ...initial,
7347
+ ...patch
7348
+ }
7349
+ }));
7271
7350
  await this.handle.put({
7272
7351
  id: minted,
7273
- data: this.hooks.initialBody(name, kind)
7352
+ data: initial
7274
7353
  }, { ifRev: 0 });
7275
- const patch = this.patchOf(values ?? {});
7276
7354
  if (Object.keys(patch).length > 0) await this.handle.patch(minted, patch);
7277
7355
  await this.hooks.onChanged?.(minted, "created");
7278
7356
  return { id: minted };
7279
7357
  };
7280
7358
  updateInstance = async ({ id, name, values }) => {
7281
7359
  const patch = this.patchOf(values);
7360
+ if (this.hooks.validateWrite !== void 0 && Object.keys(patch).length > 0) {
7361
+ const stored = await this.handle.get(id);
7362
+ if (stored !== null) Object.assign(patch, await this.hooks.validateWrite({
7363
+ kind: void 0,
7364
+ body: {
7365
+ ...stored.data,
7366
+ ...patch
7367
+ }
7368
+ }));
7369
+ }
7282
7370
  if (name !== void 0) patch[this.nameField] = name;
7283
7371
  await this.handle.patch(id, patch);
7284
7372
  await this.hooks.onChanged?.(id, "updated");
@@ -7589,6 +7677,21 @@ var SCOPED_SETTINGS_SCOPES = [
7589
7677
  "device-defaults",
7590
7678
  "node"
7591
7679
  ];
7680
+ /** The one refusal of a key a scope did not declare. */
7681
+ function assertDeclaredKeys(keys, declared) {
7682
+ const undeclared = keys.filter((key) => !declared.has(key));
7683
+ if (undeclared.length > 0) throw new Error(`scoped settings: [${undeclared.join(", ")}] not declared for this scope (declared: [${[...declared].join(", ")}])`);
7684
+ }
7685
+ /** Build the handle over an addon's scoped read, write and unset. */
7686
+ function createScopedSettings(deps) {
7687
+ return {
7688
+ async get() {
7689
+ return deps.schema.parse(await deps.read());
7690
+ },
7691
+ patch: (patch) => deps.write(Object.fromEntries(Object.entries(patch))),
7692
+ unset: (keys) => deps.unset(keys)
7693
+ };
7694
+ }
7592
7695
  /** A write to a secret path could not be stored in the keychain, so it was refused. */
7593
7696
  var KeychainWriteRefusedError = class extends Error {
7594
7697
  fieldPath;
@@ -8164,7 +8267,16 @@ function createHandle(raw, opts) {
8164
8267
  return blob;
8165
8268
  }
8166
8269
  },
8167
- writeAddonStore: writeAddon
8270
+ writeAddonStore: writeAddon,
8271
+ removeClearedKeys: (keys) => serialize("addon", async () => {
8272
+ const stored = await readStoredAddonBlob(raw);
8273
+ index.seen("addon", stored);
8274
+ const removable = keys.filter((key) => collectSecretMarkerRefs(stored[key]).length === 0);
8275
+ if (removable.length === 0) return;
8276
+ const patch = Object.fromEntries(removable.map((key) => [key, void 0]));
8277
+ await raw.writeAddonStore(patch);
8278
+ index.wrote("addon", patch);
8279
+ })
8168
8280
  };
8169
8281
  }
8170
8282
  /** The context the addon sees, plus the private raw view and write outcome. */
@@ -8709,6 +8821,151 @@ var BaseAddon = class {
8709
8821
  }
8710
8822
  }
8711
8823
  /**
8824
+ * Hook: values layered over the stored ones when the FORM of one scope is served
8825
+ * ({@link getScopedSettings}) — a preview that derives dependent options without writing.
8826
+ * Never applied to {@link ScopedSettings.get} or to a write. `null` ⇒ no overlay.
8827
+ */
8828
+ async scopedSettingsOverlay(_scope, _cap, _nodeId) {
8829
+ return null;
8830
+ }
8831
+ /**
8832
+ * Hook: a write of one scope changed stored values (not called when the store reports no change,
8833
+ * e.g. the write-back of a stored secret). `keys` are the bare field keys of the write, node keys included.
8834
+ */
8835
+ async onScopedSettingsChanged(_scope, _cap, _keys) {}
8836
+ /** Typed handle over the CLUSTER settings `cap` declares (`clusterSettingsSchema`). */
8837
+ clusterSettings(cap, schema) {
8838
+ return this.scopedHandle("cluster", cap, schema);
8839
+ }
8840
+ /** Typed handle over the fleet defaults of the per-device settings `cap` declares. */
8841
+ deviceDefaults(cap, schema) {
8842
+ return this.scopedHandle("device-defaults", cap, schema);
8843
+ }
8844
+ /**
8845
+ * Typed handle over the settings `cap` owns PER NODE. `nodeId` omitted ⇒ the local node. A node
8846
+ * with no row yields the schema defaults — never a bare-key fallback.
8847
+ */
8848
+ nodeSettings(cap, schema, nodeId) {
8849
+ return this.scopedHandle("node", cap, schema, nodeId);
8850
+ }
8851
+ /**
8852
+ * {@link state} for a value that is kept per node: stored under `<key>@<nodeId>`, and the
8853
+ * settings store carries `nodeId` in the row data (D986 §1), so a forgotten node's rows go in one
8854
+ * central delete. `nodeId` omitted ⇒ the local node.
8855
+ */
8856
+ nodeState(key, schema, fallback, nodeId) {
8857
+ this._declaredStateKeys.add(key);
8858
+ return createDurableState({
8859
+ key: nodeScopedKey(key, nodeId ?? this._ctx?.kernel?.localNodeId ?? ""),
8860
+ schema,
8861
+ fallback,
8862
+ read: async () => this.resolveStoredSecrets(await this.readAddonStoreWithRetry()),
8863
+ write: async (patch) => {
8864
+ await this._ctx?.settings?.writeAddonStore(patch);
8865
+ },
8866
+ onParseError: (k, e) => this._ctx?.logger?.warn?.(`durable-state: stored "${k}" failed validation — using fallback`, { meta: {
8867
+ addonId: this._ctx?.id,
8868
+ key: k,
8869
+ error: String(e)
8870
+ } })
8871
+ });
8872
+ }
8873
+ /** The loaded schema `cap` declares for `scope`, or `null`. */
8874
+ async declaredScopedSchema(scope, cap) {
8875
+ await this.loadScopedSchemas(cap);
8876
+ return this.loadedScopedSchemas(cap).find((entry) => entry.scope === scope)?.schema ?? null;
8877
+ }
8878
+ async requireScopedSchema(scope, cap) {
8879
+ const schema = await this.declaredScopedSchema(scope, cap);
8880
+ if (schema === null) throw new Error(`${this.constructor.name}: cap "${cap}" declares no ${scope} settings`);
8881
+ return schema;
8882
+ }
8883
+ scopedKeys(schema) {
8884
+ return new Set(schema.sections.flatMap((section) => collectValueFieldKeys(section.fields)));
8885
+ }
8886
+ /** `store` narrowed to the keys `schema` declares. */
8887
+ narrowToScope(store, schema) {
8888
+ const keys = this.scopedKeys(schema);
8889
+ return Object.fromEntries(Object.entries(store).filter(([key]) => keys.has(key)));
8890
+ }
8891
+ scopedHandle(scope, cap, schema, nodeId) {
8892
+ return createScopedSettings({
8893
+ schema,
8894
+ read: async () => {
8895
+ const declared = await this.requireScopedSchema(scope, cap);
8896
+ const stored = this.narrowToScope(await this.resolveGlobalStore(nodeId, cap), declared);
8897
+ const effective = collectHydratedFieldValues(hydrateSchema(declared, stored));
8898
+ return {
8899
+ ...Object.fromEntries([...effective].filter(([, value]) => value !== void 0)),
8900
+ ...stored
8901
+ };
8902
+ },
8903
+ write: (patch) => this.writeScoped(scope, cap, patch, nodeId),
8904
+ unset: (keys) => this.unsetScoped(scope, cap, keys, nodeId)
8905
+ });
8906
+ }
8907
+ /** The one write path of the scoped API: declared keys only, then the global patch. */
8908
+ async writeScoped(scope, cap, patch, nodeId) {
8909
+ assertDeclaredKeys(Object.keys(patch), this.scopedKeys(await this.requireScopedSchema(scope, cap)));
8910
+ if (await this.applyGlobalPatch(patch, scope === "node" ? nodeId : void 0, cap)) await this.onScopedSettingsChanged(scope, cap, Object.keys(patch));
8911
+ }
8912
+ /**
8913
+ * Remove declared keys of one scope. A secret goes through {@link clearSecrets} — its keychain
8914
+ * value is released exactly as there — and the emptied row is then removed; every other key is
8915
+ * removed by an `undefined` patch (which a secret transform would read as "keep").
8916
+ */
8917
+ async unsetScoped(scope, cap, keys, nodeId) {
8918
+ assertDeclaredKeys(keys, this.scopedKeys(await this.requireScopedSchema(scope, cap)));
8919
+ const target = scope === "node" ? nodeId : void 0;
8920
+ const tree = this.addonSecretTree();
8921
+ const secretKeys = keys.filter((key) => tree.has(key));
8922
+ const plainKeys = keys.filter((key) => !tree.has(key));
8923
+ let changed = false;
8924
+ if (plainKeys.length > 0) {
8925
+ const patch = Object.fromEntries(plainKeys.map((key) => [key, void 0]));
8926
+ changed = await this.applyGlobalPatch(patch, target, cap) || changed;
8927
+ }
8928
+ if (secretKeys.length > 0) {
8929
+ await this.clearSecretKeys(secretKeys, target, cap);
8930
+ const node = normalizeNodeId(target ?? this._ctx?.kernel?.localNodeId);
8931
+ const rows = secretKeys.map((key) => scope === "node" ? nodeScopedKey(key, node) : key);
8932
+ if (this._secretSettings !== null) await this._secretSettings.removeClearedKeys(rows);
8933
+ else await this._ctx?.settings?.writeAddonStore(Object.fromEntries(rows.map((row) => [row, void 0])));
8934
+ changed = true;
8935
+ }
8936
+ if (changed) await this.onScopedSettingsChanged(scope, cap, [...keys]);
8937
+ }
8938
+ /**
8939
+ * The hydrated form of one scope of one capability's settings (any
8940
+ * {@link scopedSettingsOverlay} applied), or `null` when the capability declares nothing there.
8941
+ */
8942
+ async getScopedSettings(scope, cap, nodeId) {
8943
+ const schema = await this.declaredScopedSchema(scope, cap);
8944
+ if (schema === null) return null;
8945
+ const stored = this.narrowToScope(await this.readRawProjectedStore(nodeId, cap), schema);
8946
+ const overlay = await this.scopedSettingsOverlay(scope, cap, nodeId);
8947
+ return hydrateSchema(schema, overlay ? await this.overlayKeepingMarkers(stored, overlay) : stored, { inlineSecretsAsViews: true });
8948
+ }
8949
+ /** The OPERATOR's write of declared keys of one scope (D787 secret semantics). */
8950
+ async updateScopedSettings(scope, cap, patch, nodeId) {
8951
+ this._operatorWriteDepth++;
8952
+ try {
8953
+ await this.writeScoped(scope, cap, patch, nodeId);
8954
+ } finally {
8955
+ this._operatorWriteDepth--;
8956
+ }
8957
+ }
8958
+ /**
8959
+ * The effective values (`stored ?? default`) of one scope, a secret as its `set` view — never
8960
+ * its value. `null` when the capability declares nothing for the scope.
8961
+ */
8962
+ async readScopedValues(scope, cap, nodeId) {
8963
+ const schema = await this.declaredScopedSchema(scope, cap);
8964
+ if (schema === null) return null;
8965
+ const form = hydrateSchema(schema, this.narrowToScope(await this.readRawProjectedStore(nodeId, cap), schema), { inlineSecretsAsViews: true });
8966
+ return Object.fromEntries([...collectHydratedFieldValues(form)].filter(([, value]) => value !== void 0));
8967
+ }
8968
+ /**
8712
8969
  * What the create wizard and the integration edit page render for one instance: the addon's
8713
8970
  * per-instance schema when it declares one, else its global schema (what they always showed).
8714
8971
  */
@@ -8860,6 +9117,9 @@ var BaseAddon = class {
8860
9117
  * a keychain (an older kernel) it writes `''`, as such code always did.
8861
9118
  */
8862
9119
  async clearSecrets(keys, nodeId) {
9120
+ await this.clearSecretKeys(keys, nodeId);
9121
+ }
9122
+ async clearSecretKeys(keys, nodeId, cap) {
8863
9123
  const tree = this.addonSecretTree();
8864
9124
  const keychain = this._ctx?.secrets !== void 0;
8865
9125
  const stored = keychain ? await this.readAddonStoreWithRetry() : {};
@@ -8872,25 +9132,27 @@ var BaseAddon = class {
8872
9132
  const keychainStored = tree.has(key) || collectSecretMarkerRefs(stored[key]).length > 0;
8873
9133
  patch[key] = keychain && keychainStored ? SECRET_CLEAR : "";
8874
9134
  }
8875
- await this.applyGlobalPatch(patch, nodeId);
9135
+ await this.applyGlobalPatch(patch, nodeId, cap);
8876
9136
  }
8877
- async applyGlobalPatch(barePatch, nodeId) {
8878
- await this.loadScopedSchemas();
8879
- const keys = this.perNodeKeys();
9137
+ /** Resolves `true` when the write changed stored values. */
9138
+ async applyGlobalPatch(barePatch, nodeId, cap) {
9139
+ await this.loadScopedSchemas(cap);
9140
+ const keys = this.perNodeKeys(cap);
8880
9141
  const localNode = normalizeNodeId(this._ctx?.kernel?.localNodeId);
8881
9142
  const target = normalizeNodeId(nodeId ?? this._ctx?.kernel?.localNodeId);
8882
9143
  const scoped = keys.size > 0 ? scopePatch(barePatch, keys, target) : barePatch;
8883
9144
  const handle = this._secretSettings;
8884
9145
  if (handle !== null) {
8885
9146
  const { changed } = await handle.writeAddonStore(scoped);
8886
- if (!changed) return;
9147
+ if (!changed) return false;
8887
9148
  } else await this._ctx?.settings?.writeAddonStore(scoped);
8888
- if (target !== localNode) return;
9149
+ if (target !== localNode) return true;
8889
9150
  await this.resolveConfig();
8890
9151
  await this.onConfigChanged();
8891
9152
  this.emitLifecycle(EventCategory.AddonUpdated, { level: "global" });
8892
9153
  const legacy = this.globalSettingsSchema();
8893
9154
  this.maybeAutoRestart(Object.keys(barePatch), [...legacy === null ? [] : [legacy], ...this.loadedScopedSchemas().map((entry) => entry.schema)]);
9155
+ return true;
8894
9156
  }
8895
9157
  /**
8896
9158
  * The set of field keys the global settings schema declares `perNode: true`
@@ -10620,7 +10882,6 @@ var CAP_NAMES = Object.freeze([
10620
10882
  "notifier",
10621
10883
  "numeric-sensor",
10622
10884
  "oauth-integration",
10623
- "oidc-connections",
10624
10885
  "osd",
10625
10886
  "osd-manager",
10626
10887
  "pet-feeder",
@@ -12512,8 +12773,7 @@ Object.freeze({
12512
12773
  "device-provider": { "reloadDevice": 18e4 },
12513
12774
  "llm": {
12514
12775
  "generate": 6e5,
12515
- "generateVision": 6e5,
12516
- "testProfile": 6e5
12776
+ "generateVision": 6e5
12517
12777
  },
12518
12778
  "llm-runtime": {
12519
12779
  "complete": 6e5,
@@ -14038,17 +14298,18 @@ function composeInstanceKinds(parts, base) {
14038
14298
  * message to what the kind supports — callers never special-case a service.
14039
14299
  *
14040
14300
  * DESIGN DECISIONS (locked):
14041
- * - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
14042
- * `setTargetEnabled`), each provider persisting via the `settings-store`
14043
- * cap. Rationale: the admin UI needs one uniform surface across the
14044
- * notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
14045
- * alternative would fork the UI per addon and cannot host the
14046
- * discovery→adopt flow.
14047
- * - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
14048
- * the generated cap-mount auto-`concatCollection`-fans them across every
14049
- * registered provider (notifiers addon + HA addon) so one catalog is
14050
- * routable. `send` / `testTarget` / CRUD route to ONE provider by the
14051
- * `addonId` the generated collection router extracts from the call input.
14301
+ * - A target is an INSTANCE of this function cap (epic #440, step 6): the
14302
+ * providers serve their targets as `integration-instances` records, one
14303
+ * record kind per target kind, and the admin lists, adds, edits, switches
14304
+ * and deletes them through that cap. This cap keeps what an instance cannot
14305
+ * say: the kind catalogue (`listTargetKinds`: capabilities, delivery
14306
+ * parameters, brand icon), dispatch (`send`, `testTarget`) and the form
14307
+ * helpers (`discoverTargets`, `probeTargetConfig`).
14308
+ * - `listTargetKinds` / `discoverTargets` return arrays → the generated
14309
+ * cap-mount auto-`concatCollection`-fans them across every registered
14310
+ * provider so one catalog is routable. `send` / `testTarget` /
14311
+ * `probeTargetConfig` route to ONE provider by the `addonId` the generated
14312
+ * collection router extracts from the call input.
14052
14313
  * - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
14053
14314
  * transformer) + UDS MsgPack both round-trip typed arrays — already used by
14054
14315
  * `storage` / `storage-provider` / `recording` caps over the same path. No
@@ -14293,7 +14554,7 @@ var TargetKindCapsSchema = object({
14293
14554
  * the union is large and not meant for runtime validation here; the exported
14294
14555
  * `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
14295
14556
  */
14296
- var ConfigSchemaPassthrough$4 = unknown();
14557
+ var ConfigSchemaPassthrough$3 = unknown();
14297
14558
  var TargetKindSchema = object({
14298
14559
  kind: string(),
14299
14560
  label: string(),
@@ -14330,7 +14591,7 @@ var TargetKindSchema = object({
14330
14591
  * its raster path, which is the safe default for an unknown image.
14331
14592
  */
14332
14593
  iconMediaType: string().optional(),
14333
- configSchema: ConfigSchemaPassthrough$4,
14594
+ configSchema: ConfigSchemaPassthrough$3,
14334
14595
  /**
14335
14596
  * The config keys that decide WHERE this kind's secrets are sent (server,
14336
14597
  * base URL, instance, chat, recipient). A save that changes any of them
@@ -14352,9 +14613,11 @@ var TargetKindSchema = object({
14352
14613
  caps: TargetKindCapsSchema
14353
14614
  });
14354
14615
  /**
14355
- * A persisted target. `config` holds secrets; providers REDACT secret fields
14356
- * (return a presence marker only) when serving `listTargets` — never
14357
- * round-trip a stored secret to the UI.
14616
+ * A target as a provider's own code sees it (the notification-center bridge, the
14617
+ * send path): the flat record body split into the name, the switch and the
14618
+ * kind's fields. `config` holds secrets; a reader that serves it to a client
14619
+ * REDACTS secret fields (a presence marker only) — never round-trip a stored
14620
+ * secret to the UI.
14358
14621
  */
14359
14622
  var TargetSchema = object({
14360
14623
  id: string(),
@@ -14397,13 +14660,13 @@ var ProbeTargetConfigResultSchema = object({
14397
14660
  stateInstance: string().optional(),
14398
14661
  error: string().optional()
14399
14662
  });
14400
- method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema), { auth: "admin" }), method(object({ targetId: string() }), TargetSchema, { auth: "admin" }), method(object({
14663
+ method(object({}), array(TargetKindSchema)), method(object({
14401
14664
  kind: string(),
14402
14665
  config: record(string(), unknown()).optional(),
14403
14666
  /**
14404
14667
  * When editing / duplicating, the blank password field never round-trips
14405
14668
  * the stored token. Pass the source target id so the provider can restore
14406
- * secrets server-side before dialling (same merge as upsert).
14669
+ * secrets server-side before dialling.
14407
14670
  */
14408
14671
  targetId: string().optional()
14409
14672
  }), array(DiscoveredTargetSchema), { auth: "admin" }), method(object({
@@ -14426,27 +14689,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
14426
14689
  }), TestResultSchema, {
14427
14690
  kind: "mutation",
14428
14691
  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
14692
  });
14451
14693
  looseObject({
14452
14694
  name: string().min(1),
@@ -22714,7 +22956,6 @@ var SYSTEM_CAP_VOCABULARY = {
22714
22956
  "notification-output": system("notification delivery — reached through notifier devices and rules"),
22715
22957
  "notification-rules": system("notification rules — authored on their own page"),
22716
22958
  "oauth-integration": system(IDENTITY),
22717
- "oidc-connections": system(IDENTITY),
22718
22959
  "osd-manager": system(PIPELINE),
22719
22960
  "pipeline-executor": system(PIPELINE),
22720
22961
  "pipeline-orchestrator": system(PIPELINE),
@@ -44856,6 +45097,8 @@ var SettingsSchemaWithValuesSchema = object({
44856
45097
  });
44857
45098
  /** Patch object — keys are field names, values are the new field values. */
44858
45099
  var SettingsPatchSchema = record(string(), unknown());
45100
+ /** The scope of a scoped-settings call (D986): where the capability declared the values. */
45101
+ var ScopedSettingsScopeSchema = _enum(SCOPED_SETTINGS_SCOPES);
44859
45102
  /** Standard success response for update operations. */
44860
45103
  var SettingsUpdateResultSchema = object({ success: literal(true) });
44861
45104
  method(object({
@@ -44871,6 +45114,25 @@ method(object({
44871
45114
  kind: "mutation",
44872
45115
  auth: "admin"
44873
45116
  }), method(object({
45117
+ addonId: string(),
45118
+ cap: string(),
45119
+ scope: ScopedSettingsScopeSchema,
45120
+ nodeId: string().optional()
45121
+ }), SettingsSchemaWithValuesSchema.nullable()), method(object({
45122
+ addonId: string(),
45123
+ cap: string(),
45124
+ scope: ScopedSettingsScopeSchema,
45125
+ nodeId: string().optional(),
45126
+ patch: SettingsPatchSchema
45127
+ }), SettingsUpdateResultSchema, {
45128
+ kind: "mutation",
45129
+ auth: "admin"
45130
+ }), method(object({
45131
+ addonId: string(),
45132
+ cap: string(),
45133
+ scope: ScopedSettingsScopeSchema,
45134
+ nodeId: string().optional()
45135
+ }), record(string(), unknown()).nullable()), method(object({
44874
45136
  addonId: string(),
44875
45137
  nodeId: string().optional()
44876
45138
  }), SettingsSchemaWithValuesSchema.nullable()), method(object({
@@ -54420,7 +54682,7 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
54420
54682
  * or the redaction token KEEPS the stored secret; `{ $secretClear: true }`
54421
54683
  * clears it.
54422
54684
  */
54423
- var ConfigSchemaPassthrough$3 = custom();
54685
+ var ConfigSchemaPassthrough$2 = custom();
54424
54686
  var IntegrationInstanceIdSchema = string().min(1);
54425
54687
  var IntegrationInstanceModeSchema = _enum(["single", "multiple"]);
54426
54688
  /**
@@ -54466,7 +54728,16 @@ var IntegrationInstanceKindSchema = object({
54466
54728
  /** Relative hub path to start an interactive account link of an instance of this kind. */
54467
54729
  connectPath: string().min(1).optional(),
54468
54730
  /** Relative hub path to disconnect that account. */
54469
- disconnectPath: string().min(1).optional()
54731
+ disconnectPath: string().min(1).optional(),
54732
+ /**
54733
+ * Parts of the edit dialog the flat form cannot draw (a node picker, a model source), named by a
54734
+ * GENERIC widget id the client maps to a component; a client that knows none of them shows none.
54735
+ * `connection` widgets write connection values, `model` widgets own the model choice.
54736
+ */
54737
+ widgets: array(object({
54738
+ id: string().min(1),
54739
+ placement: _enum(["connection", "model"])
54740
+ })).optional()
54470
54741
  });
54471
54742
  /**
54472
54743
  * How devices of an instance are found. `none`: the operator adds them by hand; `lan`: the addon
@@ -54571,7 +54842,7 @@ var integrationInstancesCapability = {
54571
54842
  id: IntegrationInstanceIdSchema.nullable(),
54572
54843
  /** The kind of the create form (`id: null`) of a provider with several. */
54573
54844
  kind: string().min(1).optional()
54574
- }), ConfigSchemaPassthrough$3, { auth: "admin" }),
54845
+ }), ConfigSchemaPassthrough$2, { auth: "admin" }),
54575
54846
  listInstances: method(_void(), array(IntegrationInstanceSchema).readonly(), { auth: "admin" }),
54576
54847
  getInstance: method(object({ id: IntegrationInstanceIdSchema }), IntegrationInstanceSchema.nullable(), { auth: "admin" }),
54577
54848
  /**
@@ -55522,12 +55793,12 @@ var LlmModelInfoSchema = object({
55522
55793
  });
55523
55794
  /**
55524
55795
  * The provider-specific part of a profile, validated by the provider that owns
55525
- * the kind (`upsertProfile` refuses what it does not accept). A field its
55796
+ * the kind (saving an instance refuses what it does not accept). A field its
55526
55797
  * `connectionSchema` declares `type: 'password'` is a secret: it is held in the
55527
55798
  * keychain, never in the row, and reads back as the redaction marker.
55528
55799
  */
55529
55800
  var LlmProviderConfigSchema = record(string(), unknown());
55530
- var LlmProfileSchema = object({
55801
+ object({
55531
55802
  id: string(),
55532
55803
  name: string(),
55533
55804
  /** The provider-declared kind (`LlmProfileKindDescriptor.kind`). */
@@ -55621,8 +55892,8 @@ var LlmProviderWidgetSchema = object({
55621
55892
  /** ConfigUISchema tree passed through untyped on the wire (the
55622
55893
  * notification-output `ConfigSchemaPassthrough` precedent at
55623
55894
  * notification-output.cap.ts:151); the exported TS type re-tightens it. */
55624
- var ConfigSchemaPassthrough$2 = unknown();
55625
- var LlmProfileKindDescriptorSchema = object({
55895
+ var ConfigSchemaPassthrough$1 = unknown();
55896
+ object({
55626
55897
  kind: LlmProfileKindSchema,
55627
55898
  label: string(),
55628
55899
  /** A generic icon name (`cloud`, `plug`, `cpu`) — never a glyph or a logo. */
@@ -55630,9 +55901,9 @@ var LlmProfileKindDescriptorSchema = object({
55630
55901
  /** Stamped by each provider so the concat-fanned catalog stays routable. */
55631
55902
  addonId: string(),
55632
55903
  /** The provider's own fields (`providerConfig`); `password` fields are keychain-held. */
55633
- connectionSchema: ConfigSchemaPassthrough$2,
55904
+ connectionSchema: ConfigSchemaPassthrough$1,
55634
55905
  /** Provider fields that belong under "Advanced" (extra headers, runtime tuning). */
55635
- advancedSchema: ConfigSchemaPassthrough$2.optional(),
55906
+ advancedSchema: ConfigSchemaPassthrough$1.optional(),
55636
55907
  /** The kind's defaults; a model from `listModels` may override any of them. */
55637
55908
  features: LlmModelFeaturesSchema,
55638
55909
  /** `false` = the provider stamps `supportsVision` itself (from what a node reports). */
@@ -55761,20 +56032,7 @@ method(LlmGenerateBaseInputSchema, LlmGenerateResultSchema, {
55761
56032
  }), method(object({
55762
56033
  addonId: string().optional(),
55763
56034
  requestId: string()
55764
- }), _void(), { kind: "mutation" }), method(object({}), array(LlmProfileKindDescriptorSchema)), method(object({}), array(LlmProfileSchema)), method(object({ profile: LlmProfileSchema }), LlmProfileSchema, {
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, {
56035
+ }), _void(), { kind: "mutation" }), method(LlmListModelsInputSchema, LlmListModelsResultSchema, {
55778
56036
  kind: "mutation",
55779
56037
  auth: "admin"
55780
56038
  }), method(object({}), array(LlmDefaultSchema)), method(object({
@@ -56769,20 +57027,7 @@ method(_void(), MeshStatusSchema), method(object({
56769
57027
  /** Optional hostname override the host should advertise once joined. */
56770
57028
  hostname: string().optional() }), object({
56771
57029
  /** 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() })), method(object({
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" });
57030
+ 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
57031
  object({
56787
57032
  value: number().nullable().meta(readingMeta("device", { label: "Total" })),
56788
57033
  lastFetchedAt: number()
@@ -66440,61 +66685,6 @@ var OauthIntegrationDescriptorSchema = object({
66440
66685
  });
66441
66686
  method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
66442
66687
  /**
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
66688
  * Generic on-screen-display (video overlay) cap. Each camera exposes
66499
66689
  * a firmware-defined list of overlays (channel name, timestamp,
66500
66690
  * watermark, logo, …); the cap models them as a homogeneous array of
@@ -72680,21 +72870,6 @@ method(object({
72680
72870
  */
72681
72871
  ttlSec: union([number().int().positive(), literal("never")]).optional()
72682
72872
  }), 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
72873
  method(object({
72699
72874
  location: StorageLocationRefSchema,
72700
72875
  relativePath: string()
@@ -72756,42 +72931,7 @@ method(object({
72756
72931
  }), _instanceof(Uint8Array), { auth: "admin" }), method(object({ downloadId: string() }), _void(), {
72757
72932
  kind: "mutation",
72758
72933
  auth: "admin"
72759
- }), method(object({ type: StorageLocationTypeSchema.optional() }), array(StorageLocationSchema).readonly()), method(_void(), array(StorageLocationDeclarationSchema).readonly()), method(StorageLocationSchema.omit({
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" });
72934
+ }), method(object({ type: StorageLocationTypeSchema.optional() }), array(StorageLocationSchema).readonly()), method(_void(), array(StorageLocationDeclarationSchema).readonly()), method(_void(), array(StorageDrainProgressSchema).readonly());
72795
72935
  /** One table of the settings database. */
72796
72936
  var StorageTableSchema = object({
72797
72937
  /** The table's full name, e.g. `recorder:addon-settings` or `addon-device-settings`. */
@@ -74022,7 +74162,7 @@ var TerminalInstanceInfoSchema = object({
74022
74162
  /**
74023
74163
  * False while the node the instance is bound to is not in the cluster
74024
74164
  * topology (forgotten, renamed, re-paired). The instance is kept; the
74025
- * operator re-points it with `updateInstance({ targetNodeId })`.
74165
+ * operator re-points it on the Terminal page.
74026
74166
  */
74027
74167
  nodeInCluster: boolean(),
74028
74168
  profileId: string(),
@@ -74060,41 +74200,7 @@ var TerminalOutputBatchSchema = object({
74060
74200
  snapshot: string().optional(),
74061
74201
  events: array(TerminalOutputEventSchema).readonly()
74062
74202
  });
74063
- method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
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({
74203
+ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalLegacyCameraSchema).readonly(), { auth: "admin" }), method(object({
74098
74204
  stableId: string().min(1),
74099
74205
  name: string().trim().min(1).max(160).optional()
74100
74206
  }), TerminalInstanceInfoSchema, {
@@ -76912,6 +77018,20 @@ Object.freeze({
76912
77018
  access: "view",
76913
77019
  role: "admin"
76914
77020
  },
77021
+ "addonSettings.getScopedSettings": {
77022
+ capName: "addon-settings",
77023
+ capScope: "system",
77024
+ addonId: null,
77025
+ access: "view",
77026
+ role: "admin"
77027
+ },
77028
+ "addonSettings.readScopedValues": {
77029
+ capName: "addon-settings",
77030
+ capScope: "system",
77031
+ addonId: null,
77032
+ access: "view",
77033
+ role: "admin"
77034
+ },
76915
77035
  "addonSettings.unsetStoredSettingsKeys": {
76916
77036
  capName: "addon-settings",
76917
77037
  capScope: "system",
@@ -76933,6 +77053,13 @@ Object.freeze({
76933
77053
  access: "create",
76934
77054
  role: "admin"
76935
77055
  },
77056
+ "addonSettings.updateScopedSettings": {
77057
+ capName: "addon-settings",
77058
+ capScope: "system",
77059
+ addonId: null,
77060
+ access: "create",
77061
+ role: "admin"
77062
+ },
76936
77063
  "addonWidgets.listWidgets": {
76937
77064
  capName: "addon-widgets",
76938
77065
  capScope: "system",
@@ -80384,13 +80511,6 @@ Object.freeze({
80384
80511
  access: "delete",
80385
80512
  role: "admin"
80386
80513
  },
80387
- "llm.deleteProfile": {
80388
- capName: "llm",
80389
- capScope: "system",
80390
- addonId: null,
80391
- access: "delete",
80392
- role: "admin"
80393
- },
80394
80514
  "llm.generate": {
80395
80515
  capName: "llm",
80396
80516
  capScope: "system",
@@ -80454,20 +80574,6 @@ Object.freeze({
80454
80574
  access: "view",
80455
80575
  role: "admin"
80456
80576
  },
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
80577
  "llm.listRuntimeNodes": {
80472
80578
  capName: "llm",
80473
80579
  capScope: "system",
@@ -80475,13 +80581,6 @@ Object.freeze({
80475
80581
  access: "view",
80476
80582
  role: "admin"
80477
80583
  },
80478
- "llm.migrateRawSecrets": {
80479
- capName: "llm",
80480
- capScope: "system",
80481
- addonId: null,
80482
- access: "create",
80483
- role: "admin"
80484
- },
80485
80584
  "llm.resolveModelRef": {
80486
80585
  capName: "llm",
80487
80586
  capScope: "system",
@@ -80510,20 +80609,6 @@ Object.freeze({
80510
80609
  access: "create",
80511
80610
  role: "admin"
80512
80611
  },
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
80612
  "llmRuntime.appleAvailability": {
80528
80613
  capName: "llm-runtime",
80529
80614
  capScope: "system",
@@ -81028,13 +81113,6 @@ Object.freeze({
81028
81113
  access: "create",
81029
81114
  role: "admin"
81030
81115
  },
81031
- "meshNetwork.testConnection": {
81032
- capName: "mesh-network",
81033
- capScope: "system",
81034
- addonId: null,
81035
- access: "create",
81036
- role: "admin"
81037
- },
81038
81116
  "meter.getStatus": {
81039
81117
  capName: "meter",
81040
81118
  capScope: "device",
@@ -81693,13 +81771,6 @@ Object.freeze({
81693
81771
  access: "create",
81694
81772
  role: "admin"
81695
81773
  },
81696
- "notificationOutput.deleteTarget": {
81697
- capName: "notification-output",
81698
- capScope: "system",
81699
- addonId: null,
81700
- access: "delete",
81701
- role: "admin"
81702
- },
81703
81774
  "notificationOutput.discoverTargets": {
81704
81775
  capName: "notification-output",
81705
81776
  capScope: "system",
@@ -81707,13 +81778,6 @@ Object.freeze({
81707
81778
  access: "view",
81708
81779
  role: "admin"
81709
81780
  },
81710
- "notificationOutput.getTarget": {
81711
- capName: "notification-output",
81712
- capScope: "system",
81713
- addonId: null,
81714
- access: "view",
81715
- role: "admin"
81716
- },
81717
81781
  "notificationOutput.listTargetKinds": {
81718
81782
  capName: "notification-output",
81719
81783
  capScope: "system",
@@ -81721,13 +81785,6 @@ Object.freeze({
81721
81785
  access: "view",
81722
81786
  role: "admin"
81723
81787
  },
81724
- "notificationOutput.listTargets": {
81725
- capName: "notification-output",
81726
- capScope: "system",
81727
- addonId: null,
81728
- access: "view",
81729
- role: "admin"
81730
- },
81731
81788
  "notificationOutput.probeTargetConfig": {
81732
81789
  capName: "notification-output",
81733
81790
  capScope: "system",
@@ -81742,13 +81799,6 @@ Object.freeze({
81742
81799
  access: "create",
81743
81800
  role: "admin"
81744
81801
  },
81745
- "notificationOutput.setTargetEnabled": {
81746
- capName: "notification-output",
81747
- capScope: "system",
81748
- addonId: null,
81749
- access: "create",
81750
- role: "admin"
81751
- },
81752
81802
  "notificationOutput.testTarget": {
81753
81803
  capName: "notification-output",
81754
81804
  capScope: "system",
@@ -81756,13 +81806,6 @@ Object.freeze({
81756
81806
  access: "create",
81757
81807
  role: "admin"
81758
81808
  },
81759
- "notificationOutput.upsertTarget": {
81760
- capName: "notification-output",
81761
- capScope: "system",
81762
- addonId: null,
81763
- access: "create",
81764
- role: "admin"
81765
- },
81766
81809
  "notificationRules.activateAlarmProfile": {
81767
81810
  capName: "notification-rules",
81768
81811
  capScope: "system",
@@ -82022,41 +82065,6 @@ Object.freeze({
82022
82065
  access: "view",
82023
82066
  role: "admin"
82024
82067
  },
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
82068
  "osd.getStatus": {
82061
82069
  capName: "osd",
82062
82070
  capScope: "device",
@@ -85088,13 +85096,6 @@ Object.freeze({
85088
85096
  access: "delete",
85089
85097
  role: "admin"
85090
85098
  },
85091
- "storage.deleteLocation": {
85092
- capName: "storage",
85093
- capScope: "system",
85094
- addonId: null,
85095
- access: "delete",
85096
- role: "admin"
85097
- },
85098
85099
  "storage.endDownload": {
85099
85100
  capName: "storage",
85100
85101
  capScope: "system",
@@ -85151,13 +85152,6 @@ Object.freeze({
85151
85152
  access: "view",
85152
85153
  role: "admin"
85153
85154
  },
85154
- "storage.listProviders": {
85155
- capName: "storage",
85156
- capScope: "system",
85157
- addonId: null,
85158
- access: "view",
85159
- role: "admin"
85160
- },
85161
85155
  "storage.read": {
85162
85156
  capName: "storage",
85163
85157
  capScope: "system",
@@ -85179,27 +85173,6 @@ Object.freeze({
85179
85173
  access: "view",
85180
85174
  role: "admin"
85181
85175
  },
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
85176
  "storage.write": {
85204
85177
  capName: "storage",
85205
85178
  capScope: "system",
@@ -85977,27 +85950,6 @@ Object.freeze({
85977
85950
  access: "create",
85978
85951
  role: "admin"
85979
85952
  },
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
85953
  "terminalSession.listLegacyCameras": {
86002
85954
  capName: "terminal-session",
86003
85955
  capScope: "system",
@@ -86040,20 +85992,6 @@ Object.freeze({
86040
85992
  access: "create",
86041
85993
  role: "admin"
86042
85994
  },
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
85995
  "terminalSession.writeInput": {
86058
85996
  capName: "terminal-session",
86059
85997
  capScope: "system",
@@ -145985,17 +145923,6 @@ function scrub(message, secret) {
145985
145923
  function mintRelayId() {
145986
145924
  return `relay-${(0, node_crypto.randomUUID)().slice(0, 8)}`;
145987
145925
  }
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
145926
  var RELAY_LIST_MAX = 200;
146000
145927
  function hasText(value) {
146001
145928
  return typeof value === "string" && value.length > 0;
@@ -146248,44 +146175,10 @@ var SmtpNodemailerAddon = class extends BaseAddon {
146248
146175
  const rows = (await records.kind(smtpRelaysKind).query({ limit: RELAY_LIST_MAX })).records;
146249
146176
  return (rows.find((row) => row.data.host.length > 0) ?? rows[0])?.id;
146250
146177
  }
146251
- /** The relay form. Its values live on the relay record, never in `addon-settings`. */
146178
+ /** The relay form. */
146252
146179
  async integrationFormSchema(_instance) {
146253
146180
  return this.relayForm();
146254
146181
  }
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
146182
  /** Probe a relay (EHLO + AUTH) with the form's values, falling back to the stored ones. */
146290
146183
  async probe(id, values) {
146291
146184
  const stored = id !== null && this.instances !== null ? await this.instances.getResolved(id) : null;