@camstack/system 1.2.147 → 1.2.149
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon-runner.js +2 -1
- package/dist/addon-runner.mjs +2 -1
- package/dist/auth/auth-manager.d.ts +17 -1
- package/dist/auth/token-expiry.d.ts +39 -0
- package/dist/auth/user-manager.d.ts +2 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
- package/dist/builtins/device-manager/device-manager.addon.js +2 -2
- package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
- package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
- package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/auth-config-reader.d.ts +20 -0
- package/dist/builtins/local-auth/local-auth.addon.js +211 -17
- package/dist/builtins/local-auth/local-auth.addon.mjs +211 -17
- package/dist/builtins/local-network/local-network.addon.js +1 -1
- package/dist/builtins/local-network/local-network.addon.mjs +1 -1
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/retired-settings-keys.d.ts +16 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/dist/builtins/system-config/system-config.addon.js +12 -11
- package/dist/builtins/system-config/system-config.addon.mjs +12 -11
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{dist-DrBc-7Y3.mjs → dist-CZWAU40-.mjs} +129 -1
- package/dist/{dist-Dl6MFXPr.js → dist-DdEXjTDo.js} +129 -1
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- package/dist/kernel/transport/child-cap-protocol.d.ts +2 -2
- package/dist/{manifest-python-deps-FYZBHc3v.js → manifest-python-deps-CivtrAha.js} +1 -1
- package/dist/{manifest-python-deps-DhT0oFOZ.mjs → manifest-python-deps-HFh_iE0E.mjs} +1 -1
- package/dist/{retired-settings-keys-6w_JOqBg.js → retired-settings-keys-BXaTgLyZ.js} +90 -14
- package/dist/{retired-settings-keys-CF5r4YKq.mjs → retired-settings-keys-BynPjBHV.mjs} +90 -14
- package/package.json +6 -4
|
@@ -1247,6 +1247,40 @@ var BaseAddon = class {
|
|
|
1247
1247
|
deviceSettingsSchema() {
|
|
1248
1248
|
return null;
|
|
1249
1249
|
}
|
|
1250
|
+
/**
|
|
1251
|
+
* INTEGRATION-LEVEL SETTINGS — declare which of this addon's global sections
|
|
1252
|
+
* ARE the configuration of its integration.
|
|
1253
|
+
*
|
|
1254
|
+
* Return the `ConfigSection.id`s, from {@link globalSettingsSchema}, that an
|
|
1255
|
+
* operator should find on the addon's integration page (System →
|
|
1256
|
+
* Integrations → <name>) rather than only in the cluster-wide list of every
|
|
1257
|
+
* addon. Empty (the default) means the addon has no integration-level
|
|
1258
|
+
* settings and no such surface is offered — this is opt-in, because whether
|
|
1259
|
+
* an addon's configuration IS its integration's configuration depends on the
|
|
1260
|
+
* nature of the integration.
|
|
1261
|
+
*
|
|
1262
|
+
* WHAT THIS IS NOT. It is not a scope. The selected sections keep living in
|
|
1263
|
+
* the ONE global schema, in the ONE addon store, written by the ONE
|
|
1264
|
+
* `updateGlobalSettings` path. There is deliberately no
|
|
1265
|
+
* `updateIntegrationSettings`: a second write path is how a surface acquires
|
|
1266
|
+
* a second store key, and this repo has shipped that twice (`btmPath@hub`,
|
|
1267
|
+
* D266). Selecting sections cannot introduce a key that selecting cannot.
|
|
1268
|
+
*
|
|
1269
|
+
* WHY IT IS A LIST OF SECTION IDS AND NOT A MARKER ON THE SECTION.
|
|
1270
|
+
* `ConfigFieldBase` used to carry `scope?: 'device' | 'global'` and it was
|
|
1271
|
+
* removed with the reason recorded at
|
|
1272
|
+
* `packages/types/src/interfaces/config-ui.ts:249` — *"a field's scope is
|
|
1273
|
+
* determined by WHICH schema it lives in, not by a field-level marker."* A
|
|
1274
|
+
* marker sprinkled across sections also has to borrow a field that already
|
|
1275
|
+
* means something else; borrowing `section.tab` put the literal word
|
|
1276
|
+
* "integration" into an operator-facing tab bar, because `tab` means "how to
|
|
1277
|
+
* GROUP this visually" and cannot also mean "where this lives" (D269
|
|
1278
|
+
* supersedes D268). One declaration, in one place, next to the schema whose
|
|
1279
|
+
* ids it names.
|
|
1280
|
+
*/
|
|
1281
|
+
integrationSettingSections() {
|
|
1282
|
+
return [];
|
|
1283
|
+
}
|
|
1250
1284
|
async getGlobalSettings(overlay, cap, nodeId) {
|
|
1251
1285
|
const schema = this.globalSettingsSchema(cap);
|
|
1252
1286
|
if (!schema) return { sections: [] };
|
|
@@ -1257,6 +1291,55 @@ var BaseAddon = class {
|
|
|
1257
1291
|
} : projected);
|
|
1258
1292
|
}
|
|
1259
1293
|
/**
|
|
1294
|
+
* The integration-level view of this addon's settings: exactly the sections
|
|
1295
|
+
* named by {@link integrationSettingSections}, hydrated from the SAME store
|
|
1296
|
+
* `getGlobalSettings` reads, and narrowed to cluster-scoped fields.
|
|
1297
|
+
*
|
|
1298
|
+
* Returns `null` when the addon declared nothing — an addon that opts out has
|
|
1299
|
+
* no integration settings surface at all, rather than an empty one that reads
|
|
1300
|
+
* as a failed load.
|
|
1301
|
+
*
|
|
1302
|
+
* Three properties hold BY CONSTRUCTION, which is why they are here in core
|
|
1303
|
+
* and not in whichever UI happens to render this:
|
|
1304
|
+
*
|
|
1305
|
+
* 1. **One key.** The payload is a SUBSET of the global schema, so a field
|
|
1306
|
+
* shown here is the same field, with the same bare key, that the addon's
|
|
1307
|
+
* own page shows. There is no integration-specific writer — callers save
|
|
1308
|
+
* through `updateGlobalSettings` — so a second store key is unreachable,
|
|
1309
|
+
* not merely discouraged.
|
|
1310
|
+
* 2. **No node scope.** `perNode: true` fields are DROPPED. Their store key
|
|
1311
|
+
* is `<key>@<nodeId>` and an integration is not a node; whichever node
|
|
1312
|
+
* such a field silently picked would be a wrong answer for the operator
|
|
1313
|
+
* who opened the page (D266).
|
|
1314
|
+
* 3. **No silent typo.** A declared id that names no section throws. The
|
|
1315
|
+
* alternative — skip it — turns a rename into a surface that quietly
|
|
1316
|
+
* empties, which looks exactly like an addon with nothing to configure.
|
|
1317
|
+
*/
|
|
1318
|
+
async getIntegrationSettings(nodeId) {
|
|
1319
|
+
const declared = this.integrationSettingSections();
|
|
1320
|
+
if (declared.length === 0) return null;
|
|
1321
|
+
const schema = this.globalSettingsSchema();
|
|
1322
|
+
if (!schema) throw new Error(`${this.constructor.name}: integrationSettingSections() names [${declared.join(", ")}] but globalSettingsSchema() returns null.`);
|
|
1323
|
+
const byId = new Map(schema.sections.map((section) => [section.id, section]));
|
|
1324
|
+
const sections = [];
|
|
1325
|
+
for (const id of declared) {
|
|
1326
|
+
const section = byId.get(id);
|
|
1327
|
+
if (!section) throw new Error(`${this.constructor.name}: integrationSettingSections() names unknown section "${id}". Known sections: [${[...byId.keys()].join(", ")}].`);
|
|
1328
|
+
const fields = dropPerNodeFields(section.fields);
|
|
1329
|
+
if (fields.length === 0) continue;
|
|
1330
|
+
sections.push({
|
|
1331
|
+
...section,
|
|
1332
|
+
fields
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
if (sections.length === 0) return null;
|
|
1336
|
+
const projected = await this.resolveGlobalStore(nodeId);
|
|
1337
|
+
return hydrateSchema({
|
|
1338
|
+
...schema,
|
|
1339
|
+
sections
|
|
1340
|
+
}, projected);
|
|
1341
|
+
}
|
|
1342
|
+
/**
|
|
1260
1343
|
* The raw addon store PROJECTED onto the target node's bare per-node keys:
|
|
1261
1344
|
* every `perNode: true` field carries THAT node's scoped value on its bare
|
|
1262
1345
|
* key (absent scoped key ⇒ key absent, so the schema `default` wins — no
|
|
@@ -1560,6 +1643,41 @@ var BaseAddon = class {
|
|
|
1560
1643
|
* `hydrateSchema` does. Valueless structural fields (separator/info/…)
|
|
1561
1644
|
* don't declare `perNode` and are excluded by the `in` narrowing.
|
|
1562
1645
|
*/
|
|
1646
|
+
/**
|
|
1647
|
+
* The same fields with every `perNode: true` one removed, recursing into layout
|
|
1648
|
+
* containers exactly as {@link collectPerNodeFieldKeys} does. A container left
|
|
1649
|
+
* with no child is dropped rather than rendered empty.
|
|
1650
|
+
*
|
|
1651
|
+
* Used by `getIntegrationSettings`: an integration is not a node, so a field
|
|
1652
|
+
* whose store key is `<key>@<nodeId>` has no node to belong to there.
|
|
1653
|
+
*/
|
|
1654
|
+
function dropPerNodeFields(fields) {
|
|
1655
|
+
const kept = [];
|
|
1656
|
+
for (const field of fields) {
|
|
1657
|
+
if (field.type === "group") {
|
|
1658
|
+
const inner = dropPerNodeFields(field.fields);
|
|
1659
|
+
if (inner.length > 0) kept.push({
|
|
1660
|
+
...field,
|
|
1661
|
+
fields: inner
|
|
1662
|
+
});
|
|
1663
|
+
continue;
|
|
1664
|
+
}
|
|
1665
|
+
if (field.type === "sub-tabs") {
|
|
1666
|
+
const tabs = field.tabs.map((tab) => ({
|
|
1667
|
+
...tab,
|
|
1668
|
+
fields: dropPerNodeFields(tab.fields)
|
|
1669
|
+
})).filter((tab) => tab.fields.length > 0);
|
|
1670
|
+
if (tabs.length > 0) kept.push({
|
|
1671
|
+
...field,
|
|
1672
|
+
tabs
|
|
1673
|
+
});
|
|
1674
|
+
continue;
|
|
1675
|
+
}
|
|
1676
|
+
if ("perNode" in field && field.perNode === true) continue;
|
|
1677
|
+
kept.push(field);
|
|
1678
|
+
}
|
|
1679
|
+
return kept;
|
|
1680
|
+
}
|
|
1563
1681
|
function collectPerNodeFieldKeys(fields) {
|
|
1564
1682
|
const collected = [];
|
|
1565
1683
|
for (const field of fields) {
|
|
@@ -5781,6 +5899,10 @@ var addonSettingsCapability = {
|
|
|
5781
5899
|
kind: "mutation",
|
|
5782
5900
|
auth: "admin"
|
|
5783
5901
|
}),
|
|
5902
|
+
getIntegrationSettings: method(z.object({
|
|
5903
|
+
addonId: z.string(),
|
|
5904
|
+
nodeId: z.string().optional()
|
|
5905
|
+
}), SettingsSchemaWithValuesSchema.nullable()),
|
|
5784
5906
|
getDeviceSettings: method(z.object({
|
|
5785
5907
|
addonId: z.string(),
|
|
5786
5908
|
deviceId: z.number(),
|
|
@@ -31956,7 +32078,7 @@ var RUNTIME_DEFAULTS = {
|
|
|
31956
32078
|
"ffmpeg.binaryPath": "ffmpeg",
|
|
31957
32079
|
"ffmpeg.hwAccel": "auto",
|
|
31958
32080
|
"ffmpeg.threadCount": 0,
|
|
31959
|
-
"auth.tokenExpiry": "
|
|
32081
|
+
"auth.tokenExpiry": "30d"
|
|
31960
32082
|
};
|
|
31961
32083
|
/**
|
|
31962
32084
|
* Accessory device helpers — shared across drivers.
|
|
@@ -32788,6 +32910,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
32788
32910
|
addonId: null,
|
|
32789
32911
|
access: "view"
|
|
32790
32912
|
},
|
|
32913
|
+
"addonSettings.getIntegrationSettings": {
|
|
32914
|
+
capName: "addon-settings",
|
|
32915
|
+
capScope: "system",
|
|
32916
|
+
addonId: null,
|
|
32917
|
+
access: "view"
|
|
32918
|
+
},
|
|
32791
32919
|
"addonSettings.updateDeviceSettings": {
|
|
32792
32920
|
capName: "addon-settings",
|
|
32793
32921
|
capScope: "system",
|
|
@@ -1247,6 +1247,40 @@ var BaseAddon = class {
|
|
|
1247
1247
|
deviceSettingsSchema() {
|
|
1248
1248
|
return null;
|
|
1249
1249
|
}
|
|
1250
|
+
/**
|
|
1251
|
+
* INTEGRATION-LEVEL SETTINGS — declare which of this addon's global sections
|
|
1252
|
+
* ARE the configuration of its integration.
|
|
1253
|
+
*
|
|
1254
|
+
* Return the `ConfigSection.id`s, from {@link globalSettingsSchema}, that an
|
|
1255
|
+
* operator should find on the addon's integration page (System →
|
|
1256
|
+
* Integrations → <name>) rather than only in the cluster-wide list of every
|
|
1257
|
+
* addon. Empty (the default) means the addon has no integration-level
|
|
1258
|
+
* settings and no such surface is offered — this is opt-in, because whether
|
|
1259
|
+
* an addon's configuration IS its integration's configuration depends on the
|
|
1260
|
+
* nature of the integration.
|
|
1261
|
+
*
|
|
1262
|
+
* WHAT THIS IS NOT. It is not a scope. The selected sections keep living in
|
|
1263
|
+
* the ONE global schema, in the ONE addon store, written by the ONE
|
|
1264
|
+
* `updateGlobalSettings` path. There is deliberately no
|
|
1265
|
+
* `updateIntegrationSettings`: a second write path is how a surface acquires
|
|
1266
|
+
* a second store key, and this repo has shipped that twice (`btmPath@hub`,
|
|
1267
|
+
* D266). Selecting sections cannot introduce a key that selecting cannot.
|
|
1268
|
+
*
|
|
1269
|
+
* WHY IT IS A LIST OF SECTION IDS AND NOT A MARKER ON THE SECTION.
|
|
1270
|
+
* `ConfigFieldBase` used to carry `scope?: 'device' | 'global'` and it was
|
|
1271
|
+
* removed with the reason recorded at
|
|
1272
|
+
* `packages/types/src/interfaces/config-ui.ts:249` — *"a field's scope is
|
|
1273
|
+
* determined by WHICH schema it lives in, not by a field-level marker."* A
|
|
1274
|
+
* marker sprinkled across sections also has to borrow a field that already
|
|
1275
|
+
* means something else; borrowing `section.tab` put the literal word
|
|
1276
|
+
* "integration" into an operator-facing tab bar, because `tab` means "how to
|
|
1277
|
+
* GROUP this visually" and cannot also mean "where this lives" (D269
|
|
1278
|
+
* supersedes D268). One declaration, in one place, next to the schema whose
|
|
1279
|
+
* ids it names.
|
|
1280
|
+
*/
|
|
1281
|
+
integrationSettingSections() {
|
|
1282
|
+
return [];
|
|
1283
|
+
}
|
|
1250
1284
|
async getGlobalSettings(overlay, cap, nodeId) {
|
|
1251
1285
|
const schema = this.globalSettingsSchema(cap);
|
|
1252
1286
|
if (!schema) return { sections: [] };
|
|
@@ -1257,6 +1291,55 @@ var BaseAddon = class {
|
|
|
1257
1291
|
} : projected);
|
|
1258
1292
|
}
|
|
1259
1293
|
/**
|
|
1294
|
+
* The integration-level view of this addon's settings: exactly the sections
|
|
1295
|
+
* named by {@link integrationSettingSections}, hydrated from the SAME store
|
|
1296
|
+
* `getGlobalSettings` reads, and narrowed to cluster-scoped fields.
|
|
1297
|
+
*
|
|
1298
|
+
* Returns `null` when the addon declared nothing — an addon that opts out has
|
|
1299
|
+
* no integration settings surface at all, rather than an empty one that reads
|
|
1300
|
+
* as a failed load.
|
|
1301
|
+
*
|
|
1302
|
+
* Three properties hold BY CONSTRUCTION, which is why they are here in core
|
|
1303
|
+
* and not in whichever UI happens to render this:
|
|
1304
|
+
*
|
|
1305
|
+
* 1. **One key.** The payload is a SUBSET of the global schema, so a field
|
|
1306
|
+
* shown here is the same field, with the same bare key, that the addon's
|
|
1307
|
+
* own page shows. There is no integration-specific writer — callers save
|
|
1308
|
+
* through `updateGlobalSettings` — so a second store key is unreachable,
|
|
1309
|
+
* not merely discouraged.
|
|
1310
|
+
* 2. **No node scope.** `perNode: true` fields are DROPPED. Their store key
|
|
1311
|
+
* is `<key>@<nodeId>` and an integration is not a node; whichever node
|
|
1312
|
+
* such a field silently picked would be a wrong answer for the operator
|
|
1313
|
+
* who opened the page (D266).
|
|
1314
|
+
* 3. **No silent typo.** A declared id that names no section throws. The
|
|
1315
|
+
* alternative — skip it — turns a rename into a surface that quietly
|
|
1316
|
+
* empties, which looks exactly like an addon with nothing to configure.
|
|
1317
|
+
*/
|
|
1318
|
+
async getIntegrationSettings(nodeId) {
|
|
1319
|
+
const declared = this.integrationSettingSections();
|
|
1320
|
+
if (declared.length === 0) return null;
|
|
1321
|
+
const schema = this.globalSettingsSchema();
|
|
1322
|
+
if (!schema) throw new Error(`${this.constructor.name}: integrationSettingSections() names [${declared.join(", ")}] but globalSettingsSchema() returns null.`);
|
|
1323
|
+
const byId = new Map(schema.sections.map((section) => [section.id, section]));
|
|
1324
|
+
const sections = [];
|
|
1325
|
+
for (const id of declared) {
|
|
1326
|
+
const section = byId.get(id);
|
|
1327
|
+
if (!section) throw new Error(`${this.constructor.name}: integrationSettingSections() names unknown section "${id}". Known sections: [${[...byId.keys()].join(", ")}].`);
|
|
1328
|
+
const fields = dropPerNodeFields(section.fields);
|
|
1329
|
+
if (fields.length === 0) continue;
|
|
1330
|
+
sections.push({
|
|
1331
|
+
...section,
|
|
1332
|
+
fields
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
if (sections.length === 0) return null;
|
|
1336
|
+
const projected = await this.resolveGlobalStore(nodeId);
|
|
1337
|
+
return hydrateSchema({
|
|
1338
|
+
...schema,
|
|
1339
|
+
sections
|
|
1340
|
+
}, projected);
|
|
1341
|
+
}
|
|
1342
|
+
/**
|
|
1260
1343
|
* The raw addon store PROJECTED onto the target node's bare per-node keys:
|
|
1261
1344
|
* every `perNode: true` field carries THAT node's scoped value on its bare
|
|
1262
1345
|
* key (absent scoped key ⇒ key absent, so the schema `default` wins — no
|
|
@@ -1560,6 +1643,41 @@ var BaseAddon = class {
|
|
|
1560
1643
|
* `hydrateSchema` does. Valueless structural fields (separator/info/…)
|
|
1561
1644
|
* don't declare `perNode` and are excluded by the `in` narrowing.
|
|
1562
1645
|
*/
|
|
1646
|
+
/**
|
|
1647
|
+
* The same fields with every `perNode: true` one removed, recursing into layout
|
|
1648
|
+
* containers exactly as {@link collectPerNodeFieldKeys} does. A container left
|
|
1649
|
+
* with no child is dropped rather than rendered empty.
|
|
1650
|
+
*
|
|
1651
|
+
* Used by `getIntegrationSettings`: an integration is not a node, so a field
|
|
1652
|
+
* whose store key is `<key>@<nodeId>` has no node to belong to there.
|
|
1653
|
+
*/
|
|
1654
|
+
function dropPerNodeFields(fields) {
|
|
1655
|
+
const kept = [];
|
|
1656
|
+
for (const field of fields) {
|
|
1657
|
+
if (field.type === "group") {
|
|
1658
|
+
const inner = dropPerNodeFields(field.fields);
|
|
1659
|
+
if (inner.length > 0) kept.push({
|
|
1660
|
+
...field,
|
|
1661
|
+
fields: inner
|
|
1662
|
+
});
|
|
1663
|
+
continue;
|
|
1664
|
+
}
|
|
1665
|
+
if (field.type === "sub-tabs") {
|
|
1666
|
+
const tabs = field.tabs.map((tab) => ({
|
|
1667
|
+
...tab,
|
|
1668
|
+
fields: dropPerNodeFields(tab.fields)
|
|
1669
|
+
})).filter((tab) => tab.fields.length > 0);
|
|
1670
|
+
if (tabs.length > 0) kept.push({
|
|
1671
|
+
...field,
|
|
1672
|
+
tabs
|
|
1673
|
+
});
|
|
1674
|
+
continue;
|
|
1675
|
+
}
|
|
1676
|
+
if ("perNode" in field && field.perNode === true) continue;
|
|
1677
|
+
kept.push(field);
|
|
1678
|
+
}
|
|
1679
|
+
return kept;
|
|
1680
|
+
}
|
|
1563
1681
|
function collectPerNodeFieldKeys(fields) {
|
|
1564
1682
|
const collected = [];
|
|
1565
1683
|
for (const field of fields) {
|
|
@@ -5781,6 +5899,10 @@ var addonSettingsCapability = {
|
|
|
5781
5899
|
kind: "mutation",
|
|
5782
5900
|
auth: "admin"
|
|
5783
5901
|
}),
|
|
5902
|
+
getIntegrationSettings: method(zod.z.object({
|
|
5903
|
+
addonId: zod.z.string(),
|
|
5904
|
+
nodeId: zod.z.string().optional()
|
|
5905
|
+
}), SettingsSchemaWithValuesSchema.nullable()),
|
|
5784
5906
|
getDeviceSettings: method(zod.z.object({
|
|
5785
5907
|
addonId: zod.z.string(),
|
|
5786
5908
|
deviceId: zod.z.number(),
|
|
@@ -31956,7 +32078,7 @@ var RUNTIME_DEFAULTS = {
|
|
|
31956
32078
|
"ffmpeg.binaryPath": "ffmpeg",
|
|
31957
32079
|
"ffmpeg.hwAccel": "auto",
|
|
31958
32080
|
"ffmpeg.threadCount": 0,
|
|
31959
|
-
"auth.tokenExpiry": "
|
|
32081
|
+
"auth.tokenExpiry": "30d"
|
|
31960
32082
|
};
|
|
31961
32083
|
/**
|
|
31962
32084
|
* Accessory device helpers — shared across drivers.
|
|
@@ -32788,6 +32910,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
32788
32910
|
addonId: null,
|
|
32789
32911
|
access: "view"
|
|
32790
32912
|
},
|
|
32913
|
+
"addonSettings.getIntegrationSettings": {
|
|
32914
|
+
capName: "addon-settings",
|
|
32915
|
+
capScope: "system",
|
|
32916
|
+
addonId: null,
|
|
32917
|
+
access: "view"
|
|
32918
|
+
},
|
|
32791
32919
|
"addonSettings.updateDeviceSettings": {
|
|
32792
32920
|
capName: "addon-settings",
|
|
32793
32921
|
capScope: "system",
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
3
|
-
const require_dist = require("./dist-
|
|
3
|
+
const require_dist = require("./dist-DdEXjTDo.js");
|
|
4
4
|
const require_builtins_alerts_alerts_addon = require("./builtins/alerts/alerts.addon.js");
|
|
5
5
|
require("./builtins/alerts/index.js");
|
|
6
6
|
const require_formatter = require("./formatter-DqAKDlvN.js");
|
|
@@ -26,7 +26,7 @@ require("./builtins/system-config/index.js");
|
|
|
26
26
|
const require_builtins_winston_logging_index = require("./builtins/winston-logging/index.js");
|
|
27
27
|
const require_file_data_plane = require("./file-data-plane-DO8KbxCe.js");
|
|
28
28
|
const require_tls$1 = require("./tls-u8QCJCFE.js");
|
|
29
|
-
const require_manifest_python_deps = require("./manifest-python-deps-
|
|
29
|
+
const require_manifest_python_deps = require("./manifest-python-deps-CivtrAha.js");
|
|
30
30
|
const require_resource_monitor = require("./resource-monitor-CdnzxBLP.js");
|
|
31
31
|
const require_custom_action_registry = require("./custom-action-registry-jY0NOZK8.js");
|
|
32
32
|
let zod = require("zod");
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM$1, r as __exportAll, t as __commonJSMin$1 } from "./chunk-CNf5ZN-e.mjs";
|
|
2
|
-
import { $ as isVoidInput, $t as scopeKey, At as DATAPLANE_SECRET_HEADER$1, Bt as asNumber, C as addonSettingsCapability, G as extractNestedAddonId, Gt as expandCapMethods, Ht as createEvent, It as ReadinessRegistry, J as isArrayOutputSchema, Lt as ReadinessTimeoutError, Mt as DEVICE_STATUS_METHOD, Ot as errMsg$1, Qt as resolveCapMount, Ut as emitDownForOwnedCaps, Vt as asString$1, X as isObjectInput, Xt as parseJsonUnknown$1, Y as isCollectionArrayMethod, Yt as parseJsonObject, Zt as readinessKey, _t as scopesAllowDeviceCap, at as looseSchema, ct as objectInputDeclaresAddonId, dt as procedureAuthKey, et as kebabToCamel, f as LOG_LEVEL_RANK, gt as scopesAllowAddon, it as logLevelAtMost, jt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, m as RUNTIME_DEFAULTS, mt as resolveMethodAuth, p as METHOD_ACCESS_MAP, t as ALL_CAPABILITY_DEFINITIONS, tn as EventCategory$1, tt as lifecycleJobSchema, zt as asJsonObject$1 } from "./dist-
|
|
2
|
+
import { $ as isVoidInput, $t as scopeKey, At as DATAPLANE_SECRET_HEADER$1, Bt as asNumber, C as addonSettingsCapability, G as extractNestedAddonId, Gt as expandCapMethods, Ht as createEvent, It as ReadinessRegistry, J as isArrayOutputSchema, Lt as ReadinessTimeoutError, Mt as DEVICE_STATUS_METHOD, Ot as errMsg$1, Qt as resolveCapMount, Ut as emitDownForOwnedCaps, Vt as asString$1, X as isObjectInput, Xt as parseJsonUnknown$1, Y as isCollectionArrayMethod, Yt as parseJsonObject, Zt as readinessKey, _t as scopesAllowDeviceCap, at as looseSchema, ct as objectInputDeclaresAddonId, dt as procedureAuthKey, et as kebabToCamel, f as LOG_LEVEL_RANK, gt as scopesAllowAddon, it as logLevelAtMost, jt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, m as RUNTIME_DEFAULTS, mt as resolveMethodAuth, p as METHOD_ACCESS_MAP, t as ALL_CAPABILITY_DEFINITIONS, tn as EventCategory$1, tt as lifecycleJobSchema, zt as asJsonObject$1 } from "./dist-CZWAU40-.mjs";
|
|
3
3
|
import { AlertCenterAddon } from "./builtins/alerts/alerts.addon.mjs";
|
|
4
4
|
import "./builtins/alerts/index.mjs";
|
|
5
5
|
import { t as formatLogLine } from "./formatter-B7qW8bPJ.mjs";
|
|
@@ -25,7 +25,7 @@ import "./builtins/system-config/index.mjs";
|
|
|
25
25
|
import { WinstonDestination, WinstonLoggingAddon } from "./builtins/winston-logging/index.mjs";
|
|
26
26
|
import { a as parseTokenizedUrl, c as collectModelFiles, d as downloadModel, f as ensureModel, h as isModelDownloaded, i as parseRangeHeader, l as deleteModelFromDisk, m as getModelFilePath, n as contentTypeFor, o as resolveFilePath, p as fetchJson, r as createAuthenticatedFileServer, s as ModelDownloadService, t as createFileDataPlaneHandler, u as downloadFile } from "./file-data-plane-BhKdxJgf.mjs";
|
|
27
27
|
import { C as registerLanHttpHandler, S as readLanHttpState, _ as DEFAULT_LAN_HTTP_PORT, a as writeTlsMode, b as bindPendingLanHttp, c as loadTlsCert, d as collectCertIdentity, f as CA_VALIDITY_DAYS, g as evaluateExistingCert, h as SERVER_AUTH_OID, i as writeExtraSans, l as reissueTlsLeaf, m as MAX_LEAF_VALIDITY_DAYS, n as readTlsAccessStatus, o as validateUploadedTls, p as LEAF_RENEWAL_WINDOW_DAYS, r as readTlsMode, s as ensureTlsCert, t as readExtraSans, u as CA_COMMON_NAME, v as allFamiliesListenHost, x as closeLanHttp, y as applyLanHttp } from "./tls-CQhPGSJm.mjs";
|
|
28
|
-
import { $ as buildUdsNativeCapProxy, A as createParentUnownedCallHandler, At as RSS_BUDGET_REANNOUNCE_MIN_MS, B as AGENT_CAP_FWD_SERVICE, Bt as shouldReclaim, C as brokerTransportLink, Ct as createAddonDataPlaneFacility, D as HUB_CAP_FWD_ACTION, Dt as HEAP_WATCH_WARN_RATIO, E as localProviderLink, Et as HEAP_WATCH_INTERVAL_MS, F as createUdsLoggerWithControl, Ft as createV8Reclaimer, G as createLocalTransport, H as CapRouteError, Ht as startRunnerHeapWatch, I as LocalChildClient, It as describeRss, J as SocketChannel, K as UdsLocalTransportClient, L as LocalChildRegistry, Lt as hubMainRssBudget, M as createUdsEventBus, Mt as RUNNER_HEAP_WATCH_INTERVAL_MS, N as udsChildLogToWorkerEntry, Nt as RUNNER_RSS_BUDGET_ENV, O as HUB_CAP_FWD_SERVICE, Ot as HUB_MAIN_RSS_BUDGET_MB, P as createUdsLogger, Pt as buildHeapSample, Q as buildNativeCapProxy, R as UDS_NO_ROUTE_PREFIX, Rt as nextRssBudgetState, S as brokerCallForCap, St as runNpm, T as ipcParentLink, Tt as HEAP_RECLAIM_TRIGGER_MB, U as classifyCapRoute, Ut as strandedMb, V as CapRouteResolver, Vt as startHeapWatch, W as callWithServiceDiscovery, X as FrameDecoder, Y as localEndpointPath, Z as encodeFrame, _ as createKernelHwAccel, _t as CapabilityUnavailableError, a as getWorkerDeviceRegistry, at as createAddonService, b as __resetCapUsageRegistryForTests, bt as resolveAddonClass, c as setHubConnected, ct as capActionName, d as getBrokerEventBus, dt as capServiceName, et as createBrokerDeviceManagerApi, f as getMoleculerEventStats, ft as parseCapAction, g as AddonDepsManager, gt as CapabilityHandle, h as subscribePassthrough, ht as DeviceRegistry, i as createUdsAddonContext, j as createUdsEventBridge, jt as RSS_BUDGET_RELEASE_RATIO, k as createHubCapForwardService, kt as HUB_RSS_BUDGET_ENV, l as EVENT_TOPIC_PREFIX, lt as capActionSuffix, m as setNodeEventInterest, mt as serializeTypedArrays, n as adaptBrokerToCluster, o as getOrInitReadinessRegistry, ot as validateProviderRegistrations, p as registerEventBusService, pt as deserializeTypedArrays, q as UdsLocalTransportServer, r as createAddonContext, rt as mountNativeCapService, s as getOrInitReadinessRegistryForClient, st as NATIVE_PROVIDER_SERVICE_INFIX, t as installManifestPythonDeps, u as clusterEventTopic, ut as capBareAction, v as resolveHwAccel, vt as copyBundledNativeModules, w as buildLinkChain, wt as HEAP_RECLAIM_MIN_INTERVAL_MS, x as getCapUsageRegistry, xt as resolveNpmInvocation, y as CapUsageRegistry, yt as installManifestNativeDeps, z as AGENT_CAP_FWD_ACTION, zt as parseRssBudgetMb } from "./manifest-python-deps-
|
|
28
|
+
import { $ as buildUdsNativeCapProxy, A as createParentUnownedCallHandler, At as RSS_BUDGET_REANNOUNCE_MIN_MS, B as AGENT_CAP_FWD_SERVICE, Bt as shouldReclaim, C as brokerTransportLink, Ct as createAddonDataPlaneFacility, D as HUB_CAP_FWD_ACTION, Dt as HEAP_WATCH_WARN_RATIO, E as localProviderLink, Et as HEAP_WATCH_INTERVAL_MS, F as createUdsLoggerWithControl, Ft as createV8Reclaimer, G as createLocalTransport, H as CapRouteError, Ht as startRunnerHeapWatch, I as LocalChildClient, It as describeRss, J as SocketChannel, K as UdsLocalTransportClient, L as LocalChildRegistry, Lt as hubMainRssBudget, M as createUdsEventBus, Mt as RUNNER_HEAP_WATCH_INTERVAL_MS, N as udsChildLogToWorkerEntry, Nt as RUNNER_RSS_BUDGET_ENV, O as HUB_CAP_FWD_SERVICE, Ot as HUB_MAIN_RSS_BUDGET_MB, P as createUdsLogger, Pt as buildHeapSample, Q as buildNativeCapProxy, R as UDS_NO_ROUTE_PREFIX, Rt as nextRssBudgetState, S as brokerCallForCap, St as runNpm, T as ipcParentLink, Tt as HEAP_RECLAIM_TRIGGER_MB, U as classifyCapRoute, Ut as strandedMb, V as CapRouteResolver, Vt as startHeapWatch, W as callWithServiceDiscovery, X as FrameDecoder, Y as localEndpointPath, Z as encodeFrame, _ as createKernelHwAccel, _t as CapabilityUnavailableError, a as getWorkerDeviceRegistry, at as createAddonService, b as __resetCapUsageRegistryForTests, bt as resolveAddonClass, c as setHubConnected, ct as capActionName, d as getBrokerEventBus, dt as capServiceName, et as createBrokerDeviceManagerApi, f as getMoleculerEventStats, ft as parseCapAction, g as AddonDepsManager, gt as CapabilityHandle, h as subscribePassthrough, ht as DeviceRegistry, i as createUdsAddonContext, j as createUdsEventBridge, jt as RSS_BUDGET_RELEASE_RATIO, k as createHubCapForwardService, kt as HUB_RSS_BUDGET_ENV, l as EVENT_TOPIC_PREFIX, lt as capActionSuffix, m as setNodeEventInterest, mt as serializeTypedArrays, n as adaptBrokerToCluster, o as getOrInitReadinessRegistry, ot as validateProviderRegistrations, p as registerEventBusService, pt as deserializeTypedArrays, q as UdsLocalTransportServer, r as createAddonContext, rt as mountNativeCapService, s as getOrInitReadinessRegistryForClient, st as NATIVE_PROVIDER_SERVICE_INFIX, t as installManifestPythonDeps, u as clusterEventTopic, ut as capBareAction, v as resolveHwAccel, vt as copyBundledNativeModules, w as buildLinkChain, wt as HEAP_RECLAIM_MIN_INTERVAL_MS, x as getCapUsageRegistry, xt as resolveNpmInvocation, y as CapUsageRegistry, yt as installManifestNativeDeps, z as AGENT_CAP_FWD_ACTION, zt as parseRssBudgetMb } from "./manifest-python-deps-HFh_iE0E.mjs";
|
|
29
29
|
import { n as getSinglePidStats, t as getPidStats } from "./resource-monitor-BWmQ5i-o.mjs";
|
|
30
30
|
import { t as CustomActionRegistry } from "./custom-action-registry-F__gp_VX.mjs";
|
|
31
31
|
import { z } from "zod";
|
|
@@ -192,8 +192,8 @@ export interface ReadinessSnapshotResponse {
|
|
|
192
192
|
* addon so it can set up its reverse-proxy. Mirrors `routes`.
|
|
193
193
|
*/
|
|
194
194
|
export type AddonCallTarget = 'routes' | 'custom' | 'settings' | 'data-planes';
|
|
195
|
-
/** The
|
|
196
|
-
export type AddonSettingsMethod = 'getGlobalSettings' | 'updateGlobalSettings' | 'getDeviceSettings' | 'updateDeviceSettings';
|
|
195
|
+
/** The addon-settings methods reachable over the addon-call plane. */
|
|
196
|
+
export type AddonSettingsMethod = 'getGlobalSettings' | 'updateGlobalSettings' | 'getIntegrationSettings' | 'getDeviceSettings' | 'updateDeviceSettings';
|
|
197
197
|
/**
|
|
198
198
|
* Parent → child: invoke an ADDON-LEVEL method on a loaded addon (not a cap).
|
|
199
199
|
* Carried as a correlated request frame (`channel.request`) — it returns a
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
2
|
-
require("./dist-
|
|
2
|
+
require("./dist-DdEXjTDo.js");
|
|
3
3
|
let node_crypto = require("node:crypto");
|
|
4
4
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
5
5
|
let _camstack_types_node = require("@camstack/types/node");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "./dist-
|
|
1
|
+
import "./dist-CZWAU40-.mjs";
|
|
2
2
|
import * as crypto$1 from "node:crypto";
|
|
3
3
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
4
4
|
import { ensureBinary, ensureFfmpeg, ensurePython, installPythonPackages, installPythonRequirements } from "@camstack/types/node";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_dist = require("./dist-
|
|
1
|
+
const require_dist = require("./dist-DdEXjTDo.js");
|
|
2
2
|
//#region src/builtins/sqlite-storage/retired-settings-keys.ts
|
|
3
3
|
/**
|
|
4
4
|
* Is THIS node the one whose settings store is the cluster's authority?
|
|
@@ -19,6 +19,22 @@ function settingsStoreIsAuthoritativeHere(env) {
|
|
|
19
19
|
/**
|
|
20
20
|
* The dead keys, per row.
|
|
21
21
|
*
|
|
22
|
+
* ## Addressing these rows
|
|
23
|
+
*
|
|
24
|
+
* Every namespace below is a FORKED addon, whose `ctx.settings` comes from
|
|
25
|
+
* `addon-context-factory` and writes `<addonId>:addon-settings` row `root`. The
|
|
26
|
+
* scoped table is therefore the right target — unlike the hub builtin whose
|
|
27
|
+
* mis-addressed spec is dissected at {@link RetiredRowSpec}. Confirmed per
|
|
28
|
+
* namespace against `packages/<pkg>/package.json`'s manifest `id`.
|
|
29
|
+
*
|
|
30
|
+
* ## `keys` vs `perNodeKeys` is a data-loss decision, not a style choice
|
|
31
|
+
*
|
|
32
|
+
* `perNodeKeys` matches `<key>` AND `<key>@<nodeId>`. That is right for a key
|
|
33
|
+
* whose per-node copies are all dead (the engine cascade, the decoder
|
|
34
|
+
* `backend`). It is WRONG for `probedBestHwaccel` / `probedBestAudioBackend`,
|
|
35
|
+
* where the bare key is unreachable residue but every `@<nodeId>` copy is the
|
|
36
|
+
* node's live probe result — those go under `keys`, which is exact-match.
|
|
37
|
+
*
|
|
22
38
|
* `detection-pipeline` / `addon-settings` / `root` — every key in this row is
|
|
23
39
|
* dead; the row itself is kept because the addon writes live keys into it
|
|
24
40
|
* (`pipelineTemplates`, `videoPipelineSteps`).
|
|
@@ -34,19 +50,79 @@ function settingsStoreIsAuthoritativeHere(env) {
|
|
|
34
50
|
* hardware (`resolveAutoEngine`). See
|
|
35
51
|
* `addon-pipeline/src/detection-pipeline/engine-store-keys.ts`.
|
|
36
52
|
*/
|
|
37
|
-
var RETIRED_SETTINGS_KEYS = [
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
var RETIRED_SETTINGS_KEYS = [
|
|
54
|
+
{
|
|
55
|
+
namespace: "detection-pipeline",
|
|
56
|
+
collection: "addon-settings",
|
|
57
|
+
row: "root",
|
|
58
|
+
keys: ["pipelineSteps", "pipelineEngine"],
|
|
59
|
+
perNodeKeys: [
|
|
60
|
+
"engineRuntime",
|
|
61
|
+
"engineBackend",
|
|
62
|
+
"engineDevice",
|
|
63
|
+
"probedBestEngine"
|
|
64
|
+
],
|
|
65
|
+
reason: "global step/engine seed and the per-node engine cascade — both removed; the live per-camera dispatch path never read either"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
namespace: "pipeline-orchestrator",
|
|
69
|
+
collection: "addon-settings",
|
|
70
|
+
row: "root",
|
|
71
|
+
keys: [
|
|
72
|
+
"enabledNodes",
|
|
73
|
+
"enabledDecoderNodes",
|
|
74
|
+
"enabledAudioNodes",
|
|
75
|
+
"remoteSourcingNodes",
|
|
76
|
+
"nativeLeaseTtlMs"
|
|
77
|
+
],
|
|
78
|
+
perNodeKeys: ["backend"],
|
|
79
|
+
reason: "the pre-singleton \"enabled nodes\" role model (node capability now lives per node in agent-settings and is derived by NodeTopology.refresh, never read from this row), `nativeLeaseTtlMs` superseded by `nativeLeaseActivityMs`, and the decoder `backend` selector whose resolver returns DEFAULT_DECODER_BACKEND unconditionally (decoder-backend.ts)"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
namespace: "stream-broker",
|
|
83
|
+
collection: "addon-settings",
|
|
84
|
+
row: "root",
|
|
85
|
+
keys: [
|
|
86
|
+
"maxDecodeFps",
|
|
87
|
+
"initialReconnectDelayMs",
|
|
88
|
+
"maxReconnectDelayMs"
|
|
89
|
+
],
|
|
90
|
+
perNodeKeys: [],
|
|
91
|
+
reason: "three form knobs deleted 2026-08-28 (D272): nothing capped decode fps, and the reconnect ladder has always run on the INITIAL/MAX_RECONNECT_DELAY_MS constants"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
namespace: "embedding-encoder",
|
|
95
|
+
collection: "addon-settings",
|
|
96
|
+
row: "root",
|
|
97
|
+
keys: ["runtime", "backend"],
|
|
98
|
+
perNodeKeys: [],
|
|
99
|
+
reason: "two selects deleted 2026-08-28 (D272); their only reference was a withTags log field, and the CUDA/CoreML options named acceleration that has never existed — embedding inference is always ONNX in the embedded Python"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
namespace: "audio-analyzer",
|
|
103
|
+
collection: "addon-settings",
|
|
104
|
+
row: "root",
|
|
105
|
+
keys: ["selectedAudioModel", "probedBestAudioBackend"],
|
|
106
|
+
perNodeKeys: [],
|
|
107
|
+
reason: "`selectedAudioModel` deleted 2026-08-28 (D272) — createAudioPipeline takes a backend and no model id, so it never reached inference; the BARE `probedBestAudioBackend` is pre-perNode residue that projectStore already drops (no bare fallback), so no node can ever read it"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
namespace: "decoder-nodeav",
|
|
111
|
+
collection: "addon-settings",
|
|
112
|
+
row: "root",
|
|
113
|
+
keys: ["probedBestHwaccel"],
|
|
114
|
+
perNodeKeys: [],
|
|
115
|
+
reason: "bare pre-perNode residue — the live probe result is `probedBestHwaccel@<nodeId>` and `projectStore` deliberately drops the bare key, so nothing can read it"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
namespace: "pipeline-analytics",
|
|
119
|
+
collection: "addon-settings",
|
|
120
|
+
row: "root",
|
|
121
|
+
keys: ["mediaAttachPolicy"],
|
|
122
|
+
perNodeKeys: [],
|
|
123
|
+
reason: "deleted 2026-08-28 (D272) — absent from MediaSettingsSchema, so the value was never even resolved, let alone read"
|
|
124
|
+
}
|
|
125
|
+
];
|
|
50
126
|
/**
|
|
51
127
|
* The device-manager's three fleet blobs, replaced by one row per device in
|
|
52
128
|
* `device-manager:devices` (`device-row-store.ts`).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { zt as asJsonObject } from "./dist-
|
|
1
|
+
import { zt as asJsonObject } from "./dist-CZWAU40-.mjs";
|
|
2
2
|
//#region src/builtins/sqlite-storage/retired-settings-keys.ts
|
|
3
3
|
/**
|
|
4
4
|
* Is THIS node the one whose settings store is the cluster's authority?
|
|
@@ -19,6 +19,22 @@ function settingsStoreIsAuthoritativeHere(env) {
|
|
|
19
19
|
/**
|
|
20
20
|
* The dead keys, per row.
|
|
21
21
|
*
|
|
22
|
+
* ## Addressing these rows
|
|
23
|
+
*
|
|
24
|
+
* Every namespace below is a FORKED addon, whose `ctx.settings` comes from
|
|
25
|
+
* `addon-context-factory` and writes `<addonId>:addon-settings` row `root`. The
|
|
26
|
+
* scoped table is therefore the right target — unlike the hub builtin whose
|
|
27
|
+
* mis-addressed spec is dissected at {@link RetiredRowSpec}. Confirmed per
|
|
28
|
+
* namespace against `packages/<pkg>/package.json`'s manifest `id`.
|
|
29
|
+
*
|
|
30
|
+
* ## `keys` vs `perNodeKeys` is a data-loss decision, not a style choice
|
|
31
|
+
*
|
|
32
|
+
* `perNodeKeys` matches `<key>` AND `<key>@<nodeId>`. That is right for a key
|
|
33
|
+
* whose per-node copies are all dead (the engine cascade, the decoder
|
|
34
|
+
* `backend`). It is WRONG for `probedBestHwaccel` / `probedBestAudioBackend`,
|
|
35
|
+
* where the bare key is unreachable residue but every `@<nodeId>` copy is the
|
|
36
|
+
* node's live probe result — those go under `keys`, which is exact-match.
|
|
37
|
+
*
|
|
22
38
|
* `detection-pipeline` / `addon-settings` / `root` — every key in this row is
|
|
23
39
|
* dead; the row itself is kept because the addon writes live keys into it
|
|
24
40
|
* (`pipelineTemplates`, `videoPipelineSteps`).
|
|
@@ -34,19 +50,79 @@ function settingsStoreIsAuthoritativeHere(env) {
|
|
|
34
50
|
* hardware (`resolveAutoEngine`). See
|
|
35
51
|
* `addon-pipeline/src/detection-pipeline/engine-store-keys.ts`.
|
|
36
52
|
*/
|
|
37
|
-
var RETIRED_SETTINGS_KEYS = [
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
var RETIRED_SETTINGS_KEYS = [
|
|
54
|
+
{
|
|
55
|
+
namespace: "detection-pipeline",
|
|
56
|
+
collection: "addon-settings",
|
|
57
|
+
row: "root",
|
|
58
|
+
keys: ["pipelineSteps", "pipelineEngine"],
|
|
59
|
+
perNodeKeys: [
|
|
60
|
+
"engineRuntime",
|
|
61
|
+
"engineBackend",
|
|
62
|
+
"engineDevice",
|
|
63
|
+
"probedBestEngine"
|
|
64
|
+
],
|
|
65
|
+
reason: "global step/engine seed and the per-node engine cascade — both removed; the live per-camera dispatch path never read either"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
namespace: "pipeline-orchestrator",
|
|
69
|
+
collection: "addon-settings",
|
|
70
|
+
row: "root",
|
|
71
|
+
keys: [
|
|
72
|
+
"enabledNodes",
|
|
73
|
+
"enabledDecoderNodes",
|
|
74
|
+
"enabledAudioNodes",
|
|
75
|
+
"remoteSourcingNodes",
|
|
76
|
+
"nativeLeaseTtlMs"
|
|
77
|
+
],
|
|
78
|
+
perNodeKeys: ["backend"],
|
|
79
|
+
reason: "the pre-singleton \"enabled nodes\" role model (node capability now lives per node in agent-settings and is derived by NodeTopology.refresh, never read from this row), `nativeLeaseTtlMs` superseded by `nativeLeaseActivityMs`, and the decoder `backend` selector whose resolver returns DEFAULT_DECODER_BACKEND unconditionally (decoder-backend.ts)"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
namespace: "stream-broker",
|
|
83
|
+
collection: "addon-settings",
|
|
84
|
+
row: "root",
|
|
85
|
+
keys: [
|
|
86
|
+
"maxDecodeFps",
|
|
87
|
+
"initialReconnectDelayMs",
|
|
88
|
+
"maxReconnectDelayMs"
|
|
89
|
+
],
|
|
90
|
+
perNodeKeys: [],
|
|
91
|
+
reason: "three form knobs deleted 2026-08-28 (D272): nothing capped decode fps, and the reconnect ladder has always run on the INITIAL/MAX_RECONNECT_DELAY_MS constants"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
namespace: "embedding-encoder",
|
|
95
|
+
collection: "addon-settings",
|
|
96
|
+
row: "root",
|
|
97
|
+
keys: ["runtime", "backend"],
|
|
98
|
+
perNodeKeys: [],
|
|
99
|
+
reason: "two selects deleted 2026-08-28 (D272); their only reference was a withTags log field, and the CUDA/CoreML options named acceleration that has never existed — embedding inference is always ONNX in the embedded Python"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
namespace: "audio-analyzer",
|
|
103
|
+
collection: "addon-settings",
|
|
104
|
+
row: "root",
|
|
105
|
+
keys: ["selectedAudioModel", "probedBestAudioBackend"],
|
|
106
|
+
perNodeKeys: [],
|
|
107
|
+
reason: "`selectedAudioModel` deleted 2026-08-28 (D272) — createAudioPipeline takes a backend and no model id, so it never reached inference; the BARE `probedBestAudioBackend` is pre-perNode residue that projectStore already drops (no bare fallback), so no node can ever read it"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
namespace: "decoder-nodeav",
|
|
111
|
+
collection: "addon-settings",
|
|
112
|
+
row: "root",
|
|
113
|
+
keys: ["probedBestHwaccel"],
|
|
114
|
+
perNodeKeys: [],
|
|
115
|
+
reason: "bare pre-perNode residue — the live probe result is `probedBestHwaccel@<nodeId>` and `projectStore` deliberately drops the bare key, so nothing can read it"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
namespace: "pipeline-analytics",
|
|
119
|
+
collection: "addon-settings",
|
|
120
|
+
row: "root",
|
|
121
|
+
keys: ["mediaAttachPolicy"],
|
|
122
|
+
perNodeKeys: [],
|
|
123
|
+
reason: "deleted 2026-08-28 (D272) — absent from MediaSettingsSchema, so the value was never even resolved, let alone read"
|
|
124
|
+
}
|
|
125
|
+
];
|
|
50
126
|
/**
|
|
51
127
|
* The device-manager's three fleet blobs, replaced by one row per device in
|
|
52
128
|
* `device-manager:devices` (`device-row-store.ts`).
|