@camstack/system 1.2.484 → 1.2.486
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/{agent-https-DttPIFry.mjs → agent-https-C4PLR74Z.mjs} +1 -1
- package/dist/{agent-https-CW8aLMDL.js → agent-https-DP-Ds2hU.js} +1 -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/autotrack/index.js +1 -1
- package/dist/builtins/autotrack/index.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2 -2
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2 -2
- package/dist/builtins/calendars/calendars.addon.js +1 -1
- package/dist/builtins/calendars/calendars.addon.mjs +1 -1
- package/dist/builtins/camera-grid/index.js +1 -1
- package/dist/builtins/camera-grid/index.mjs +1 -1
- package/dist/builtins/composer/composer.addon.js +69 -15
- package/dist/builtins/composer/composer.addon.mjs +69 -15
- package/dist/builtins/composer/composition-runtime.d.ts +2 -0
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/composition-sources.d.ts +3 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +53 -28
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +53 -28
- package/dist/builtins/device-history/device-history.addon.d.ts +2 -0
- package/dist/builtins/device-history/device-history.addon.js +248 -4
- package/dist/builtins/device-history/device-history.addon.mjs +248 -4
- package/dist/builtins/device-history/query/history-query.d.ts +5 -1
- package/dist/builtins/device-history/runtime/history-runtime.d.ts +18 -1
- package/dist/builtins/device-history/store/history-schema.d.ts +2 -0
- package/dist/builtins/device-history/store/history-store.d.ts +11 -0
- package/dist/builtins/device-history/store/series-scale.d.ts +37 -0
- package/dist/builtins/device-manager/device-manager.addon.js +3 -2
- package/dist/builtins/device-manager/device-manager.addon.mjs +3 -2
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/keychain/index.js +3 -3
- package/dist/builtins/keychain/index.mjs +3 -3
- 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/local-auth.addon.js +2 -2
- package/dist/builtins/local-auth/local-auth.addon.mjs +2 -2
- package/dist/builtins/local-network/local-network.addon.js +2 -2
- package/dist/builtins/local-network/local-network.addon.mjs +2 -2
- 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/record-entries/index.js +1 -1
- package/dist/builtins/record-entries/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/index.js +1 -1
- package/dist/builtins/sqlite-storage/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +2 -2
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +2 -2
- 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 +3 -3
- package/dist/builtins/system-config/system-config.addon.mjs +3 -3
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{composition-sources-DqRPHdtw.js → composition-sources-CN8K2Q91.js} +4 -2
- package/dist/{composition-sources-DEsDonpg.mjs → composition-sources-IxiUkrz1.mjs} +4 -2
- package/dist/{constants-71vf77HY.js → constants-1S7BBGMb.js} +1 -1
- package/dist/{constants-B3FDrBIq.mjs → constants-DLyGFHZ2.mjs} +1 -1
- package/dist/{device-ca-bhz04X_N.mjs → device-ca-Cbf7_R9t.mjs} +1 -1
- package/dist/{device-ca-BDPYXhkH.js → device-ca-DoOFG0nm.js} +1 -1
- package/dist/{dist-k--OhKkO.js → dist-D-d_UWL4.js} +1375 -537
- package/dist/{dist-BT_THdzJ.mjs → dist-HBue971z.mjs} +1364 -538
- package/dist/file-host-worker.js +1 -1
- package/dist/file-host-worker.mjs +1 -1
- package/dist/{hub-mdns-ciao-DDgdvcQw.mjs → hub-mdns-ciao-CuEWb6gB.mjs} +2 -2
- package/dist/{hub-mdns-ciao-CGXfhvTk.js → hub-mdns-ciao-dcacrwqd.js} +2 -2
- package/dist/index.js +7 -7
- package/dist/index.mjs +7 -7
- package/dist/{restore-archive-z0XT2g29.mjs → restore-archive-BGBRadFJ.mjs} +1 -1
- package/dist/{restore-archive-B-GiglWt.js → restore-archive-DHdXrKwG.js} +1 -1
- package/dist/{retention-DFkmhjeH.mjs → retention-8uqDWll8.mjs} +1 -1
- package/dist/{retention-DR0_xRTy.js → retention-ChgrkTfz.js} +1 -1
- package/dist/{wal-maintenance-C4cma95b.js → wal-maintenance-BOT7wWvH.js} +0 -0
- package/dist/{wal-maintenance-CVDrL_BD.mjs → wal-maintenance-DubGwqz2.mjs} +0 -0
- package/package.json +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
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-D-d_UWL4.js");
|
|
4
4
|
const require_read_all_rows$1 = require("../../read-all-rows-CVoO1ONM.js");
|
|
5
|
-
const require_composition_sources = require("../../composition-sources-
|
|
5
|
+
const require_composition_sources = require("../../composition-sources-CN8K2Q91.js");
|
|
6
6
|
const require_prefix_range = require("../../prefix-range-D_KueXbQ.js");
|
|
7
7
|
const require_prefix_walk = require("../../prefix-walk-Dv6MLZlM.js");
|
|
8
8
|
let zod = require("zod");
|
|
@@ -1933,6 +1933,16 @@ function refuseIfChanged(deps, blockId, expectedUpdatedAt) {
|
|
|
1933
1933
|
function existingTarget(composition) {
|
|
1934
1934
|
return composition.target.kind === "existing" ? composition.target.device : null;
|
|
1935
1935
|
}
|
|
1936
|
+
function helperMemberDeviceIds(composition, sources) {
|
|
1937
|
+
const helper = composition.helper;
|
|
1938
|
+
if (helper === void 0) return [];
|
|
1939
|
+
const ids = [];
|
|
1940
|
+
for (const member of helper.members) {
|
|
1941
|
+
const found = sources.get(require_dist.compositionSourceKey(member.source));
|
|
1942
|
+
if (found?.kind === "found") ids.push(found.deviceId);
|
|
1943
|
+
}
|
|
1944
|
+
return ids;
|
|
1945
|
+
}
|
|
1936
1946
|
async function validateAgainstStore(deps, composition, blockId) {
|
|
1937
1947
|
if (!deps.store.isLoaded()) throw new Error(`${NOT_LOADED_REASON} — a composition cannot be judged against the stored ones until it has; retry shortly`);
|
|
1938
1948
|
const self = blockId === null ? null : require_dist.composedDeviceRef(blockId);
|
|
@@ -1942,29 +1952,37 @@ async function validateAgainstStore(deps, composition, blockId) {
|
|
|
1942
1952
|
const blocks = deps.store.list();
|
|
1943
1953
|
const read = await deps.describe(refs, [...target === null ? [] : [target], ...storedCustomizationTargets(blocks)]);
|
|
1944
1954
|
const stored = storedPeers(blocks, read.targets, deps.lookupCap, blockId);
|
|
1945
|
-
return
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1955
|
+
return {
|
|
1956
|
+
validation: require_dist.validateComposition(composition, {
|
|
1957
|
+
lookupCap: deps.lookupCap,
|
|
1958
|
+
sources: read.sources,
|
|
1959
|
+
self,
|
|
1960
|
+
blockId,
|
|
1961
|
+
target: target === null ? null : read.targets.get(require_dist.compositionSourceKey(target)) ?? {
|
|
1962
|
+
kind: "unreadable",
|
|
1963
|
+
error: "it was not read"
|
|
1964
|
+
},
|
|
1965
|
+
peers: stored.peers,
|
|
1966
|
+
unreadTargets: stored.unread
|
|
1967
|
+
}),
|
|
1968
|
+
memberDeviceIds: helperMemberDeviceIds(composition, read.sources)
|
|
1969
|
+
};
|
|
1957
1970
|
}
|
|
1958
1971
|
function describeProblems(validation) {
|
|
1959
1972
|
return validation.problems.map((p) => `${p.path} [${p.code}]: ${p.message}`);
|
|
1960
1973
|
}
|
|
1961
|
-
function refuse(deps, subject, validation) {
|
|
1974
|
+
function refuse(deps, subject, validation, memberDeviceIds) {
|
|
1962
1975
|
const problems = describeProblems(validation);
|
|
1963
|
-
|
|
1976
|
+
const meta = {
|
|
1964
1977
|
name: subject.name,
|
|
1965
1978
|
blockId: subject.blockId,
|
|
1966
1979
|
problems
|
|
1967
|
-
}
|
|
1980
|
+
};
|
|
1981
|
+
if (memberDeviceIds.length === 0) deps.logger.warn("composition save refused", { meta });
|
|
1982
|
+
else for (const deviceId of memberDeviceIds) deps.logger.warn("composition save refused", {
|
|
1983
|
+
tags: { deviceId },
|
|
1984
|
+
meta
|
|
1985
|
+
});
|
|
1968
1986
|
throw new Error(`core-blocks: the composition "${subject.name}" was refused — ${problems.join("; ")}`);
|
|
1969
1987
|
}
|
|
1970
1988
|
async function readStates(deps, blockIds) {
|
|
@@ -2109,11 +2127,11 @@ function buildCompositionApi(deps) {
|
|
|
2109
2127
|
return {
|
|
2110
2128
|
createComposition: ({ block, caller }) => serialized(async () => {
|
|
2111
2129
|
const name = await nameOnCreate(deps, block);
|
|
2112
|
-
const
|
|
2113
|
-
if (!validation.ok && require_dist.problemsBlockSave(validation.problems)) refuse(deps, {
|
|
2130
|
+
const judged = await validateAgainstStore(deps, block.composition, null);
|
|
2131
|
+
if (!judged.validation.ok && require_dist.problemsBlockSave(judged.validation.problems)) refuse(deps, {
|
|
2114
2132
|
name,
|
|
2115
2133
|
blockId: null
|
|
2116
|
-
}, validation);
|
|
2134
|
+
}, judged.validation, judged.memberDeviceIds);
|
|
2117
2135
|
const created = await deps.store.createComposition({
|
|
2118
2136
|
...block,
|
|
2119
2137
|
name
|
|
@@ -2130,11 +2148,11 @@ function buildCompositionApi(deps) {
|
|
|
2130
2148
|
refuseIfChanged(deps, blockId, expectedUpdatedAt);
|
|
2131
2149
|
await refuseRetarget(deps, blockId, block);
|
|
2132
2150
|
if (block.composition !== void 0) {
|
|
2133
|
-
const
|
|
2134
|
-
if (!validation.ok && require_dist.problemsBlockSave(validation.problems)) refuse(deps, {
|
|
2151
|
+
const judged = await validateAgainstStore(deps, block.composition, blockId);
|
|
2152
|
+
if (!judged.validation.ok && require_dist.problemsBlockSave(judged.validation.problems)) refuse(deps, {
|
|
2135
2153
|
name: block.name ?? blockId,
|
|
2136
2154
|
blockId
|
|
2137
|
-
}, validation);
|
|
2155
|
+
}, judged.validation, judged.memberDeviceIds);
|
|
2138
2156
|
}
|
|
2139
2157
|
const updated = await deps.store.updateComposition(blockId, block);
|
|
2140
2158
|
deps.logger.info("composition updated", { meta: {
|
|
@@ -2212,7 +2230,7 @@ function buildCompositionApi(deps) {
|
|
|
2212
2230
|
}
|
|
2213
2231
|
};
|
|
2214
2232
|
},
|
|
2215
|
-
validateComposition: async ({ composition, blockId }) => validateAgainstStore(deps, composition, blockId ?? null),
|
|
2233
|
+
validateComposition: async ({ composition, blockId }) => (await validateAgainstStore(deps, composition, blockId ?? null)).validation,
|
|
2216
2234
|
listComposableCaps: async ({ deviceType }) => ({ caps: [...require_dist.describeComposableCaps(deps.capabilityDefinitions, deviceType)] })
|
|
2217
2235
|
};
|
|
2218
2236
|
}
|
|
@@ -2637,10 +2655,17 @@ var CoreBlocksAddon = class extends require_dist.BaseAddon {
|
|
|
2637
2655
|
return buildCompositionApi({
|
|
2638
2656
|
store: this.requireStore(),
|
|
2639
2657
|
describe: (sources, targets) => require_composition_sources.describeCompositionSources({
|
|
2640
|
-
listByAddon: async (addonId) =>
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2658
|
+
listByAddon: async (addonId) => {
|
|
2659
|
+
return (await requireApi().deviceManager.listAll.query({
|
|
2660
|
+
addonId,
|
|
2661
|
+
projection: "slim"
|
|
2662
|
+
})).map((row) => ({
|
|
2663
|
+
id: row.id,
|
|
2664
|
+
stableId: row.stableId,
|
|
2665
|
+
type: row.type,
|
|
2666
|
+
...row.sourceInfo?.quantity === void 0 ? {} : { quantity: row.sourceInfo.quantity }
|
|
2667
|
+
}));
|
|
2668
|
+
},
|
|
2644
2669
|
bindings: async (deviceId) => (await requireApi().deviceManager.getBindings.query({ deviceId })).entries
|
|
2645
2670
|
}, sources, targets),
|
|
2646
2671
|
lookupCap: require_dist.buildCapabilityLookup(require_dist.ALL_CAPABILITY_DEFINITIONS),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { $n as planComposition, Bt as coreBlockComposition,
|
|
1
|
+
import { $n as planComposition, Bt as coreBlockComposition, Ht as coreBlockSourceKind, Ji as defineRecordKinds, Jr as compositionSourceKey, Kn as normalizeCoreBlockWrite, N as DeclaredDevices, Oa as transformSecretWrite, Ot as buildCapabilityLookup, Pr as validateComposition, Rt as compositionSourceRefs, Ui as collectSecretMarkerRefs, Ur as composedDeviceRef, Ut as coreBlocksCapability, Vt as coreBlockIdFromAddonId, Zt as describeComposableCaps, dr as resolveCoreBlockFiles, f as COMPOSER_RUNNER_ID, la as isSecretRefOwnedBy, m as CORE_BLOCK_ADDON_PREFIX, ni as BaseAddon, p as CORE_BLOCKS_ADDON_ID, r as ALL_CAPABILITY_DEFINITIONS, sa as isSecretMarker, sr as replacedFieldKeys, ta as hydrateSchema, ti as errMsg, tr as problemsBlockSave, ur as resolveCoreBlockEntry, v as CoreBlockSchema, wa as secretTreeFromSchema, xa as resolveSecretMarkers, zt as coreBlockAddonId } from "../../dist-HBue971z.mjs";
|
|
2
2
|
import { t as require_read_all_rows } from "../../read-all-rows-TaPqdWNF.mjs";
|
|
3
|
-
import { t as describeCompositionSources } from "../../composition-sources-
|
|
3
|
+
import { t as describeCompositionSources } from "../../composition-sources-IxiUkrz1.mjs";
|
|
4
4
|
import { t as prefixRange } from "../../prefix-range-Dl0znowN.mjs";
|
|
5
5
|
import { n as unwrapStoredValue, t as loadPrefixed } from "../../prefix-walk-DAOBSyH1.mjs";
|
|
6
6
|
import { createRequire } from "node:module";
|
|
@@ -1928,6 +1928,16 @@ function refuseIfChanged(deps, blockId, expectedUpdatedAt) {
|
|
|
1928
1928
|
function existingTarget(composition) {
|
|
1929
1929
|
return composition.target.kind === "existing" ? composition.target.device : null;
|
|
1930
1930
|
}
|
|
1931
|
+
function helperMemberDeviceIds(composition, sources) {
|
|
1932
|
+
const helper = composition.helper;
|
|
1933
|
+
if (helper === void 0) return [];
|
|
1934
|
+
const ids = [];
|
|
1935
|
+
for (const member of helper.members) {
|
|
1936
|
+
const found = sources.get(compositionSourceKey(member.source));
|
|
1937
|
+
if (found?.kind === "found") ids.push(found.deviceId);
|
|
1938
|
+
}
|
|
1939
|
+
return ids;
|
|
1940
|
+
}
|
|
1931
1941
|
async function validateAgainstStore(deps, composition, blockId) {
|
|
1932
1942
|
if (!deps.store.isLoaded()) throw new Error(`${NOT_LOADED_REASON} — a composition cannot be judged against the stored ones until it has; retry shortly`);
|
|
1933
1943
|
const self = blockId === null ? null : composedDeviceRef(blockId);
|
|
@@ -1937,29 +1947,37 @@ async function validateAgainstStore(deps, composition, blockId) {
|
|
|
1937
1947
|
const blocks = deps.store.list();
|
|
1938
1948
|
const read = await deps.describe(refs, [...target === null ? [] : [target], ...storedCustomizationTargets(blocks)]);
|
|
1939
1949
|
const stored = storedPeers(blocks, read.targets, deps.lookupCap, blockId);
|
|
1940
|
-
return
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1950
|
+
return {
|
|
1951
|
+
validation: validateComposition(composition, {
|
|
1952
|
+
lookupCap: deps.lookupCap,
|
|
1953
|
+
sources: read.sources,
|
|
1954
|
+
self,
|
|
1955
|
+
blockId,
|
|
1956
|
+
target: target === null ? null : read.targets.get(compositionSourceKey(target)) ?? {
|
|
1957
|
+
kind: "unreadable",
|
|
1958
|
+
error: "it was not read"
|
|
1959
|
+
},
|
|
1960
|
+
peers: stored.peers,
|
|
1961
|
+
unreadTargets: stored.unread
|
|
1962
|
+
}),
|
|
1963
|
+
memberDeviceIds: helperMemberDeviceIds(composition, read.sources)
|
|
1964
|
+
};
|
|
1952
1965
|
}
|
|
1953
1966
|
function describeProblems(validation) {
|
|
1954
1967
|
return validation.problems.map((p) => `${p.path} [${p.code}]: ${p.message}`);
|
|
1955
1968
|
}
|
|
1956
|
-
function refuse(deps, subject, validation) {
|
|
1969
|
+
function refuse(deps, subject, validation, memberDeviceIds) {
|
|
1957
1970
|
const problems = describeProblems(validation);
|
|
1958
|
-
|
|
1971
|
+
const meta = {
|
|
1959
1972
|
name: subject.name,
|
|
1960
1973
|
blockId: subject.blockId,
|
|
1961
1974
|
problems
|
|
1962
|
-
}
|
|
1975
|
+
};
|
|
1976
|
+
if (memberDeviceIds.length === 0) deps.logger.warn("composition save refused", { meta });
|
|
1977
|
+
else for (const deviceId of memberDeviceIds) deps.logger.warn("composition save refused", {
|
|
1978
|
+
tags: { deviceId },
|
|
1979
|
+
meta
|
|
1980
|
+
});
|
|
1963
1981
|
throw new Error(`core-blocks: the composition "${subject.name}" was refused — ${problems.join("; ")}`);
|
|
1964
1982
|
}
|
|
1965
1983
|
async function readStates(deps, blockIds) {
|
|
@@ -2104,11 +2122,11 @@ function buildCompositionApi(deps) {
|
|
|
2104
2122
|
return {
|
|
2105
2123
|
createComposition: ({ block, caller }) => serialized(async () => {
|
|
2106
2124
|
const name = await nameOnCreate(deps, block);
|
|
2107
|
-
const
|
|
2108
|
-
if (!validation.ok && problemsBlockSave(validation.problems)) refuse(deps, {
|
|
2125
|
+
const judged = await validateAgainstStore(deps, block.composition, null);
|
|
2126
|
+
if (!judged.validation.ok && problemsBlockSave(judged.validation.problems)) refuse(deps, {
|
|
2109
2127
|
name,
|
|
2110
2128
|
blockId: null
|
|
2111
|
-
}, validation);
|
|
2129
|
+
}, judged.validation, judged.memberDeviceIds);
|
|
2112
2130
|
const created = await deps.store.createComposition({
|
|
2113
2131
|
...block,
|
|
2114
2132
|
name
|
|
@@ -2125,11 +2143,11 @@ function buildCompositionApi(deps) {
|
|
|
2125
2143
|
refuseIfChanged(deps, blockId, expectedUpdatedAt);
|
|
2126
2144
|
await refuseRetarget(deps, blockId, block);
|
|
2127
2145
|
if (block.composition !== void 0) {
|
|
2128
|
-
const
|
|
2129
|
-
if (!validation.ok && problemsBlockSave(validation.problems)) refuse(deps, {
|
|
2146
|
+
const judged = await validateAgainstStore(deps, block.composition, blockId);
|
|
2147
|
+
if (!judged.validation.ok && problemsBlockSave(judged.validation.problems)) refuse(deps, {
|
|
2130
2148
|
name: block.name ?? blockId,
|
|
2131
2149
|
blockId
|
|
2132
|
-
}, validation);
|
|
2150
|
+
}, judged.validation, judged.memberDeviceIds);
|
|
2133
2151
|
}
|
|
2134
2152
|
const updated = await deps.store.updateComposition(blockId, block);
|
|
2135
2153
|
deps.logger.info("composition updated", { meta: {
|
|
@@ -2207,7 +2225,7 @@ function buildCompositionApi(deps) {
|
|
|
2207
2225
|
}
|
|
2208
2226
|
};
|
|
2209
2227
|
},
|
|
2210
|
-
validateComposition: async ({ composition, blockId }) => validateAgainstStore(deps, composition, blockId ?? null),
|
|
2228
|
+
validateComposition: async ({ composition, blockId }) => (await validateAgainstStore(deps, composition, blockId ?? null)).validation,
|
|
2211
2229
|
listComposableCaps: async ({ deviceType }) => ({ caps: [...describeComposableCaps(deps.capabilityDefinitions, deviceType)] })
|
|
2212
2230
|
};
|
|
2213
2231
|
}
|
|
@@ -2632,10 +2650,17 @@ var CoreBlocksAddon = class extends BaseAddon {
|
|
|
2632
2650
|
return buildCompositionApi({
|
|
2633
2651
|
store: this.requireStore(),
|
|
2634
2652
|
describe: (sources, targets) => describeCompositionSources({
|
|
2635
|
-
listByAddon: async (addonId) =>
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2653
|
+
listByAddon: async (addonId) => {
|
|
2654
|
+
return (await requireApi().deviceManager.listAll.query({
|
|
2655
|
+
addonId,
|
|
2656
|
+
projection: "slim"
|
|
2657
|
+
})).map((row) => ({
|
|
2658
|
+
id: row.id,
|
|
2659
|
+
stableId: row.stableId,
|
|
2660
|
+
type: row.type,
|
|
2661
|
+
...row.sourceInfo?.quantity === void 0 ? {} : { quantity: row.sourceInfo.quantity }
|
|
2662
|
+
}));
|
|
2663
|
+
},
|
|
2639
2664
|
bindings: async (deviceId) => (await requireApi().deviceManager.getBindings.query({ deviceId })).entries
|
|
2640
2665
|
}, sources, targets),
|
|
2641
2666
|
lookupCap: buildCapabilityLookup(ALL_CAPABILITY_DEFINITIONS),
|
|
@@ -41,6 +41,8 @@ export declare class DeviceHistoryAddon extends BaseAddon<DeviceHistoryConfig> {
|
|
|
41
41
|
/** Readiness of both provided caps, on the bare node this runner belongs to. */
|
|
42
42
|
private emitStoreReadiness;
|
|
43
43
|
private retention;
|
|
44
|
+
/** Unraid array counters still stored in GiB. A failed listing throws to the caller. */
|
|
45
|
+
private legacyScales;
|
|
44
46
|
private requireRuntime;
|
|
45
47
|
protected onInitialize(): Promise<ProviderRegistration[]>;
|
|
46
48
|
override onHubReachable(): Promise<void>;
|
|
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
7
|
-
const require_retention = require("../../retention-
|
|
6
|
+
const require_dist = require("../../dist-D-d_UWL4.js");
|
|
7
|
+
const require_retention = require("../../retention-ChgrkTfz.js");
|
|
8
8
|
//#region src/builtins/device-history/capture/point-writer.ts
|
|
9
9
|
var FLUSH_INTERVAL_MS = 1e4;
|
|
10
10
|
var MAX_BUFFER_AGE_MS = 6e4;
|
|
@@ -451,6 +451,13 @@ var MAX_SCOPES = 50;
|
|
|
451
451
|
/** The power-meter series the energy key is derived from, meter first. */
|
|
452
452
|
var ENERGY_METER_KEY = require_retention.capSeriesKey("power-meter", "kwhTotal");
|
|
453
453
|
var ENERGY_POWER_KEY = require_retention.capSeriesKey("power-meter", "watts");
|
|
454
|
+
/**
|
|
455
|
+
* Series whose quantity is chosen per device (D944). Weather is not here:
|
|
456
|
+
* each weather field has its own quantity on the capability, and the catalog
|
|
457
|
+
* unit is that base. A past weather point stored in another unit cannot be
|
|
458
|
+
* rescaled — the unit at sample time was not kept.
|
|
459
|
+
*/
|
|
460
|
+
var DEVICE_QUANTITY_KEYS = new Set([require_retention.capSeriesKey("numeric-sensor", "value")]);
|
|
454
461
|
function retentionMsOf(tier, policy) {
|
|
455
462
|
if (tier === "raw") return policy.rawDays * require_retention.DAY_MS;
|
|
456
463
|
if (tier === "5m") return policy.fiveMinuteDays * require_retention.DAY_MS;
|
|
@@ -717,12 +724,26 @@ var HistoryQuery = class {
|
|
|
717
724
|
/** The metric's fixed unit, else the device's own (a `unitFrom` field), else unknown. */
|
|
718
725
|
async unitOf(subject, series, fixed, slices) {
|
|
719
726
|
if (fixed !== null || subject.kind !== "device" || !series.key.startsWith("cap:")) return fixed;
|
|
727
|
+
if (DEVICE_QUANTITY_KEYS.has(series.key)) {
|
|
728
|
+
const quantity = await this.quantityOf(subject.deviceId);
|
|
729
|
+
if (quantity === null || quantity === "device" || quantity === "none") return null;
|
|
730
|
+
return require_dist.historyUnitFor(quantity) ?? null;
|
|
731
|
+
}
|
|
720
732
|
const spec = this.specOf(series.key);
|
|
721
733
|
if (spec?.unitFrom === void 0) return null;
|
|
722
734
|
const capName = series.key.slice(require_retention.CAP_KEY_PREFIX.length, series.key.indexOf("."));
|
|
723
735
|
const slice = await this.sliceOf(subject.deviceId, capName, slices);
|
|
724
736
|
return slice === null ? null : require_retention.readUnit(slice, spec.unitFrom);
|
|
725
737
|
}
|
|
738
|
+
quantityOf(deviceId) {
|
|
739
|
+
const pending = this.quantities.get(deviceId);
|
|
740
|
+
if (pending !== void 0) return pending;
|
|
741
|
+
const read = this.deps.readDeviceQuantity;
|
|
742
|
+
const run = read === void 0 ? Promise.resolve(null) : read(deviceId).catch(() => null);
|
|
743
|
+
this.quantities.set(deviceId, run);
|
|
744
|
+
return run;
|
|
745
|
+
}
|
|
746
|
+
quantities = /* @__PURE__ */ new Map();
|
|
726
747
|
specOf(key) {
|
|
727
748
|
const body = key.slice(require_retention.CAP_KEY_PREFIX.length);
|
|
728
749
|
const dot = body.indexOf(".");
|
|
@@ -882,6 +903,59 @@ var OrphanSeries = class {
|
|
|
882
903
|
}
|
|
883
904
|
};
|
|
884
905
|
//#endregion
|
|
906
|
+
//#region src/builtins/device-history/store/series-scale.ts
|
|
907
|
+
/**
|
|
908
|
+
* One-shot rescales of series whose every stored point shared one factor
|
|
909
|
+
* (D944). A reading already in the base unit is at or above `legacyMax` and
|
|
910
|
+
* is left alone, so a second pass does not multiply it again.
|
|
911
|
+
*
|
|
912
|
+
* Rollup `sum` / `tw_sum` follow the bucket when min, max and last are still
|
|
913
|
+
* in the old unit. Judging the sum itself would skip a day's samples of a
|
|
914
|
+
* large gauge (many × GiB already exceeds the ceiling) and keep the raw
|
|
915
|
+
* points and the rollup in different units.
|
|
916
|
+
*/
|
|
917
|
+
var GIB_TO_BYTES = 1024 ** 3;
|
|
918
|
+
var DAY_TO_SECONDS = 86400;
|
|
919
|
+
/** A homelab array in GiB is below 1 MiB; the same array in bytes is not. */
|
|
920
|
+
var INFORMATION_LEGACY_MAX = 1024 ** 2;
|
|
921
|
+
/** Desiccant life in days is below this; the same life in seconds is not. */
|
|
922
|
+
var DESICCANT_LEGACY_MAX_DAYS = 1e4;
|
|
923
|
+
var DESICCANT_SERIES_KEY = "cap:pet-feeder.desiccantLeftDays";
|
|
924
|
+
var DESICCANT_SCALE_ID = "pet-feeder-desiccant-days-to-seconds";
|
|
925
|
+
var UNRAID_INFORMATION_KEYS = [
|
|
926
|
+
"array_total",
|
|
927
|
+
"array_used",
|
|
928
|
+
"array_free"
|
|
929
|
+
];
|
|
930
|
+
var NUMERIC_SENSOR_SERIES_KEY = "cap:numeric-sensor.value";
|
|
931
|
+
/** The stored number after one rescale, or the same number when it is already base. */
|
|
932
|
+
function scaledMagnitude(value, factor, legacyMax) {
|
|
933
|
+
if (!Number.isFinite(value) || value === 0) return value;
|
|
934
|
+
if (Math.abs(value) >= legacyMax) return value;
|
|
935
|
+
return value * factor;
|
|
936
|
+
}
|
|
937
|
+
function rollupIsLegacy(row, legacyMax) {
|
|
938
|
+
const samples = [
|
|
939
|
+
row.min,
|
|
940
|
+
row.max,
|
|
941
|
+
...row.last === null ? [] : [row.last]
|
|
942
|
+
];
|
|
943
|
+
if (samples.some((value) => !Number.isFinite(value))) return false;
|
|
944
|
+
if (samples.every((value) => value === 0)) return false;
|
|
945
|
+
return samples.every((value) => Math.abs(value) < legacyMax);
|
|
946
|
+
}
|
|
947
|
+
/** Unraid array capacity children. Other numeric sensors on the same key stay put. */
|
|
948
|
+
function unraidInformationScale(deviceId, entityKey) {
|
|
949
|
+
if (!UNRAID_INFORMATION_KEYS.includes(entityKey)) return null;
|
|
950
|
+
return {
|
|
951
|
+
seriesKey: NUMERIC_SENSOR_SERIES_KEY,
|
|
952
|
+
deviceId,
|
|
953
|
+
factor: GIB_TO_BYTES,
|
|
954
|
+
legacyMax: INFORMATION_LEGACY_MAX,
|
|
955
|
+
migrationId: `unraid-gib-to-bytes:${String(deviceId)}`
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
//#endregion
|
|
885
959
|
//#region src/builtins/device-history/store/history-schema.ts
|
|
886
960
|
var HISTORY_NAMESPACE = "device-history";
|
|
887
961
|
var COLLECTIONS = {
|
|
@@ -892,7 +966,9 @@ var COLLECTIONS = {
|
|
|
892
966
|
rollup1h: "rollup-1h",
|
|
893
967
|
rollup1d: "rollup-1d",
|
|
894
968
|
optOuts: "device-opt-outs",
|
|
895
|
-
departures: "device-departures"
|
|
969
|
+
departures: "device-departures",
|
|
970
|
+
/** One row per applied base-unit rescale, in history.db so it travels with the points. */
|
|
971
|
+
appliedScales: "applied-scales"
|
|
896
972
|
};
|
|
897
973
|
function rollupCollectionOf(tier) {
|
|
898
974
|
if (tier === "5m") return COLLECTIONS.rollup5m;
|
|
@@ -1145,6 +1221,21 @@ var HISTORY_DECLARATIONS = [
|
|
|
1145
1221
|
columns: ["device_id"],
|
|
1146
1222
|
unique: true
|
|
1147
1223
|
}]
|
|
1224
|
+
},
|
|
1225
|
+
{
|
|
1226
|
+
namespace: HISTORY_NAMESPACE,
|
|
1227
|
+
collection: COLLECTIONS.appliedScales,
|
|
1228
|
+
database: "history",
|
|
1229
|
+
columns: [{
|
|
1230
|
+
name: "id",
|
|
1231
|
+
type: "TEXT",
|
|
1232
|
+
primaryKey: true,
|
|
1233
|
+
notNull: true
|
|
1234
|
+
}, {
|
|
1235
|
+
name: "applied_at",
|
|
1236
|
+
type: "INTEGER",
|
|
1237
|
+
notNull: true
|
|
1238
|
+
}]
|
|
1148
1239
|
}
|
|
1149
1240
|
];
|
|
1150
1241
|
//#endregion
|
|
@@ -1561,7 +1652,98 @@ var HistoryStore = class {
|
|
|
1561
1652
|
filter: { where: { device_id: deviceId } }
|
|
1562
1653
|
});
|
|
1563
1654
|
}
|
|
1655
|
+
/** True when this rescale already finished. A missing row is "not yet". */
|
|
1656
|
+
async scaleApplied(id) {
|
|
1657
|
+
return (await this.door.query.query({
|
|
1658
|
+
namespace: HISTORY_NAMESPACE,
|
|
1659
|
+
collection: COLLECTIONS.appliedScales,
|
|
1660
|
+
filter: {
|
|
1661
|
+
where: { id },
|
|
1662
|
+
limit: 1
|
|
1663
|
+
}
|
|
1664
|
+
})).length > 0;
|
|
1665
|
+
}
|
|
1666
|
+
async markScale(id, at) {
|
|
1667
|
+
await this.door.upsertMany.mutate({
|
|
1668
|
+
namespace: HISTORY_NAMESPACE,
|
|
1669
|
+
collection: COLLECTIONS.appliedScales,
|
|
1670
|
+
conflict: ["id"],
|
|
1671
|
+
records: [{
|
|
1672
|
+
id,
|
|
1673
|
+
data: {
|
|
1674
|
+
id,
|
|
1675
|
+
applied_at: at
|
|
1676
|
+
}
|
|
1677
|
+
}]
|
|
1678
|
+
});
|
|
1679
|
+
}
|
|
1680
|
+
/**
|
|
1681
|
+
* Multiply one series' raw points and rollups that are still in the old
|
|
1682
|
+
* unit. Points already at or above `legacyMax` stay. Returns how many rows
|
|
1683
|
+
* changed.
|
|
1684
|
+
*/
|
|
1685
|
+
async scaleSeries(seriesId, factor, legacyMax) {
|
|
1686
|
+
const raw = await this.scaleRaw(seriesId, factor, legacyMax);
|
|
1687
|
+
let rollups = 0;
|
|
1688
|
+
for (const tier of [
|
|
1689
|
+
"5m",
|
|
1690
|
+
"1h",
|
|
1691
|
+
"1d"
|
|
1692
|
+
]) rollups += await this.scaleRollupTier(tier, seriesId, factor, legacyMax);
|
|
1693
|
+
return raw + rollups;
|
|
1694
|
+
}
|
|
1695
|
+
async scaleRaw(seriesId, factor, legacyMax) {
|
|
1696
|
+
let after = -1;
|
|
1697
|
+
let changed = 0;
|
|
1698
|
+
for (;;) {
|
|
1699
|
+
const rows = await this.readRaw(seriesId, after + 1, Number.MAX_SAFE_INTEGER, READ_PAGE, "asc");
|
|
1700
|
+
if (rows.length === 0) break;
|
|
1701
|
+
const next = rows.flatMap((row) => {
|
|
1702
|
+
const value = scaledMagnitude(row.value, factor, legacyMax);
|
|
1703
|
+
return value === row.value ? [] : [{
|
|
1704
|
+
seriesId,
|
|
1705
|
+
ts: row.ts,
|
|
1706
|
+
value
|
|
1707
|
+
}];
|
|
1708
|
+
});
|
|
1709
|
+
if (next.length > 0) {
|
|
1710
|
+
await this.upsertRaw(next);
|
|
1711
|
+
changed += next.length;
|
|
1712
|
+
}
|
|
1713
|
+
const last = rows[rows.length - 1];
|
|
1714
|
+
if (last === void 0 || rows.length < 5e3) break;
|
|
1715
|
+
after = last.ts;
|
|
1716
|
+
}
|
|
1717
|
+
return changed;
|
|
1718
|
+
}
|
|
1719
|
+
async scaleRollupTier(tier, seriesId, factor, legacyMax) {
|
|
1720
|
+
let after = -1;
|
|
1721
|
+
let changed = 0;
|
|
1722
|
+
for (;;) {
|
|
1723
|
+
const rows = await this.readRollups(tier, seriesId, after + 1, Number.MAX_SAFE_INTEGER, READ_PAGE, "asc");
|
|
1724
|
+
if (rows.length === 0) break;
|
|
1725
|
+
const next = rows.flatMap((row) => rollupIsLegacy(row, legacyMax) ? [scaleRollup(row, factor)] : []);
|
|
1726
|
+
if (next.length > 0) {
|
|
1727
|
+
await this.upsertRollups(tier, next);
|
|
1728
|
+
changed += next.length;
|
|
1729
|
+
}
|
|
1730
|
+
const last = rows[rows.length - 1];
|
|
1731
|
+
if (last === void 0 || rows.length < 5e3) break;
|
|
1732
|
+
after = last.bucketStart;
|
|
1733
|
+
}
|
|
1734
|
+
return changed;
|
|
1735
|
+
}
|
|
1564
1736
|
};
|
|
1737
|
+
function scaleRollup(row, factor) {
|
|
1738
|
+
return {
|
|
1739
|
+
...row,
|
|
1740
|
+
sum: row.sum * factor,
|
|
1741
|
+
min: row.min * factor,
|
|
1742
|
+
max: row.max * factor,
|
|
1743
|
+
last: row.last === null ? null : row.last * factor,
|
|
1744
|
+
twSum: row.twSum === null ? null : row.twSum * factor
|
|
1745
|
+
};
|
|
1746
|
+
}
|
|
1565
1747
|
//#endregion
|
|
1566
1748
|
//#region src/builtins/device-history/rollup/rollup-math.ts
|
|
1567
1749
|
/**
|
|
@@ -2131,7 +2313,8 @@ var HistoryRuntime = class {
|
|
|
2131
2313
|
retention: deps.retention,
|
|
2132
2314
|
catalog,
|
|
2133
2315
|
itemCatalog,
|
|
2134
|
-
readCapSlice: deps.readCapSlice
|
|
2316
|
+
readCapSlice: deps.readCapSlice,
|
|
2317
|
+
readDeviceQuantity: deps.readDeviceQuantity
|
|
2135
2318
|
});
|
|
2136
2319
|
this.departures = new require_retention.DepartureTracker(this.store, this.registry, logger);
|
|
2137
2320
|
this.registry.onRemove((series) => {
|
|
@@ -2167,10 +2350,53 @@ var HistoryRuntime = class {
|
|
|
2167
2350
|
await this.capture.seed();
|
|
2168
2351
|
}
|
|
2169
2352
|
async finishBoot() {
|
|
2353
|
+
await this.applyLegacyScales();
|
|
2170
2354
|
const series = await this.rollup.bootRecompute(this.deps.clock());
|
|
2171
2355
|
this.deps.logger.info("device-history: recent rollup window rebuilt", { meta: { series } });
|
|
2172
2356
|
await this.reconcile();
|
|
2173
2357
|
}
|
|
2358
|
+
/**
|
|
2359
|
+
* PetKit desiccant was stored in days; the quantity base is seconds.
|
|
2360
|
+
* Unraid array counters were stored in GiB; the base is bytes. Both
|
|
2361
|
+
* factors are honest because the unit never varied inside the series.
|
|
2362
|
+
* Weather and numeric-sensor are not rescaled: the unit at sample time
|
|
2363
|
+
* was not stored, so a factor would invent a number (D393).
|
|
2364
|
+
*/
|
|
2365
|
+
async applyLegacyScales() {
|
|
2366
|
+
await this.scaleMatching(DESICCANT_SERIES_KEY, void 0, DAY_TO_SECONDS, DESICCANT_LEGACY_MAX_DAYS, DESICCANT_SCALE_ID);
|
|
2367
|
+
const list = this.deps.listLegacyScales;
|
|
2368
|
+
if (list === void 0) return;
|
|
2369
|
+
let subjects;
|
|
2370
|
+
try {
|
|
2371
|
+
subjects = await list();
|
|
2372
|
+
} catch (err) {
|
|
2373
|
+
this.deps.logger.warn("device-history: legacy scale listing failed — stored points unchanged", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
2374
|
+
return;
|
|
2375
|
+
}
|
|
2376
|
+
for (const subject of subjects) await this.scaleMatching(subject.seriesKey, subject.deviceId, subject.factor, subject.legacyMax, subject.migrationId);
|
|
2377
|
+
}
|
|
2378
|
+
async scaleMatching(key, deviceId, factor, legacyMax, migrationId) {
|
|
2379
|
+
if (await this.store.scaleApplied(migrationId)) return;
|
|
2380
|
+
const subject = deviceId === void 0 ? void 0 : require_retention.subjectIdOf({
|
|
2381
|
+
kind: "device",
|
|
2382
|
+
deviceId
|
|
2383
|
+
});
|
|
2384
|
+
const series = this.registry.all().filter((row) => {
|
|
2385
|
+
if (row.key !== key) return false;
|
|
2386
|
+
return subject === void 0 || row.subject === subject;
|
|
2387
|
+
});
|
|
2388
|
+
let changed = 0;
|
|
2389
|
+
for (const row of series) changed += await this.store.scaleSeries(row.id, factor, legacyMax);
|
|
2390
|
+
await this.store.markScale(migrationId, this.deps.clock());
|
|
2391
|
+
if (changed > 0) this.deps.logger.info("device-history: rescaled a series into its base unit", {
|
|
2392
|
+
...deviceId === void 0 ? {} : { tags: { deviceId } },
|
|
2393
|
+
meta: {
|
|
2394
|
+
migrationId,
|
|
2395
|
+
key,
|
|
2396
|
+
changed
|
|
2397
|
+
}
|
|
2398
|
+
});
|
|
2399
|
+
}
|
|
2174
2400
|
startTimers() {
|
|
2175
2401
|
const every = (ms, run) => {
|
|
2176
2402
|
const timer = setInterval(() => {
|
|
@@ -2448,6 +2674,19 @@ var DeviceHistoryAddon = class extends require_dist.BaseAddon {
|
|
|
2448
2674
|
dayDays: positiveOr(c.dayDays, 0) > 0 ? c.dayDays : null
|
|
2449
2675
|
};
|
|
2450
2676
|
}
|
|
2677
|
+
/** Unraid array counters still stored in GiB. A failed listing throws to the caller. */
|
|
2678
|
+
async legacyScales() {
|
|
2679
|
+
const devices = await this.ctx.api.deviceManager.listAll.query({});
|
|
2680
|
+
const scales = [];
|
|
2681
|
+
for (const device of devices) {
|
|
2682
|
+
if (device.addonId !== "provider-unraid") continue;
|
|
2683
|
+
const entityKey = device.config["entityKey"];
|
|
2684
|
+
if (typeof entityKey !== "string") continue;
|
|
2685
|
+
const scale = unraidInformationScale(device.id, entityKey);
|
|
2686
|
+
if (scale !== null) scales.push(scale);
|
|
2687
|
+
}
|
|
2688
|
+
return scales;
|
|
2689
|
+
}
|
|
2451
2690
|
requireRuntime() {
|
|
2452
2691
|
if (this.runtime === null) throw new Error("device-history is starting — the history store is not open yet");
|
|
2453
2692
|
return this.runtime;
|
|
@@ -2541,6 +2780,11 @@ var DeviceHistoryAddon = class extends require_dist.BaseAddon {
|
|
|
2541
2780
|
deviceId,
|
|
2542
2781
|
capName
|
|
2543
2782
|
}),
|
|
2783
|
+
readDeviceQuantity: async (deviceId) => {
|
|
2784
|
+
const quantity = (await api.deviceManager.getDevice.query({ deviceId }))?.sourceInfo?.quantity;
|
|
2785
|
+
return require_dist.isReadingQuantity(quantity) ? quantity : null;
|
|
2786
|
+
},
|
|
2787
|
+
listLegacyScales: () => this.legacyScales(),
|
|
2544
2788
|
retention: () => this.retention(),
|
|
2545
2789
|
logger: this.ctx.logger,
|
|
2546
2790
|
clock: () => Date.now()
|