@camstack/addon-mqtt-broker 1.2.150 → 1.2.151
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 +6 -0
- package/dist/mqtt-broker.addon.js +209 -56
- package/dist/mqtt-broker.addon.mjs +209 -56
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.2.151] - 2026-11-05
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- MQTT embedded broker settings are declared on the cluster hook; the form and stored values are unchanged.
|
|
15
|
+
|
|
10
16
|
## [1.2.150] - 2026-11-04
|
|
11
17
|
|
|
12
18
|
### Changed
|
|
@@ -6028,7 +6028,7 @@ var ZodIssueCode = {
|
|
|
6028
6028
|
var ZodFirstPartyTypeKind;
|
|
6029
6029
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
6030
6030
|
//#endregion
|
|
6031
|
-
//#region ../types/dist/sleep-
|
|
6031
|
+
//#region ../types/dist/sleep-DEZaLbiu.mjs
|
|
6032
6032
|
/**
|
|
6033
6033
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6034
6034
|
* window to float samples (D455).
|
|
@@ -6628,7 +6628,7 @@ var NOT_RUN = {
|
|
|
6628
6628
|
* throws: an unreachable or refusing engine is logged and reported `declared: false`,
|
|
6629
6629
|
* because the hub (and this addon's boot) must not hang on a migration.
|
|
6630
6630
|
*/
|
|
6631
|
-
async function runAddonMigrations(host, migrations, logger) {
|
|
6631
|
+
async function runAddonMigrations(host, migrations, logger, options = {}) {
|
|
6632
6632
|
const first = migrations[0];
|
|
6633
6633
|
if (first === void 0) return NOT_RUN;
|
|
6634
6634
|
const owner = first.meta.owner;
|
|
@@ -6657,7 +6657,9 @@ async function runAddonMigrations(host, migrations, logger) {
|
|
|
6657
6657
|
else if (status === "blocked") blocked.push(id);
|
|
6658
6658
|
else skipped.push(id);
|
|
6659
6659
|
};
|
|
6660
|
+
const selected = options.only === void 0 ? null : new Set(options.only);
|
|
6660
6661
|
for (const step of declaration.steps) {
|
|
6662
|
+
if (selected !== null && !selected.has(step.id)) continue;
|
|
6661
6663
|
const bound = byId.get(step.id);
|
|
6662
6664
|
if (bound === void 0 || step.action === "skip") {
|
|
6663
6665
|
skipped.push(step.id);
|
|
@@ -6835,6 +6837,12 @@ function projectStore(store, perNodeKeys, nodeId) {
|
|
|
6835
6837
|
}
|
|
6836
6838
|
return out;
|
|
6837
6839
|
}
|
|
6840
|
+
/** Every scope, in the order the guard and the docs list them. */
|
|
6841
|
+
var SCOPED_SETTINGS_SCOPES = [
|
|
6842
|
+
"cluster",
|
|
6843
|
+
"device-defaults",
|
|
6844
|
+
"node"
|
|
6845
|
+
];
|
|
6838
6846
|
/**
|
|
6839
6847
|
* The address of one keychain value: `secret://<owner>/<scope>/<fieldPath>`.
|
|
6840
6848
|
*
|
|
@@ -7726,6 +7734,13 @@ var BaseAddon = class {
|
|
|
7726
7734
|
*/
|
|
7727
7735
|
secretStatePaths = [];
|
|
7728
7736
|
_addonSecretTree = null;
|
|
7737
|
+
/**
|
|
7738
|
+
* D986 M4: the scoped schemas this addon declared, resolved once per capability
|
|
7739
|
+
* (`loadScopedSchemas`) so the sync readers (`perNodeKeys`, the secret tree, the restart check)
|
|
7740
|
+
* see them. Empty until loaded: the readers then fall back to {@link globalSettingsSchema}.
|
|
7741
|
+
*/
|
|
7742
|
+
_scopedByCap = /* @__PURE__ */ new Map();
|
|
7743
|
+
_nodeKeysByCap = /* @__PURE__ */ new Map();
|
|
7729
7744
|
_deviceSecretTree = null;
|
|
7730
7745
|
/** Refs the last resolved config pointed at — a change to one re-resolves. */
|
|
7731
7746
|
_configSecretRefs = /* @__PURE__ */ new Set();
|
|
@@ -7795,6 +7810,7 @@ var BaseAddon = class {
|
|
|
7795
7810
|
this._ctx = context;
|
|
7796
7811
|
this._secretSettings = null;
|
|
7797
7812
|
}
|
|
7813
|
+
await this.loadScopedSchemas();
|
|
7798
7814
|
await this.resolveConfig();
|
|
7799
7815
|
if (secrets !== void 0) this._secretChangeUnsub = secrets.onChange((ref) => {
|
|
7800
7816
|
if (this._configSecretRefs.has(ref)) this.scheduleSecretReresolve(SECRET_CHANGE_DEBOUNCE_MS);
|
|
@@ -7804,6 +7820,7 @@ var BaseAddon = class {
|
|
|
7804
7820
|
const normalized = normalizeAddonInitResult(result);
|
|
7805
7821
|
const providers = normalized && "providers" in normalized && normalized.providers ? normalized.providers : [];
|
|
7806
7822
|
this._registeredCapNames = providers.map((p) => p.capability.name);
|
|
7823
|
+
await this.loadScopedSchemas();
|
|
7807
7824
|
return normalized;
|
|
7808
7825
|
}
|
|
7809
7826
|
/**
|
|
@@ -7817,14 +7834,18 @@ var BaseAddon = class {
|
|
|
7817
7834
|
* nothing; the boot continues. A migration that FAILED (or was blocked by one)
|
|
7818
7835
|
* and declares `onFailure: 'block-owner'` makes this throw, so the addon does not
|
|
7819
7836
|
* serve data whose shape it cannot trust; `tolerate` migrations never do.
|
|
7837
|
+
*
|
|
7838
|
+
* ALWAYS pass the whole catalogue; a phase that must run only some of it passes
|
|
7839
|
+
* `{ only: [ids] }` — never a filtered catalogue (the engine would judge the
|
|
7840
|
+
* omitted applied ids "newer").
|
|
7820
7841
|
*/
|
|
7821
|
-
async runMigrations(migrations) {
|
|
7842
|
+
async runMigrations(migrations, options) {
|
|
7822
7843
|
const api = this.ctx.api.migrations;
|
|
7823
7844
|
const report = await runAddonMigrations({
|
|
7824
7845
|
declareOwner: (input) => api.declareOwner.mutate(input),
|
|
7825
7846
|
startMigration: (input) => api.startMigration.mutate(input),
|
|
7826
7847
|
finishMigration: (input) => api.finishMigration.mutate(input)
|
|
7827
|
-
}, migrations, this.ctx.logger);
|
|
7848
|
+
}, migrations, this.ctx.logger, options);
|
|
7828
7849
|
if (report.blockOwner.length > 0) throw new AddonMigrationsBlockedError(report.blockOwner);
|
|
7829
7850
|
return report;
|
|
7830
7851
|
}
|
|
@@ -7888,6 +7909,16 @@ var BaseAddon = class {
|
|
|
7888
7909
|
schema(schema) {
|
|
7889
7910
|
return schema;
|
|
7890
7911
|
}
|
|
7912
|
+
/**
|
|
7913
|
+
* The capability names whose scoped settings schemas ({@link clusterSettingsSchema},
|
|
7914
|
+
* {@link nodeSettingsSchema}, {@link deviceDefaultsSchema}) this addon declares. Read BEFORE
|
|
7915
|
+
* `onInitialize`, when the providers it registers are not known yet: the first config resolve
|
|
7916
|
+
* must already know which keys are per node. Names the providers register at init are added
|
|
7917
|
+
* once known.
|
|
7918
|
+
*/
|
|
7919
|
+
scopedSettingsCapabilities() {
|
|
7920
|
+
return [];
|
|
7921
|
+
}
|
|
7891
7922
|
/** Override to provide global-level settings UI schema. */
|
|
7892
7923
|
globalSettingsSchema(_cap) {
|
|
7893
7924
|
return null;
|
|
@@ -7931,7 +7962,8 @@ var BaseAddon = class {
|
|
|
7931
7962
|
return [];
|
|
7932
7963
|
}
|
|
7933
7964
|
async getGlobalSettings(overlay, cap, nodeId) {
|
|
7934
|
-
|
|
7965
|
+
await this.loadScopedSchemas(cap);
|
|
7966
|
+
const schema = this.globalSettingsSchema(cap) ?? this.scopedFormSchema(cap);
|
|
7935
7967
|
if (!schema) return { sections: [] };
|
|
7936
7968
|
const projected = await this.readRawProjectedStore(nodeId, cap);
|
|
7937
7969
|
return hydrateSchema(schema, overlay ? await this.overlayKeepingMarkers(projected, overlay) : projected, { inlineSecretsAsViews: true });
|
|
@@ -7966,10 +7998,9 @@ var BaseAddon = class {
|
|
|
7966
7998
|
*
|
|
7967
7999
|
* Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
|
|
7968
8000
|
* needs its connection fields, the default integration the addon's own sections. It is the
|
|
7969
|
-
* SHAPE of the form only — the values live
|
|
7970
|
-
* unchanged (`integrations.setSettings` for an account integration).
|
|
8001
|
+
* SHAPE of the form only — the values live on the instance record.
|
|
7971
8002
|
*/
|
|
7972
|
-
async
|
|
8003
|
+
async integrationFormSchema(_instance) {
|
|
7973
8004
|
return null;
|
|
7974
8005
|
}
|
|
7975
8006
|
/**
|
|
@@ -8015,7 +8046,7 @@ var BaseAddon = class {
|
|
|
8015
8046
|
* per-instance schema when it declares one, else its global schema (what they always showed).
|
|
8016
8047
|
*/
|
|
8017
8048
|
async getIntegrationFormSchema(instance, nodeId) {
|
|
8018
|
-
const scoped = await this.
|
|
8049
|
+
const scoped = await this.integrationFormSchema(instance);
|
|
8019
8050
|
if (scoped === null) return this.getGlobalSettings(void 0, void 0, nodeId);
|
|
8020
8051
|
return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
|
|
8021
8052
|
}
|
|
@@ -8063,6 +8094,7 @@ var BaseAddon = class {
|
|
|
8063
8094
|
* resolved blob back is a no-op for every unchanged secret.
|
|
8064
8095
|
*/
|
|
8065
8096
|
async resolveGlobalStore(nodeId, cap) {
|
|
8097
|
+
await this.loadScopedSchemas(cap);
|
|
8066
8098
|
const raw = await this._ctx?.settings?.readAddonStore() ?? {};
|
|
8067
8099
|
return this.projectForNode(raw, nodeId, cap);
|
|
8068
8100
|
}
|
|
@@ -8073,6 +8105,7 @@ var BaseAddon = class {
|
|
|
8073
8105
|
}
|
|
8074
8106
|
/** The PROJECTED store with its markers — the form hydrate only (D798). */
|
|
8075
8107
|
async readRawProjectedStore(nodeId, cap) {
|
|
8108
|
+
await this.loadScopedSchemas(cap);
|
|
8076
8109
|
const raw = await this.rawSettings()?.readAddonStore() ?? {};
|
|
8077
8110
|
return this.projectForNode(raw, nodeId, cap);
|
|
8078
8111
|
}
|
|
@@ -8175,6 +8208,7 @@ var BaseAddon = class {
|
|
|
8175
8208
|
await this.applyGlobalPatch(patch, nodeId);
|
|
8176
8209
|
}
|
|
8177
8210
|
async applyGlobalPatch(barePatch, nodeId) {
|
|
8211
|
+
await this.loadScopedSchemas();
|
|
8178
8212
|
const keys = this.perNodeKeys();
|
|
8179
8213
|
const localNode = normalizeNodeId(this._ctx?.kernel?.localNodeId);
|
|
8180
8214
|
const target = normalizeNodeId(nodeId ?? this._ctx?.kernel?.localNodeId);
|
|
@@ -8188,7 +8222,8 @@ var BaseAddon = class {
|
|
|
8188
8222
|
await this.resolveConfig();
|
|
8189
8223
|
await this.onConfigChanged();
|
|
8190
8224
|
this.emitLifecycle(EventCategory.AddonUpdated, { level: "global" });
|
|
8191
|
-
|
|
8225
|
+
const legacy = this.globalSettingsSchema();
|
|
8226
|
+
this.maybeAutoRestart(Object.keys(barePatch), [...legacy === null ? [] : [legacy], ...this.loadedScopedSchemas().map((entry) => entry.schema)]);
|
|
8192
8227
|
}
|
|
8193
8228
|
/**
|
|
8194
8229
|
* The set of field keys the global settings schema declares `perNode: true`
|
|
@@ -8196,14 +8231,67 @@ var BaseAddon = class {
|
|
|
8196
8231
|
* declarations). Empty set ⇒ every per-node code path is bypassed and the
|
|
8197
8232
|
* settings API behaves exactly like the legacy node-agnostic one.
|
|
8198
8233
|
*/
|
|
8199
|
-
|
|
8234
|
+
/**
|
|
8235
|
+
* Load the scoped schemas of every capability this addon declares (the override and the
|
|
8236
|
+
* providers registered at init, plus `extraCap`) that is not loaded yet, then drop what was
|
|
8237
|
+
* derived from the previous set. Idempotent.
|
|
8238
|
+
*/
|
|
8239
|
+
async loadScopedSchemas(extraCap) {
|
|
8240
|
+
const caps = new Set([
|
|
8241
|
+
...this.scopedSettingsCapabilities(),
|
|
8242
|
+
...this._registeredCapNames,
|
|
8243
|
+
...extraCap === void 0 ? [] : [extraCap]
|
|
8244
|
+
]);
|
|
8245
|
+
let added = false;
|
|
8246
|
+
for (const cap of caps) {
|
|
8247
|
+
if (this._scopedByCap.has(cap)) continue;
|
|
8248
|
+
const loaded = [];
|
|
8249
|
+
for (const scope of SCOPED_SETTINGS_SCOPES) {
|
|
8250
|
+
const schema = await this.getScopedSettingsSchema(scope, cap);
|
|
8251
|
+
if (schema !== null) loaded.push({
|
|
8252
|
+
scope,
|
|
8253
|
+
schema
|
|
8254
|
+
});
|
|
8255
|
+
}
|
|
8256
|
+
this._scopedByCap.set(cap, loaded);
|
|
8257
|
+
added = true;
|
|
8258
|
+
}
|
|
8259
|
+
if (!added) return;
|
|
8260
|
+
this._nodeKeysByCap = /* @__PURE__ */ new Map();
|
|
8261
|
+
this._addonSecretTree = null;
|
|
8262
|
+
}
|
|
8263
|
+
/**
|
|
8264
|
+
* The form the settings API serves while an addon declares no {@link globalSettingsSchema}: the
|
|
8265
|
+
* sections of its scoped schemas, so dropping the old hook does not blank the form.
|
|
8266
|
+
*/
|
|
8267
|
+
scopedFormSchema(cap) {
|
|
8268
|
+
const byId = /* @__PURE__ */ new Map();
|
|
8269
|
+
for (const entry of this.loadedScopedSchemas(cap)) for (const section of entry.schema.sections) if (!byId.has(section.id)) byId.set(section.id, section);
|
|
8270
|
+
return byId.size === 0 ? null : { sections: [...byId.values()] };
|
|
8271
|
+
}
|
|
8272
|
+
/** Every loaded scoped schema of `cap`, or of every loaded capability. */
|
|
8273
|
+
loadedScopedSchemas(cap) {
|
|
8274
|
+
if (cap !== void 0) return this._scopedByCap.get(cap) ?? [];
|
|
8275
|
+
return [...this._scopedByCap.values()].flat();
|
|
8276
|
+
}
|
|
8277
|
+
/**
|
|
8278
|
+
* The field keys that are stored per node: every field of a {@link nodeSettingsSchema}, plus
|
|
8279
|
+
* the fields the legacy {@link globalSettingsSchema} still marks `perNode: true`. Derived once
|
|
8280
|
+
* per `cap` argument and memoized (schemas are static declarations). Empty set ⇒ every
|
|
8281
|
+
* per-node code path is bypassed and the settings API behaves like the node-agnostic one.
|
|
8282
|
+
* Call {@link loadScopedSchemas} first (the async seams do).
|
|
8283
|
+
*/
|
|
8200
8284
|
perNodeKeys(cap) {
|
|
8201
8285
|
const cacheKey = cap ?? "";
|
|
8202
|
-
const cached = this.
|
|
8286
|
+
const cached = this._nodeKeysByCap.get(cacheKey);
|
|
8203
8287
|
if (cached) return cached;
|
|
8204
|
-
const
|
|
8205
|
-
const keys = new Set(
|
|
8206
|
-
this.
|
|
8288
|
+
const legacy = this.globalSettingsSchema(cap);
|
|
8289
|
+
const keys = new Set(legacy ? legacy.sections.flatMap((section) => collectPerNodeFieldKeys(section.fields)) : []);
|
|
8290
|
+
for (const { scope, schema } of this.loadedScopedSchemas(cap)) {
|
|
8291
|
+
if (scope !== "node") continue;
|
|
8292
|
+
for (const section of schema.sections) for (const key of collectValueFieldKeys(section.fields)) keys.add(key);
|
|
8293
|
+
}
|
|
8294
|
+
this._nodeKeysByCap.set(cacheKey, keys);
|
|
8207
8295
|
return keys;
|
|
8208
8296
|
}
|
|
8209
8297
|
/**
|
|
@@ -8213,10 +8301,9 @@ var BaseAddon = class {
|
|
|
8213
8301
|
* time to return its response before the addon is torn down and
|
|
8214
8302
|
* re-initialised by `AddonRegistryService.restartAddon`.
|
|
8215
8303
|
*/
|
|
8216
|
-
maybeAutoRestart(patchKeys,
|
|
8217
|
-
if (!schema) return;
|
|
8304
|
+
maybeAutoRestart(patchKeys, schemas) {
|
|
8218
8305
|
const restartKeys = /* @__PURE__ */ new Set();
|
|
8219
|
-
for (const section of schema.sections) for (const field of section.fields) {
|
|
8306
|
+
for (const schema of schemas) for (const section of schema.sections) for (const field of section.fields) {
|
|
8220
8307
|
if (field.type === "separator" || field.type === "info") continue;
|
|
8221
8308
|
if (field.requiresRestart) restartKeys.add(field.key);
|
|
8222
8309
|
}
|
|
@@ -8412,12 +8499,14 @@ var BaseAddon = class {
|
|
|
8412
8499
|
* here, in the addon's own process, so the hub keeps no copy of it.
|
|
8413
8500
|
*/
|
|
8414
8501
|
async getDeclaredSettingsKeys() {
|
|
8502
|
+
await this.loadScopedSchemas();
|
|
8415
8503
|
return { keys: [...this.declaredKeySet()].toSorted() };
|
|
8416
8504
|
}
|
|
8417
8505
|
declaredKeySet() {
|
|
8418
8506
|
const keys = new Set(Object.keys(this.defaults));
|
|
8419
8507
|
const schema = this.globalSettingsSchema();
|
|
8420
8508
|
if (schema) for (const section of schema.sections) for (const key of collectFieldKeys(section.fields)) keys.add(key);
|
|
8509
|
+
for (const { schema: scoped } of this.loadedScopedSchemas()) for (const section of scoped.sections) for (const key of collectFieldKeys(section.fields)) keys.add(key);
|
|
8421
8510
|
for (const key of this._declaredStateKeys) keys.add(key);
|
|
8422
8511
|
for (const path of this.secretStatePaths) {
|
|
8423
8512
|
const root = path.split(/[.[]/, 1)[0];
|
|
@@ -8513,7 +8602,11 @@ var BaseAddon = class {
|
|
|
8513
8602
|
}
|
|
8514
8603
|
/** The addon store's secret tree: schema fields by TYPE, plus `secretStatePaths`. */
|
|
8515
8604
|
addonSecretTree() {
|
|
8516
|
-
this._addonSecretTree
|
|
8605
|
+
if (this._addonSecretTree === null) {
|
|
8606
|
+
const tree = new Map(secretTreeFromSchema(this.globalSettingsSchema()));
|
|
8607
|
+
for (const { schema } of this.loadedScopedSchemas()) for (const [key, node] of secretTreeFromSchema(schema)) tree.set(key, node);
|
|
8608
|
+
this._addonSecretTree = mergeSecretStatePaths(tree, this.secretStatePaths);
|
|
8609
|
+
}
|
|
8517
8610
|
return this._addonSecretTree;
|
|
8518
8611
|
}
|
|
8519
8612
|
deviceSecretTree() {
|
|
@@ -8763,6 +8856,23 @@ function dropPerNodeFields(fields) {
|
|
|
8763
8856
|
}
|
|
8764
8857
|
return kept;
|
|
8765
8858
|
}
|
|
8859
|
+
/** The keys of the value-holding fields, recursing into layout containers. */
|
|
8860
|
+
function collectValueFieldKeys(fields) {
|
|
8861
|
+
const collected = [];
|
|
8862
|
+
for (const field of fields) {
|
|
8863
|
+
if (field.type === "group") {
|
|
8864
|
+
collected.push(...collectValueFieldKeys(field.fields));
|
|
8865
|
+
continue;
|
|
8866
|
+
}
|
|
8867
|
+
if (field.type === "sub-tabs") {
|
|
8868
|
+
for (const tab of field.tabs) collected.push(...collectValueFieldKeys(tab.fields));
|
|
8869
|
+
continue;
|
|
8870
|
+
}
|
|
8871
|
+
if (field.type === "separator" || field.type === "info") continue;
|
|
8872
|
+
if ("key" in field && typeof field.key === "string") collected.push(field.key);
|
|
8873
|
+
}
|
|
8874
|
+
return collected;
|
|
8875
|
+
}
|
|
8766
8876
|
function collectFieldKeys(fields) {
|
|
8767
8877
|
const collected = [];
|
|
8768
8878
|
for (const field of fields) {
|
|
@@ -9289,6 +9399,7 @@ function defineEntryKind(name, spec) {
|
|
|
9289
9399
|
class: "config",
|
|
9290
9400
|
writeTrigger: spec.writeTrigger ?? "an operator adds or edits an entry in the entries UI",
|
|
9291
9401
|
retention: { none: "an entry goes only when the operator deletes it" },
|
|
9402
|
+
...spec.maxDataBytes === void 0 ? {} : { maxDataBytes: spec.maxDataBytes },
|
|
9292
9403
|
...spec.database === void 0 ? {} : { database: spec.database },
|
|
9293
9404
|
...spec.indexes === void 0 ? {} : { indexes: spec.indexes },
|
|
9294
9405
|
...spec.secretArrayKeys === void 0 ? {} : { secretArrayKeys: spec.secretArrayKeys },
|
|
@@ -11954,7 +12065,7 @@ object({
|
|
|
11954
12065
|
params: record(string(), union([string(), number()])).optional()
|
|
11955
12066
|
});
|
|
11956
12067
|
//#endregion
|
|
11957
|
-
//#region ../types/dist/composition-
|
|
12068
|
+
//#region ../types/dist/composition-pOHbTzRB.mjs
|
|
11958
12069
|
/**
|
|
11959
12070
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11960
12071
|
*
|
|
@@ -14545,7 +14656,13 @@ var MigrationLedgerEntrySchema = object({
|
|
|
14545
14656
|
* joined by the engine from the catalogues it knows this boot. Absent when no
|
|
14546
14657
|
* catalogue lists the id (a newer database).
|
|
14547
14658
|
*/
|
|
14548
|
-
meta: MigrationMetaSchema.optional()
|
|
14659
|
+
meta: MigrationMetaSchema.optional(),
|
|
14660
|
+
/**
|
|
14661
|
+
* Set when this is an applied row of an addon owner whose catalogue the answering
|
|
14662
|
+
* process has not loaded (the owner has not declared yet): the row is applied, the
|
|
14663
|
+
* process just cannot judge it. Never `skipped-newer` — that needs the owner loaded.
|
|
14664
|
+
*/
|
|
14665
|
+
ownerNotLoaded: boolean().optional()
|
|
14549
14666
|
});
|
|
14550
14667
|
/** A catalogued migration that is not applied, with where it stands. */
|
|
14551
14668
|
var MigrationPendingEntrySchema = object({
|
|
@@ -49085,6 +49202,9 @@ var RunningProposalEvidenceSchema = object({
|
|
|
49085
49202
|
runsFound: number().int().nonnegative(),
|
|
49086
49203
|
pausesFound: number().int().nonnegative(),
|
|
49087
49204
|
longestPauseMs: number().nonnegative(),
|
|
49205
|
+
/** Episodes shorter than ~90 s (an anti-crease pulse, a display waking): never a run, never a pause. */
|
|
49206
|
+
pulsesFound: number().int().nonnegative(),
|
|
49207
|
+
longestPulseMs: number().nonnegative(),
|
|
49088
49208
|
idleFloorW: number(),
|
|
49089
49209
|
noiseCeilingW: number(),
|
|
49090
49210
|
plateauW: number(),
|
|
@@ -54006,11 +54126,7 @@ var CreateIntegrationInputSchema = object({
|
|
|
54006
54126
|
info: record(string(), unknown()).optional(),
|
|
54007
54127
|
/** `stableId` of the discovery candidate the form was seeded from (D984). */
|
|
54008
54128
|
originStableId: string().optional(),
|
|
54009
|
-
settings: record(string(), unknown()).optional()
|
|
54010
|
-
/** Keys of `settings` the form's schema declares secret (by type) — kept in
|
|
54011
|
-
* the keychain, not the table (D787). */
|
|
54012
|
-
secretKeys: array(string()).optional(),
|
|
54013
|
-
skipRestart: boolean().optional()
|
|
54129
|
+
settings: record(string(), unknown()).optional()
|
|
54014
54130
|
});
|
|
54015
54131
|
var UpdateIntegrationInputSchema = object({
|
|
54016
54132
|
id: string(),
|
|
@@ -54031,16 +54147,6 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
|
|
|
54031
54147
|
}), method(object({ id: string() }), DeleteIntegrationResultSchema, {
|
|
54032
54148
|
kind: "mutation",
|
|
54033
54149
|
auth: "admin"
|
|
54034
|
-
}), method(object({ id: string() }), record(string(), unknown()), { auth: "admin" }), method(object({
|
|
54035
|
-
id: string(),
|
|
54036
|
-
settings: record(string(), unknown()),
|
|
54037
|
-
/** Keys the form's schema declares secret (by type) — keychain-stored (D787). */
|
|
54038
|
-
secretKeys: array(string()).optional(),
|
|
54039
|
-
/** The integration's own addon applies the change in-process and asks the hub not to respawn it. */
|
|
54040
|
-
skipRestart: boolean().optional()
|
|
54041
|
-
}), object({ success: boolean() }), {
|
|
54042
|
-
kind: "mutation",
|
|
54043
|
-
auth: "admin"
|
|
54044
54150
|
}), method(_void(), array(AvailableIntegrationTypeSchema), { auth: "admin" }), method(object({
|
|
54045
54151
|
addonId: string(),
|
|
54046
54152
|
settings: record(string(), unknown())
|
|
@@ -56765,6 +56871,27 @@ method(object({}), object({ entries: array(MigrationLedgerEntrySchema) }), { aut
|
|
|
56765
56871
|
}), {
|
|
56766
56872
|
kind: "mutation",
|
|
56767
56873
|
auth: "admin"
|
|
56874
|
+
}), method(object({ integrationId: string().min(1) }), record(string(), unknown()), { auth: "admin" }), method(object({ integrationId: string().min(1) }), object({
|
|
56875
|
+
rows: number().int().nonnegative(),
|
|
56876
|
+
secrets: number().int().nonnegative()
|
|
56877
|
+
}), {
|
|
56878
|
+
kind: "mutation",
|
|
56879
|
+
auth: "admin"
|
|
56880
|
+
}), method(object({
|
|
56881
|
+
integrationId: string().min(1),
|
|
56882
|
+
patch: record(string(), unknown())
|
|
56883
|
+
}), object({ written: boolean() }), {
|
|
56884
|
+
kind: "mutation",
|
|
56885
|
+
auth: "admin"
|
|
56886
|
+
}), method(object({
|
|
56887
|
+
integrationId: string().min(1),
|
|
56888
|
+
keys: array(string().min(1))
|
|
56889
|
+
}), object({
|
|
56890
|
+
present: boolean(),
|
|
56891
|
+
removed: record(string(), unknown())
|
|
56892
|
+
}), {
|
|
56893
|
+
kind: "mutation",
|
|
56894
|
+
auth: "admin"
|
|
56768
56895
|
});
|
|
56769
56896
|
method(object({
|
|
56770
56897
|
sourceUrl: string(),
|
|
@@ -75945,11 +76072,15 @@ discriminatedUnion("kind", [object({
|
|
|
75945
76072
|
* 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
|
|
75946
76073
|
* near F. A device that is not near one level most of the time has no floor.
|
|
75947
76074
|
* 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
|
|
75948
|
-
* 3.
|
|
75949
|
-
*
|
|
76075
|
+
* 3. an episode shorter than `PULSE_MAX_MS` is a PULSE (an anti-crease tumble, a
|
|
76076
|
+
* display waking): it is neither a run nor a pause. Among the remaining
|
|
76077
|
+
* episodes, gaps over `PAUSE_MAX_MS` always separate runs; the rest split in
|
|
76078
|
+
* two by the largest log-scale jump (>= 3x): the short ones are pauses INSIDE
|
|
76079
|
+
* a run (a soak), the long ones separate runs. A stretch under `MIN_RUN_MS`
|
|
76080
|
+
* is no run.
|
|
75950
76081
|
* 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
|
|
75951
|
-
* grid a person would type; stop dwell covers the longest pause
|
|
75952
|
-
* covers the longest standby blip above T.
|
|
76082
|
+
* grid a person would type; stop dwell covers the longest pause and the
|
|
76083
|
+
* kind's floor; start dwell covers the longest pulse and standby blip above T.
|
|
75953
76084
|
* 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
|
|
75954
76085
|
* run must hold exactly one true interval and nothing may flap outside.
|
|
75955
76086
|
*/
|
|
@@ -75960,6 +76091,10 @@ var MINUTE_MS$1 = 60 * SECOND_MS;
|
|
|
75960
76091
|
30 * SECOND_MS;
|
|
75961
76092
|
60 * SECOND_MS;
|
|
75962
76093
|
20 * MINUTE_MS$1;
|
|
76094
|
+
90 * SECOND_MS;
|
|
76095
|
+
30 * MINUTE_MS$1;
|
|
76096
|
+
10 * MINUTE_MS$1;
|
|
76097
|
+
DeviceType.Dryer, 3 * MINUTE_MS$1, DeviceType.Dishwasher, 3 * MINUTE_MS$1, DeviceType.Washer, 10 * MINUTE_MS$1;
|
|
75963
76098
|
10 * SECOND_MS;
|
|
75964
76099
|
10 * SECOND_MS;
|
|
75965
76100
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
@@ -79715,13 +79850,6 @@ Object.freeze({
|
|
|
79715
79850
|
access: "view",
|
|
79716
79851
|
role: "admin"
|
|
79717
79852
|
},
|
|
79718
|
-
"integrations.getSettings": {
|
|
79719
|
-
capName: "integrations",
|
|
79720
|
-
capScope: "system",
|
|
79721
|
-
addonId: null,
|
|
79722
|
-
access: "view",
|
|
79723
|
-
role: "admin"
|
|
79724
|
-
},
|
|
79725
79853
|
"integrations.list": {
|
|
79726
79854
|
capName: "integrations",
|
|
79727
79855
|
capScope: "system",
|
|
@@ -79729,13 +79857,6 @@ Object.freeze({
|
|
|
79729
79857
|
access: "view",
|
|
79730
79858
|
role: "admin"
|
|
79731
79859
|
},
|
|
79732
|
-
"integrations.setSettings": {
|
|
79733
|
-
capName: "integrations",
|
|
79734
|
-
capScope: "system",
|
|
79735
|
-
addonId: null,
|
|
79736
|
-
access: "create",
|
|
79737
|
-
role: "admin"
|
|
79738
|
-
},
|
|
79739
79860
|
"integrations.testConnection": {
|
|
79740
79861
|
capName: "integrations",
|
|
79741
79862
|
capScope: "system",
|
|
@@ -80730,6 +80851,13 @@ Object.freeze({
|
|
|
80730
80851
|
access: "view",
|
|
80731
80852
|
role: "admin"
|
|
80732
80853
|
},
|
|
80854
|
+
"migrations.clearLegacyIntegrationRows": {
|
|
80855
|
+
capName: "migrations",
|
|
80856
|
+
capScope: "system",
|
|
80857
|
+
addonId: null,
|
|
80858
|
+
access: "delete",
|
|
80859
|
+
role: "admin"
|
|
80860
|
+
},
|
|
80733
80861
|
"migrations.declareOwner": {
|
|
80734
80862
|
capName: "migrations",
|
|
80735
80863
|
capScope: "system",
|
|
@@ -80737,6 +80865,13 @@ Object.freeze({
|
|
|
80737
80865
|
access: "create",
|
|
80738
80866
|
role: "admin"
|
|
80739
80867
|
},
|
|
80868
|
+
"migrations.deleteLegacyIntegrationRowKeys": {
|
|
80869
|
+
capName: "migrations",
|
|
80870
|
+
capScope: "system",
|
|
80871
|
+
addonId: null,
|
|
80872
|
+
access: "delete",
|
|
80873
|
+
role: "admin"
|
|
80874
|
+
},
|
|
80740
80875
|
"migrations.dryRun": {
|
|
80741
80876
|
capName: "migrations",
|
|
80742
80877
|
capScope: "system",
|
|
@@ -80772,6 +80907,20 @@ Object.freeze({
|
|
|
80772
80907
|
access: "create",
|
|
80773
80908
|
role: "admin"
|
|
80774
80909
|
},
|
|
80910
|
+
"migrations.patchLegacyIntegrationRows": {
|
|
80911
|
+
capName: "migrations",
|
|
80912
|
+
capScope: "system",
|
|
80913
|
+
addonId: null,
|
|
80914
|
+
access: "create",
|
|
80915
|
+
role: "admin"
|
|
80916
|
+
},
|
|
80917
|
+
"migrations.readLegacyIntegrationRows": {
|
|
80918
|
+
capName: "migrations",
|
|
80919
|
+
capScope: "system",
|
|
80920
|
+
addonId: null,
|
|
80921
|
+
access: "view",
|
|
80922
|
+
role: "admin"
|
|
80923
|
+
},
|
|
80775
80924
|
"migrations.restorePreMigration": {
|
|
80776
80925
|
capName: "migrations",
|
|
80777
80926
|
capScope: "system",
|
|
@@ -123467,7 +123616,7 @@ var MqttAclStore = class MqttAclStore {
|
|
|
123467
123616
|
* The addon has NO standalone admin page. All configuration — external
|
|
123468
123617
|
* broker entries, the embedded `aedes` broker, embedded credentials,
|
|
123469
123618
|
* and the topic ACL — is exposed through the standard
|
|
123470
|
-
* `
|
|
123619
|
+
* `clusterSettingsSchema()` and rendered automatically inside the
|
|
123471
123620
|
* Integrations → Brokers tab's docked Settings panel, like every other
|
|
123472
123621
|
* integration-type addon.
|
|
123473
123622
|
*
|
|
@@ -124538,11 +124687,15 @@ var MqttBrokerAddon = class extends BaseAddon {
|
|
|
124538
124687
|
}
|
|
124539
124688
|
};
|
|
124540
124689
|
}
|
|
124690
|
+
scopedSettingsCapabilities() {
|
|
124691
|
+
return ["mqtt-broker", "broker"];
|
|
124692
|
+
}
|
|
124541
124693
|
/**
|
|
124542
124694
|
* The embedded broker, its credentials and the ACL. The external brokers are records, listed
|
|
124543
124695
|
* on the Brokers page and edited as integration instances (`brokerForm`).
|
|
124544
124696
|
*/
|
|
124545
|
-
|
|
124697
|
+
async clusterSettingsSchema(cap) {
|
|
124698
|
+
if (cap !== "mqtt-broker" && cap !== "broker") return null;
|
|
124546
124699
|
return this.schema({ sections: [
|
|
124547
124700
|
{
|
|
124548
124701
|
id: "mqtt-broker-embedded",
|
|
@@ -6021,7 +6021,7 @@ var ZodIssueCode = {
|
|
|
6021
6021
|
var ZodFirstPartyTypeKind;
|
|
6022
6022
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
6023
6023
|
//#endregion
|
|
6024
|
-
//#region ../types/dist/sleep-
|
|
6024
|
+
//#region ../types/dist/sleep-DEZaLbiu.mjs
|
|
6025
6025
|
/**
|
|
6026
6026
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6027
6027
|
* window to float samples (D455).
|
|
@@ -6621,7 +6621,7 @@ var NOT_RUN = {
|
|
|
6621
6621
|
* throws: an unreachable or refusing engine is logged and reported `declared: false`,
|
|
6622
6622
|
* because the hub (and this addon's boot) must not hang on a migration.
|
|
6623
6623
|
*/
|
|
6624
|
-
async function runAddonMigrations(host, migrations, logger) {
|
|
6624
|
+
async function runAddonMigrations(host, migrations, logger, options = {}) {
|
|
6625
6625
|
const first = migrations[0];
|
|
6626
6626
|
if (first === void 0) return NOT_RUN;
|
|
6627
6627
|
const owner = first.meta.owner;
|
|
@@ -6650,7 +6650,9 @@ async function runAddonMigrations(host, migrations, logger) {
|
|
|
6650
6650
|
else if (status === "blocked") blocked.push(id);
|
|
6651
6651
|
else skipped.push(id);
|
|
6652
6652
|
};
|
|
6653
|
+
const selected = options.only === void 0 ? null : new Set(options.only);
|
|
6653
6654
|
for (const step of declaration.steps) {
|
|
6655
|
+
if (selected !== null && !selected.has(step.id)) continue;
|
|
6654
6656
|
const bound = byId.get(step.id);
|
|
6655
6657
|
if (bound === void 0 || step.action === "skip") {
|
|
6656
6658
|
skipped.push(step.id);
|
|
@@ -6828,6 +6830,12 @@ function projectStore(store, perNodeKeys, nodeId) {
|
|
|
6828
6830
|
}
|
|
6829
6831
|
return out;
|
|
6830
6832
|
}
|
|
6833
|
+
/** Every scope, in the order the guard and the docs list them. */
|
|
6834
|
+
var SCOPED_SETTINGS_SCOPES = [
|
|
6835
|
+
"cluster",
|
|
6836
|
+
"device-defaults",
|
|
6837
|
+
"node"
|
|
6838
|
+
];
|
|
6831
6839
|
/**
|
|
6832
6840
|
* The address of one keychain value: `secret://<owner>/<scope>/<fieldPath>`.
|
|
6833
6841
|
*
|
|
@@ -7719,6 +7727,13 @@ var BaseAddon = class {
|
|
|
7719
7727
|
*/
|
|
7720
7728
|
secretStatePaths = [];
|
|
7721
7729
|
_addonSecretTree = null;
|
|
7730
|
+
/**
|
|
7731
|
+
* D986 M4: the scoped schemas this addon declared, resolved once per capability
|
|
7732
|
+
* (`loadScopedSchemas`) so the sync readers (`perNodeKeys`, the secret tree, the restart check)
|
|
7733
|
+
* see them. Empty until loaded: the readers then fall back to {@link globalSettingsSchema}.
|
|
7734
|
+
*/
|
|
7735
|
+
_scopedByCap = /* @__PURE__ */ new Map();
|
|
7736
|
+
_nodeKeysByCap = /* @__PURE__ */ new Map();
|
|
7722
7737
|
_deviceSecretTree = null;
|
|
7723
7738
|
/** Refs the last resolved config pointed at — a change to one re-resolves. */
|
|
7724
7739
|
_configSecretRefs = /* @__PURE__ */ new Set();
|
|
@@ -7788,6 +7803,7 @@ var BaseAddon = class {
|
|
|
7788
7803
|
this._ctx = context;
|
|
7789
7804
|
this._secretSettings = null;
|
|
7790
7805
|
}
|
|
7806
|
+
await this.loadScopedSchemas();
|
|
7791
7807
|
await this.resolveConfig();
|
|
7792
7808
|
if (secrets !== void 0) this._secretChangeUnsub = secrets.onChange((ref) => {
|
|
7793
7809
|
if (this._configSecretRefs.has(ref)) this.scheduleSecretReresolve(SECRET_CHANGE_DEBOUNCE_MS);
|
|
@@ -7797,6 +7813,7 @@ var BaseAddon = class {
|
|
|
7797
7813
|
const normalized = normalizeAddonInitResult(result);
|
|
7798
7814
|
const providers = normalized && "providers" in normalized && normalized.providers ? normalized.providers : [];
|
|
7799
7815
|
this._registeredCapNames = providers.map((p) => p.capability.name);
|
|
7816
|
+
await this.loadScopedSchemas();
|
|
7800
7817
|
return normalized;
|
|
7801
7818
|
}
|
|
7802
7819
|
/**
|
|
@@ -7810,14 +7827,18 @@ var BaseAddon = class {
|
|
|
7810
7827
|
* nothing; the boot continues. A migration that FAILED (or was blocked by one)
|
|
7811
7828
|
* and declares `onFailure: 'block-owner'` makes this throw, so the addon does not
|
|
7812
7829
|
* serve data whose shape it cannot trust; `tolerate` migrations never do.
|
|
7830
|
+
*
|
|
7831
|
+
* ALWAYS pass the whole catalogue; a phase that must run only some of it passes
|
|
7832
|
+
* `{ only: [ids] }` — never a filtered catalogue (the engine would judge the
|
|
7833
|
+
* omitted applied ids "newer").
|
|
7813
7834
|
*/
|
|
7814
|
-
async runMigrations(migrations) {
|
|
7835
|
+
async runMigrations(migrations, options) {
|
|
7815
7836
|
const api = this.ctx.api.migrations;
|
|
7816
7837
|
const report = await runAddonMigrations({
|
|
7817
7838
|
declareOwner: (input) => api.declareOwner.mutate(input),
|
|
7818
7839
|
startMigration: (input) => api.startMigration.mutate(input),
|
|
7819
7840
|
finishMigration: (input) => api.finishMigration.mutate(input)
|
|
7820
|
-
}, migrations, this.ctx.logger);
|
|
7841
|
+
}, migrations, this.ctx.logger, options);
|
|
7821
7842
|
if (report.blockOwner.length > 0) throw new AddonMigrationsBlockedError(report.blockOwner);
|
|
7822
7843
|
return report;
|
|
7823
7844
|
}
|
|
@@ -7881,6 +7902,16 @@ var BaseAddon = class {
|
|
|
7881
7902
|
schema(schema) {
|
|
7882
7903
|
return schema;
|
|
7883
7904
|
}
|
|
7905
|
+
/**
|
|
7906
|
+
* The capability names whose scoped settings schemas ({@link clusterSettingsSchema},
|
|
7907
|
+
* {@link nodeSettingsSchema}, {@link deviceDefaultsSchema}) this addon declares. Read BEFORE
|
|
7908
|
+
* `onInitialize`, when the providers it registers are not known yet: the first config resolve
|
|
7909
|
+
* must already know which keys are per node. Names the providers register at init are added
|
|
7910
|
+
* once known.
|
|
7911
|
+
*/
|
|
7912
|
+
scopedSettingsCapabilities() {
|
|
7913
|
+
return [];
|
|
7914
|
+
}
|
|
7884
7915
|
/** Override to provide global-level settings UI schema. */
|
|
7885
7916
|
globalSettingsSchema(_cap) {
|
|
7886
7917
|
return null;
|
|
@@ -7924,7 +7955,8 @@ var BaseAddon = class {
|
|
|
7924
7955
|
return [];
|
|
7925
7956
|
}
|
|
7926
7957
|
async getGlobalSettings(overlay, cap, nodeId) {
|
|
7927
|
-
|
|
7958
|
+
await this.loadScopedSchemas(cap);
|
|
7959
|
+
const schema = this.globalSettingsSchema(cap) ?? this.scopedFormSchema(cap);
|
|
7928
7960
|
if (!schema) return { sections: [] };
|
|
7929
7961
|
const projected = await this.readRawProjectedStore(nodeId, cap);
|
|
7930
7962
|
return hydrateSchema(schema, overlay ? await this.overlayKeepingMarkers(projected, overlay) : projected, { inlineSecretsAsViews: true });
|
|
@@ -7959,10 +7991,9 @@ var BaseAddon = class {
|
|
|
7959
7991
|
*
|
|
7960
7992
|
* Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
|
|
7961
7993
|
* needs its connection fields, the default integration the addon's own sections. It is the
|
|
7962
|
-
* SHAPE of the form only — the values live
|
|
7963
|
-
* unchanged (`integrations.setSettings` for an account integration).
|
|
7994
|
+
* SHAPE of the form only — the values live on the instance record.
|
|
7964
7995
|
*/
|
|
7965
|
-
async
|
|
7996
|
+
async integrationFormSchema(_instance) {
|
|
7966
7997
|
return null;
|
|
7967
7998
|
}
|
|
7968
7999
|
/**
|
|
@@ -8008,7 +8039,7 @@ var BaseAddon = class {
|
|
|
8008
8039
|
* per-instance schema when it declares one, else its global schema (what they always showed).
|
|
8009
8040
|
*/
|
|
8010
8041
|
async getIntegrationFormSchema(instance, nodeId) {
|
|
8011
|
-
const scoped = await this.
|
|
8042
|
+
const scoped = await this.integrationFormSchema(instance);
|
|
8012
8043
|
if (scoped === null) return this.getGlobalSettings(void 0, void 0, nodeId);
|
|
8013
8044
|
return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
|
|
8014
8045
|
}
|
|
@@ -8056,6 +8087,7 @@ var BaseAddon = class {
|
|
|
8056
8087
|
* resolved blob back is a no-op for every unchanged secret.
|
|
8057
8088
|
*/
|
|
8058
8089
|
async resolveGlobalStore(nodeId, cap) {
|
|
8090
|
+
await this.loadScopedSchemas(cap);
|
|
8059
8091
|
const raw = await this._ctx?.settings?.readAddonStore() ?? {};
|
|
8060
8092
|
return this.projectForNode(raw, nodeId, cap);
|
|
8061
8093
|
}
|
|
@@ -8066,6 +8098,7 @@ var BaseAddon = class {
|
|
|
8066
8098
|
}
|
|
8067
8099
|
/** The PROJECTED store with its markers — the form hydrate only (D798). */
|
|
8068
8100
|
async readRawProjectedStore(nodeId, cap) {
|
|
8101
|
+
await this.loadScopedSchemas(cap);
|
|
8069
8102
|
const raw = await this.rawSettings()?.readAddonStore() ?? {};
|
|
8070
8103
|
return this.projectForNode(raw, nodeId, cap);
|
|
8071
8104
|
}
|
|
@@ -8168,6 +8201,7 @@ var BaseAddon = class {
|
|
|
8168
8201
|
await this.applyGlobalPatch(patch, nodeId);
|
|
8169
8202
|
}
|
|
8170
8203
|
async applyGlobalPatch(barePatch, nodeId) {
|
|
8204
|
+
await this.loadScopedSchemas();
|
|
8171
8205
|
const keys = this.perNodeKeys();
|
|
8172
8206
|
const localNode = normalizeNodeId(this._ctx?.kernel?.localNodeId);
|
|
8173
8207
|
const target = normalizeNodeId(nodeId ?? this._ctx?.kernel?.localNodeId);
|
|
@@ -8181,7 +8215,8 @@ var BaseAddon = class {
|
|
|
8181
8215
|
await this.resolveConfig();
|
|
8182
8216
|
await this.onConfigChanged();
|
|
8183
8217
|
this.emitLifecycle(EventCategory.AddonUpdated, { level: "global" });
|
|
8184
|
-
|
|
8218
|
+
const legacy = this.globalSettingsSchema();
|
|
8219
|
+
this.maybeAutoRestart(Object.keys(barePatch), [...legacy === null ? [] : [legacy], ...this.loadedScopedSchemas().map((entry) => entry.schema)]);
|
|
8185
8220
|
}
|
|
8186
8221
|
/**
|
|
8187
8222
|
* The set of field keys the global settings schema declares `perNode: true`
|
|
@@ -8189,14 +8224,67 @@ var BaseAddon = class {
|
|
|
8189
8224
|
* declarations). Empty set ⇒ every per-node code path is bypassed and the
|
|
8190
8225
|
* settings API behaves exactly like the legacy node-agnostic one.
|
|
8191
8226
|
*/
|
|
8192
|
-
|
|
8227
|
+
/**
|
|
8228
|
+
* Load the scoped schemas of every capability this addon declares (the override and the
|
|
8229
|
+
* providers registered at init, plus `extraCap`) that is not loaded yet, then drop what was
|
|
8230
|
+
* derived from the previous set. Idempotent.
|
|
8231
|
+
*/
|
|
8232
|
+
async loadScopedSchemas(extraCap) {
|
|
8233
|
+
const caps = new Set([
|
|
8234
|
+
...this.scopedSettingsCapabilities(),
|
|
8235
|
+
...this._registeredCapNames,
|
|
8236
|
+
...extraCap === void 0 ? [] : [extraCap]
|
|
8237
|
+
]);
|
|
8238
|
+
let added = false;
|
|
8239
|
+
for (const cap of caps) {
|
|
8240
|
+
if (this._scopedByCap.has(cap)) continue;
|
|
8241
|
+
const loaded = [];
|
|
8242
|
+
for (const scope of SCOPED_SETTINGS_SCOPES) {
|
|
8243
|
+
const schema = await this.getScopedSettingsSchema(scope, cap);
|
|
8244
|
+
if (schema !== null) loaded.push({
|
|
8245
|
+
scope,
|
|
8246
|
+
schema
|
|
8247
|
+
});
|
|
8248
|
+
}
|
|
8249
|
+
this._scopedByCap.set(cap, loaded);
|
|
8250
|
+
added = true;
|
|
8251
|
+
}
|
|
8252
|
+
if (!added) return;
|
|
8253
|
+
this._nodeKeysByCap = /* @__PURE__ */ new Map();
|
|
8254
|
+
this._addonSecretTree = null;
|
|
8255
|
+
}
|
|
8256
|
+
/**
|
|
8257
|
+
* The form the settings API serves while an addon declares no {@link globalSettingsSchema}: the
|
|
8258
|
+
* sections of its scoped schemas, so dropping the old hook does not blank the form.
|
|
8259
|
+
*/
|
|
8260
|
+
scopedFormSchema(cap) {
|
|
8261
|
+
const byId = /* @__PURE__ */ new Map();
|
|
8262
|
+
for (const entry of this.loadedScopedSchemas(cap)) for (const section of entry.schema.sections) if (!byId.has(section.id)) byId.set(section.id, section);
|
|
8263
|
+
return byId.size === 0 ? null : { sections: [...byId.values()] };
|
|
8264
|
+
}
|
|
8265
|
+
/** Every loaded scoped schema of `cap`, or of every loaded capability. */
|
|
8266
|
+
loadedScopedSchemas(cap) {
|
|
8267
|
+
if (cap !== void 0) return this._scopedByCap.get(cap) ?? [];
|
|
8268
|
+
return [...this._scopedByCap.values()].flat();
|
|
8269
|
+
}
|
|
8270
|
+
/**
|
|
8271
|
+
* The field keys that are stored per node: every field of a {@link nodeSettingsSchema}, plus
|
|
8272
|
+
* the fields the legacy {@link globalSettingsSchema} still marks `perNode: true`. Derived once
|
|
8273
|
+
* per `cap` argument and memoized (schemas are static declarations). Empty set ⇒ every
|
|
8274
|
+
* per-node code path is bypassed and the settings API behaves like the node-agnostic one.
|
|
8275
|
+
* Call {@link loadScopedSchemas} first (the async seams do).
|
|
8276
|
+
*/
|
|
8193
8277
|
perNodeKeys(cap) {
|
|
8194
8278
|
const cacheKey = cap ?? "";
|
|
8195
|
-
const cached = this.
|
|
8279
|
+
const cached = this._nodeKeysByCap.get(cacheKey);
|
|
8196
8280
|
if (cached) return cached;
|
|
8197
|
-
const
|
|
8198
|
-
const keys = new Set(
|
|
8199
|
-
this.
|
|
8281
|
+
const legacy = this.globalSettingsSchema(cap);
|
|
8282
|
+
const keys = new Set(legacy ? legacy.sections.flatMap((section) => collectPerNodeFieldKeys(section.fields)) : []);
|
|
8283
|
+
for (const { scope, schema } of this.loadedScopedSchemas(cap)) {
|
|
8284
|
+
if (scope !== "node") continue;
|
|
8285
|
+
for (const section of schema.sections) for (const key of collectValueFieldKeys(section.fields)) keys.add(key);
|
|
8286
|
+
}
|
|
8287
|
+
this._nodeKeysByCap.set(cacheKey, keys);
|
|
8200
8288
|
return keys;
|
|
8201
8289
|
}
|
|
8202
8290
|
/**
|
|
@@ -8206,10 +8294,9 @@ var BaseAddon = class {
|
|
|
8206
8294
|
* time to return its response before the addon is torn down and
|
|
8207
8295
|
* re-initialised by `AddonRegistryService.restartAddon`.
|
|
8208
8296
|
*/
|
|
8209
|
-
maybeAutoRestart(patchKeys,
|
|
8210
|
-
if (!schema) return;
|
|
8297
|
+
maybeAutoRestart(patchKeys, schemas) {
|
|
8211
8298
|
const restartKeys = /* @__PURE__ */ new Set();
|
|
8212
|
-
for (const section of schema.sections) for (const field of section.fields) {
|
|
8299
|
+
for (const schema of schemas) for (const section of schema.sections) for (const field of section.fields) {
|
|
8213
8300
|
if (field.type === "separator" || field.type === "info") continue;
|
|
8214
8301
|
if (field.requiresRestart) restartKeys.add(field.key);
|
|
8215
8302
|
}
|
|
@@ -8405,12 +8492,14 @@ var BaseAddon = class {
|
|
|
8405
8492
|
* here, in the addon's own process, so the hub keeps no copy of it.
|
|
8406
8493
|
*/
|
|
8407
8494
|
async getDeclaredSettingsKeys() {
|
|
8495
|
+
await this.loadScopedSchemas();
|
|
8408
8496
|
return { keys: [...this.declaredKeySet()].toSorted() };
|
|
8409
8497
|
}
|
|
8410
8498
|
declaredKeySet() {
|
|
8411
8499
|
const keys = new Set(Object.keys(this.defaults));
|
|
8412
8500
|
const schema = this.globalSettingsSchema();
|
|
8413
8501
|
if (schema) for (const section of schema.sections) for (const key of collectFieldKeys(section.fields)) keys.add(key);
|
|
8502
|
+
for (const { schema: scoped } of this.loadedScopedSchemas()) for (const section of scoped.sections) for (const key of collectFieldKeys(section.fields)) keys.add(key);
|
|
8414
8503
|
for (const key of this._declaredStateKeys) keys.add(key);
|
|
8415
8504
|
for (const path of this.secretStatePaths) {
|
|
8416
8505
|
const root = path.split(/[.[]/, 1)[0];
|
|
@@ -8506,7 +8595,11 @@ var BaseAddon = class {
|
|
|
8506
8595
|
}
|
|
8507
8596
|
/** The addon store's secret tree: schema fields by TYPE, plus `secretStatePaths`. */
|
|
8508
8597
|
addonSecretTree() {
|
|
8509
|
-
this._addonSecretTree
|
|
8598
|
+
if (this._addonSecretTree === null) {
|
|
8599
|
+
const tree = new Map(secretTreeFromSchema(this.globalSettingsSchema()));
|
|
8600
|
+
for (const { schema } of this.loadedScopedSchemas()) for (const [key, node] of secretTreeFromSchema(schema)) tree.set(key, node);
|
|
8601
|
+
this._addonSecretTree = mergeSecretStatePaths(tree, this.secretStatePaths);
|
|
8602
|
+
}
|
|
8510
8603
|
return this._addonSecretTree;
|
|
8511
8604
|
}
|
|
8512
8605
|
deviceSecretTree() {
|
|
@@ -8756,6 +8849,23 @@ function dropPerNodeFields(fields) {
|
|
|
8756
8849
|
}
|
|
8757
8850
|
return kept;
|
|
8758
8851
|
}
|
|
8852
|
+
/** The keys of the value-holding fields, recursing into layout containers. */
|
|
8853
|
+
function collectValueFieldKeys(fields) {
|
|
8854
|
+
const collected = [];
|
|
8855
|
+
for (const field of fields) {
|
|
8856
|
+
if (field.type === "group") {
|
|
8857
|
+
collected.push(...collectValueFieldKeys(field.fields));
|
|
8858
|
+
continue;
|
|
8859
|
+
}
|
|
8860
|
+
if (field.type === "sub-tabs") {
|
|
8861
|
+
for (const tab of field.tabs) collected.push(...collectValueFieldKeys(tab.fields));
|
|
8862
|
+
continue;
|
|
8863
|
+
}
|
|
8864
|
+
if (field.type === "separator" || field.type === "info") continue;
|
|
8865
|
+
if ("key" in field && typeof field.key === "string") collected.push(field.key);
|
|
8866
|
+
}
|
|
8867
|
+
return collected;
|
|
8868
|
+
}
|
|
8759
8869
|
function collectFieldKeys(fields) {
|
|
8760
8870
|
const collected = [];
|
|
8761
8871
|
for (const field of fields) {
|
|
@@ -9282,6 +9392,7 @@ function defineEntryKind(name, spec) {
|
|
|
9282
9392
|
class: "config",
|
|
9283
9393
|
writeTrigger: spec.writeTrigger ?? "an operator adds or edits an entry in the entries UI",
|
|
9284
9394
|
retention: { none: "an entry goes only when the operator deletes it" },
|
|
9395
|
+
...spec.maxDataBytes === void 0 ? {} : { maxDataBytes: spec.maxDataBytes },
|
|
9285
9396
|
...spec.database === void 0 ? {} : { database: spec.database },
|
|
9286
9397
|
...spec.indexes === void 0 ? {} : { indexes: spec.indexes },
|
|
9287
9398
|
...spec.secretArrayKeys === void 0 ? {} : { secretArrayKeys: spec.secretArrayKeys },
|
|
@@ -11947,7 +12058,7 @@ object({
|
|
|
11947
12058
|
params: record(string(), union([string(), number()])).optional()
|
|
11948
12059
|
});
|
|
11949
12060
|
//#endregion
|
|
11950
|
-
//#region ../types/dist/composition-
|
|
12061
|
+
//#region ../types/dist/composition-pOHbTzRB.mjs
|
|
11951
12062
|
/**
|
|
11952
12063
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11953
12064
|
*
|
|
@@ -14538,7 +14649,13 @@ var MigrationLedgerEntrySchema = object({
|
|
|
14538
14649
|
* joined by the engine from the catalogues it knows this boot. Absent when no
|
|
14539
14650
|
* catalogue lists the id (a newer database).
|
|
14540
14651
|
*/
|
|
14541
|
-
meta: MigrationMetaSchema.optional()
|
|
14652
|
+
meta: MigrationMetaSchema.optional(),
|
|
14653
|
+
/**
|
|
14654
|
+
* Set when this is an applied row of an addon owner whose catalogue the answering
|
|
14655
|
+
* process has not loaded (the owner has not declared yet): the row is applied, the
|
|
14656
|
+
* process just cannot judge it. Never `skipped-newer` — that needs the owner loaded.
|
|
14657
|
+
*/
|
|
14658
|
+
ownerNotLoaded: boolean().optional()
|
|
14542
14659
|
});
|
|
14543
14660
|
/** A catalogued migration that is not applied, with where it stands. */
|
|
14544
14661
|
var MigrationPendingEntrySchema = object({
|
|
@@ -49078,6 +49195,9 @@ var RunningProposalEvidenceSchema = object({
|
|
|
49078
49195
|
runsFound: number().int().nonnegative(),
|
|
49079
49196
|
pausesFound: number().int().nonnegative(),
|
|
49080
49197
|
longestPauseMs: number().nonnegative(),
|
|
49198
|
+
/** Episodes shorter than ~90 s (an anti-crease pulse, a display waking): never a run, never a pause. */
|
|
49199
|
+
pulsesFound: number().int().nonnegative(),
|
|
49200
|
+
longestPulseMs: number().nonnegative(),
|
|
49081
49201
|
idleFloorW: number(),
|
|
49082
49202
|
noiseCeilingW: number(),
|
|
49083
49203
|
plateauW: number(),
|
|
@@ -53999,11 +54119,7 @@ var CreateIntegrationInputSchema = object({
|
|
|
53999
54119
|
info: record(string(), unknown()).optional(),
|
|
54000
54120
|
/** `stableId` of the discovery candidate the form was seeded from (D984). */
|
|
54001
54121
|
originStableId: string().optional(),
|
|
54002
|
-
settings: record(string(), unknown()).optional()
|
|
54003
|
-
/** Keys of `settings` the form's schema declares secret (by type) — kept in
|
|
54004
|
-
* the keychain, not the table (D787). */
|
|
54005
|
-
secretKeys: array(string()).optional(),
|
|
54006
|
-
skipRestart: boolean().optional()
|
|
54122
|
+
settings: record(string(), unknown()).optional()
|
|
54007
54123
|
});
|
|
54008
54124
|
var UpdateIntegrationInputSchema = object({
|
|
54009
54125
|
id: string(),
|
|
@@ -54024,16 +54140,6 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
|
|
|
54024
54140
|
}), method(object({ id: string() }), DeleteIntegrationResultSchema, {
|
|
54025
54141
|
kind: "mutation",
|
|
54026
54142
|
auth: "admin"
|
|
54027
|
-
}), method(object({ id: string() }), record(string(), unknown()), { auth: "admin" }), method(object({
|
|
54028
|
-
id: string(),
|
|
54029
|
-
settings: record(string(), unknown()),
|
|
54030
|
-
/** Keys the form's schema declares secret (by type) — keychain-stored (D787). */
|
|
54031
|
-
secretKeys: array(string()).optional(),
|
|
54032
|
-
/** The integration's own addon applies the change in-process and asks the hub not to respawn it. */
|
|
54033
|
-
skipRestart: boolean().optional()
|
|
54034
|
-
}), object({ success: boolean() }), {
|
|
54035
|
-
kind: "mutation",
|
|
54036
|
-
auth: "admin"
|
|
54037
54143
|
}), method(_void(), array(AvailableIntegrationTypeSchema), { auth: "admin" }), method(object({
|
|
54038
54144
|
addonId: string(),
|
|
54039
54145
|
settings: record(string(), unknown())
|
|
@@ -56758,6 +56864,27 @@ method(object({}), object({ entries: array(MigrationLedgerEntrySchema) }), { aut
|
|
|
56758
56864
|
}), {
|
|
56759
56865
|
kind: "mutation",
|
|
56760
56866
|
auth: "admin"
|
|
56867
|
+
}), method(object({ integrationId: string().min(1) }), record(string(), unknown()), { auth: "admin" }), method(object({ integrationId: string().min(1) }), object({
|
|
56868
|
+
rows: number().int().nonnegative(),
|
|
56869
|
+
secrets: number().int().nonnegative()
|
|
56870
|
+
}), {
|
|
56871
|
+
kind: "mutation",
|
|
56872
|
+
auth: "admin"
|
|
56873
|
+
}), method(object({
|
|
56874
|
+
integrationId: string().min(1),
|
|
56875
|
+
patch: record(string(), unknown())
|
|
56876
|
+
}), object({ written: boolean() }), {
|
|
56877
|
+
kind: "mutation",
|
|
56878
|
+
auth: "admin"
|
|
56879
|
+
}), method(object({
|
|
56880
|
+
integrationId: string().min(1),
|
|
56881
|
+
keys: array(string().min(1))
|
|
56882
|
+
}), object({
|
|
56883
|
+
present: boolean(),
|
|
56884
|
+
removed: record(string(), unknown())
|
|
56885
|
+
}), {
|
|
56886
|
+
kind: "mutation",
|
|
56887
|
+
auth: "admin"
|
|
56761
56888
|
});
|
|
56762
56889
|
method(object({
|
|
56763
56890
|
sourceUrl: string(),
|
|
@@ -75938,11 +76065,15 @@ discriminatedUnion("kind", [object({
|
|
|
75938
76065
|
* 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
|
|
75939
76066
|
* near F. A device that is not near one level most of the time has no floor.
|
|
75940
76067
|
* 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
|
|
75941
|
-
* 3.
|
|
75942
|
-
*
|
|
76068
|
+
* 3. an episode shorter than `PULSE_MAX_MS` is a PULSE (an anti-crease tumble, a
|
|
76069
|
+
* display waking): it is neither a run nor a pause. Among the remaining
|
|
76070
|
+
* episodes, gaps over `PAUSE_MAX_MS` always separate runs; the rest split in
|
|
76071
|
+
* two by the largest log-scale jump (>= 3x): the short ones are pauses INSIDE
|
|
76072
|
+
* a run (a soak), the long ones separate runs. A stretch under `MIN_RUN_MS`
|
|
76073
|
+
* is no run.
|
|
75943
76074
|
* 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
|
|
75944
|
-
* grid a person would type; stop dwell covers the longest pause
|
|
75945
|
-
* covers the longest standby blip above T.
|
|
76075
|
+
* grid a person would type; stop dwell covers the longest pause and the
|
|
76076
|
+
* kind's floor; start dwell covers the longest pulse and standby blip above T.
|
|
75946
76077
|
* 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
|
|
75947
76078
|
* run must hold exactly one true interval and nothing may flap outside.
|
|
75948
76079
|
*/
|
|
@@ -75953,6 +76084,10 @@ var MINUTE_MS$1 = 60 * SECOND_MS;
|
|
|
75953
76084
|
30 * SECOND_MS;
|
|
75954
76085
|
60 * SECOND_MS;
|
|
75955
76086
|
20 * MINUTE_MS$1;
|
|
76087
|
+
90 * SECOND_MS;
|
|
76088
|
+
30 * MINUTE_MS$1;
|
|
76089
|
+
10 * MINUTE_MS$1;
|
|
76090
|
+
DeviceType.Dryer, 3 * MINUTE_MS$1, DeviceType.Dishwasher, 3 * MINUTE_MS$1, DeviceType.Washer, 10 * MINUTE_MS$1;
|
|
75956
76091
|
10 * SECOND_MS;
|
|
75957
76092
|
10 * SECOND_MS;
|
|
75958
76093
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
@@ -79708,13 +79843,6 @@ Object.freeze({
|
|
|
79708
79843
|
access: "view",
|
|
79709
79844
|
role: "admin"
|
|
79710
79845
|
},
|
|
79711
|
-
"integrations.getSettings": {
|
|
79712
|
-
capName: "integrations",
|
|
79713
|
-
capScope: "system",
|
|
79714
|
-
addonId: null,
|
|
79715
|
-
access: "view",
|
|
79716
|
-
role: "admin"
|
|
79717
|
-
},
|
|
79718
79846
|
"integrations.list": {
|
|
79719
79847
|
capName: "integrations",
|
|
79720
79848
|
capScope: "system",
|
|
@@ -79722,13 +79850,6 @@ Object.freeze({
|
|
|
79722
79850
|
access: "view",
|
|
79723
79851
|
role: "admin"
|
|
79724
79852
|
},
|
|
79725
|
-
"integrations.setSettings": {
|
|
79726
|
-
capName: "integrations",
|
|
79727
|
-
capScope: "system",
|
|
79728
|
-
addonId: null,
|
|
79729
|
-
access: "create",
|
|
79730
|
-
role: "admin"
|
|
79731
|
-
},
|
|
79732
79853
|
"integrations.testConnection": {
|
|
79733
79854
|
capName: "integrations",
|
|
79734
79855
|
capScope: "system",
|
|
@@ -80723,6 +80844,13 @@ Object.freeze({
|
|
|
80723
80844
|
access: "view",
|
|
80724
80845
|
role: "admin"
|
|
80725
80846
|
},
|
|
80847
|
+
"migrations.clearLegacyIntegrationRows": {
|
|
80848
|
+
capName: "migrations",
|
|
80849
|
+
capScope: "system",
|
|
80850
|
+
addonId: null,
|
|
80851
|
+
access: "delete",
|
|
80852
|
+
role: "admin"
|
|
80853
|
+
},
|
|
80726
80854
|
"migrations.declareOwner": {
|
|
80727
80855
|
capName: "migrations",
|
|
80728
80856
|
capScope: "system",
|
|
@@ -80730,6 +80858,13 @@ Object.freeze({
|
|
|
80730
80858
|
access: "create",
|
|
80731
80859
|
role: "admin"
|
|
80732
80860
|
},
|
|
80861
|
+
"migrations.deleteLegacyIntegrationRowKeys": {
|
|
80862
|
+
capName: "migrations",
|
|
80863
|
+
capScope: "system",
|
|
80864
|
+
addonId: null,
|
|
80865
|
+
access: "delete",
|
|
80866
|
+
role: "admin"
|
|
80867
|
+
},
|
|
80733
80868
|
"migrations.dryRun": {
|
|
80734
80869
|
capName: "migrations",
|
|
80735
80870
|
capScope: "system",
|
|
@@ -80765,6 +80900,20 @@ Object.freeze({
|
|
|
80765
80900
|
access: "create",
|
|
80766
80901
|
role: "admin"
|
|
80767
80902
|
},
|
|
80903
|
+
"migrations.patchLegacyIntegrationRows": {
|
|
80904
|
+
capName: "migrations",
|
|
80905
|
+
capScope: "system",
|
|
80906
|
+
addonId: null,
|
|
80907
|
+
access: "create",
|
|
80908
|
+
role: "admin"
|
|
80909
|
+
},
|
|
80910
|
+
"migrations.readLegacyIntegrationRows": {
|
|
80911
|
+
capName: "migrations",
|
|
80912
|
+
capScope: "system",
|
|
80913
|
+
addonId: null,
|
|
80914
|
+
access: "view",
|
|
80915
|
+
role: "admin"
|
|
80916
|
+
},
|
|
80768
80917
|
"migrations.restorePreMigration": {
|
|
80769
80918
|
capName: "migrations",
|
|
80770
80919
|
capScope: "system",
|
|
@@ -123460,7 +123609,7 @@ var MqttAclStore = class MqttAclStore {
|
|
|
123460
123609
|
* The addon has NO standalone admin page. All configuration — external
|
|
123461
123610
|
* broker entries, the embedded `aedes` broker, embedded credentials,
|
|
123462
123611
|
* and the topic ACL — is exposed through the standard
|
|
123463
|
-
* `
|
|
123612
|
+
* `clusterSettingsSchema()` and rendered automatically inside the
|
|
123464
123613
|
* Integrations → Brokers tab's docked Settings panel, like every other
|
|
123465
123614
|
* integration-type addon.
|
|
123466
123615
|
*
|
|
@@ -124531,11 +124680,15 @@ var MqttBrokerAddon = class extends BaseAddon {
|
|
|
124531
124680
|
}
|
|
124532
124681
|
};
|
|
124533
124682
|
}
|
|
124683
|
+
scopedSettingsCapabilities() {
|
|
124684
|
+
return ["mqtt-broker", "broker"];
|
|
124685
|
+
}
|
|
124534
124686
|
/**
|
|
124535
124687
|
* The embedded broker, its credentials and the ACL. The external brokers are records, listed
|
|
124536
124688
|
* on the Brokers page and edited as integration instances (`brokerForm`).
|
|
124537
124689
|
*/
|
|
124538
|
-
|
|
124690
|
+
async clusterSettingsSchema(cap) {
|
|
124691
|
+
if (cap !== "mqtt-broker" && cap !== "broker") return null;
|
|
124539
124692
|
return this.schema({ sections: [
|
|
124540
124693
|
{
|
|
124541
124694
|
id: "mqtt-broker-embedded",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-mqtt-broker",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.151",
|
|
4
4
|
"description": "MQTT broker registry addon for CamStack — manages external broker entries + an optional embedded aedes broker. Consumers spin up their own `mqtt.js` clients via the `mqtt-broker` cap.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"aedes"
|
|
61
61
|
],
|
|
62
62
|
"requires": {
|
|
63
|
-
"server": ">=1.2.
|
|
63
|
+
"server": ">=1.2.775"
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
66
|
"files": [
|