@camstack/addon-provider-homeassistant 1.2.78 → 1.2.79
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.js +1 -1
- package/dist/addon.mjs +1 -1
- package/dist/{dist-gv0Gmrm1.js → dist-BI0EGQ5s.js} +42 -0
- package/dist/{dist-CQzCvoCx.mjs → dist-CXuG5e6V.mjs} +42 -0
- package/dist/ha-export/ha-export.addon.js +37 -22
- package/dist/ha-export/ha-export.addon.mjs +37 -22
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_dist = require("./dist-
|
|
2
|
+
const require_dist = require("./dist-BI0EGQ5s.js");
|
|
3
3
|
let node_crypto = require("node:crypto");
|
|
4
4
|
let node_zlib = require("node:zlib");
|
|
5
5
|
//#region src/ha-device-source.ts
|
package/dist/addon.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as presenceCapability, A as controlCapability, At as EventCategory, B as humiditySensorCapability, C as buildAddonRouteProvider, Ct as number, D as colorCapability, Dt as union, E as climateControlCapability, Et as string, F as eventEmitterCapability, G as motionCapability, H as lawnMowerControlCapability, I as fanControlCapability, J as notifierCapability, K as normalizeUnit, L as floodCapability, M as deviceAdoptionCapability, O as connectivityCapability, Ot as unknown, P as enumSensorCapability, Q as prepareNotification, R as gasCapability, S as brokerCapability, St as literal, T as carbonMonoxideCapability, Tt as record, U as lockControlCapability, V as imageCapability, W as mediaPlayerCapability, Y as numericSensorCapability, Z as powerMeterCapability, _ as automationControlCapability, _t as createEvent, at as temperatureSensorCapability, b as binaryCapability, bt as array, ct as valveCapability, d as TargetSchema, dt as weatherCapability, et as pressureSensorCapability, f as accessoriesCapability, ft as errMsg, g as ambientLightSensorCapability, gt as DeviceType, h as alarmPanelCapability, ht as DeviceRole, it as tamperCapability, j as coverCapability, k as contactCapability, kt as url, lt as vibrationCapability, m as airQualitySensorCapability, mt as DeviceFeature, n as BaseDevice, nt as smokeCapability, ot as updateCapability, p as addonRoutesCapability, q as notificationOutputCapability, r as BaseDeviceProvider, rt as switchCapability, s as EnumSensorDateTimeFormatSchema, st as vacuumControlCapability, tt as scriptRunnerCapability, ut as waterHeaterCapability, v as batteryCapability, w as buttonCapability, wt as object, x as brightnessCapability, xt as discriminatedUnion, y as bestLocationMatch, yt as _enum, z as humidifierCapability } from "./dist-
|
|
1
|
+
import { $ as presenceCapability, A as controlCapability, At as EventCategory, B as humiditySensorCapability, C as buildAddonRouteProvider, Ct as number, D as colorCapability, Dt as union, E as climateControlCapability, Et as string, F as eventEmitterCapability, G as motionCapability, H as lawnMowerControlCapability, I as fanControlCapability, J as notifierCapability, K as normalizeUnit, L as floodCapability, M as deviceAdoptionCapability, O as connectivityCapability, Ot as unknown, P as enumSensorCapability, Q as prepareNotification, R as gasCapability, S as brokerCapability, St as literal, T as carbonMonoxideCapability, Tt as record, U as lockControlCapability, V as imageCapability, W as mediaPlayerCapability, Y as numericSensorCapability, Z as powerMeterCapability, _ as automationControlCapability, _t as createEvent, at as temperatureSensorCapability, b as binaryCapability, bt as array, ct as valveCapability, d as TargetSchema, dt as weatherCapability, et as pressureSensorCapability, f as accessoriesCapability, ft as errMsg, g as ambientLightSensorCapability, gt as DeviceType, h as alarmPanelCapability, ht as DeviceRole, it as tamperCapability, j as coverCapability, k as contactCapability, kt as url, lt as vibrationCapability, m as airQualitySensorCapability, mt as DeviceFeature, n as BaseDevice, nt as smokeCapability, ot as updateCapability, p as addonRoutesCapability, q as notificationOutputCapability, r as BaseDeviceProvider, rt as switchCapability, s as EnumSensorDateTimeFormatSchema, st as vacuumControlCapability, tt as scriptRunnerCapability, ut as waterHeaterCapability, v as batteryCapability, w as buttonCapability, wt as object, x as brightnessCapability, xt as discriminatedUnion, y as bestLocationMatch, yt as _enum, z as humidifierCapability } from "./dist-CXuG5e6V.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { brotliCompressSync, deflateSync, gzipSync } from "node:zlib";
|
|
4
4
|
//#region src/ha-device-source.ts
|
|
@@ -13285,6 +13285,24 @@ var deviceProviderCapability = {
|
|
|
13285
13285
|
})
|
|
13286
13286
|
}
|
|
13287
13287
|
};
|
|
13288
|
+
/**
|
|
13289
|
+
* Device Manager capability — hub-side singleton that unifies device persistence,
|
|
13290
|
+
* live registry access, and all management operations into a single tRPC surface.
|
|
13291
|
+
*
|
|
13292
|
+
* Replaces:
|
|
13293
|
+
* - `device-persistence` capability (persistence methods absorbed here)
|
|
13294
|
+
* - `device-management.router.ts` (deleted in Phase 2)
|
|
13295
|
+
* - `device-ops.router.ts` (compat layer — deleted; device-provider ops absorbed here)
|
|
13296
|
+
*
|
|
13297
|
+
* All device provider addons (rtsp, onvif, frigate, …) are hub-local: they may
|
|
13298
|
+
* fork into separate processes but never run on remote cluster agents. Therefore:
|
|
13299
|
+
* - No nodeId routing needed — this is a pure hub singleton.
|
|
13300
|
+
* - The hub's DeviceRegistry is the single source of truth for all live devices.
|
|
13301
|
+
* - No shadow registry or cross-node aggregation required.
|
|
13302
|
+
*
|
|
13303
|
+
* Forked workers register devices back to the hub via `ctx.devices`
|
|
13304
|
+
* (DeviceManagerApi → ctx.api.deviceManager.registerDevice), same as today.
|
|
13305
|
+
*/
|
|
13288
13306
|
/** One child-placement directive on a container's `childLayout`. Structurally
|
|
13289
13307
|
* identical to `ChildLayoutEntry` in `device-management.ts` — the cap wire
|
|
13290
13308
|
* shape for the same field. The child is identified by its re-sync-stable
|
|
@@ -19041,6 +19059,9 @@ var RetrainStatusSchema = _enum([
|
|
|
19041
19059
|
*
|
|
19042
19060
|
* `debug` does NOT pin; it is attention, not durability.
|
|
19043
19061
|
*
|
|
19062
|
+
* `debugNote` is the operator's own words about WHAT should be checked on this
|
|
19063
|
+
* track, and it lives and dies with `debug` — see {@link MAX_TRACK_DEBUG_NOTE_LEN}.
|
|
19064
|
+
*
|
|
19044
19065
|
* `favourited` IS a BOOLEAN pin (durability bit), not a retrain lifecycle.
|
|
19045
19066
|
* A favourited track is skipped by retention the same way `staging` is, but
|
|
19046
19067
|
* it does not enter `none|staging|trained` and has no staging budget.
|
|
@@ -19051,6 +19072,21 @@ var TrackFlagFields = {
|
|
|
19051
19072
|
markForTrain: boolean().optional(),
|
|
19052
19073
|
/** Operator marked this track for diagnostic attention. */
|
|
19053
19074
|
debug: boolean().optional(),
|
|
19075
|
+
/**
|
|
19076
|
+
* What the operator wants CHECKED on this track, in their own words.
|
|
19077
|
+
*
|
|
19078
|
+
* The flag alone says "look at this" and nothing about what for; a debug set
|
|
19079
|
+
* reviewed hours later is a list of tracks with no question attached. Bound
|
|
19080
|
+
* to `debug` on the WRITE side — the body clears it when `debug` goes off,
|
|
19081
|
+
* and refuses it on a track whose debug is off — so a note can never outlive
|
|
19082
|
+
* the attention it belongs to.
|
|
19083
|
+
*
|
|
19084
|
+
* `''` is a real value ("marked, nothing to add"); the ABSENT key means
|
|
19085
|
+
* "leave whatever is stored alone", which is what lets a surface turn debug
|
|
19086
|
+
* on without a note (a cancelled prompt) and what lets it edit the note
|
|
19087
|
+
* without touching the flag.
|
|
19088
|
+
*/
|
|
19089
|
+
debugNote: string().max(500).optional(),
|
|
19054
19090
|
/** Operator favourited this track. Pins it against pruning. */
|
|
19055
19091
|
favourited: boolean().optional()
|
|
19056
19092
|
};
|
|
@@ -19077,6 +19113,12 @@ var TrackFlagsSchema = object({
|
|
|
19077
19113
|
trackId: string(),
|
|
19078
19114
|
markForTrain: boolean(),
|
|
19079
19115
|
debug: boolean(),
|
|
19116
|
+
/** The note as it STANDS after the write — never absent here (a track with no
|
|
19117
|
+
* note reports `''`), for the same reason the booleans are required: a
|
|
19118
|
+
* surface that has just written must be able to render the note it now owns
|
|
19119
|
+
* without a re-fetch, and an absent key would read as "unchanged" on a
|
|
19120
|
+
* screen that has no previous value to keep. */
|
|
19121
|
+
debugNote: string(),
|
|
19080
19122
|
favourited: boolean(),
|
|
19081
19123
|
/** The lifecycle state the boolean was derived from. Required here (unlike on
|
|
19082
19124
|
* a track row) because this shape is only ever produced by the write body,
|
|
@@ -13285,6 +13285,24 @@ var deviceProviderCapability = {
|
|
|
13285
13285
|
})
|
|
13286
13286
|
}
|
|
13287
13287
|
};
|
|
13288
|
+
/**
|
|
13289
|
+
* Device Manager capability — hub-side singleton that unifies device persistence,
|
|
13290
|
+
* live registry access, and all management operations into a single tRPC surface.
|
|
13291
|
+
*
|
|
13292
|
+
* Replaces:
|
|
13293
|
+
* - `device-persistence` capability (persistence methods absorbed here)
|
|
13294
|
+
* - `device-management.router.ts` (deleted in Phase 2)
|
|
13295
|
+
* - `device-ops.router.ts` (compat layer — deleted; device-provider ops absorbed here)
|
|
13296
|
+
*
|
|
13297
|
+
* All device provider addons (rtsp, onvif, frigate, …) are hub-local: they may
|
|
13298
|
+
* fork into separate processes but never run on remote cluster agents. Therefore:
|
|
13299
|
+
* - No nodeId routing needed — this is a pure hub singleton.
|
|
13300
|
+
* - The hub's DeviceRegistry is the single source of truth for all live devices.
|
|
13301
|
+
* - No shadow registry or cross-node aggregation required.
|
|
13302
|
+
*
|
|
13303
|
+
* Forked workers register devices back to the hub via `ctx.devices`
|
|
13304
|
+
* (DeviceManagerApi → ctx.api.deviceManager.registerDevice), same as today.
|
|
13305
|
+
*/
|
|
13288
13306
|
/** One child-placement directive on a container's `childLayout`. Structurally
|
|
13289
13307
|
* identical to `ChildLayoutEntry` in `device-management.ts` — the cap wire
|
|
13290
13308
|
* shape for the same field. The child is identified by its re-sync-stable
|
|
@@ -19041,6 +19059,9 @@ var RetrainStatusSchema = _enum([
|
|
|
19041
19059
|
*
|
|
19042
19060
|
* `debug` does NOT pin; it is attention, not durability.
|
|
19043
19061
|
*
|
|
19062
|
+
* `debugNote` is the operator's own words about WHAT should be checked on this
|
|
19063
|
+
* track, and it lives and dies with `debug` — see {@link MAX_TRACK_DEBUG_NOTE_LEN}.
|
|
19064
|
+
*
|
|
19044
19065
|
* `favourited` IS a BOOLEAN pin (durability bit), not a retrain lifecycle.
|
|
19045
19066
|
* A favourited track is skipped by retention the same way `staging` is, but
|
|
19046
19067
|
* it does not enter `none|staging|trained` and has no staging budget.
|
|
@@ -19051,6 +19072,21 @@ var TrackFlagFields = {
|
|
|
19051
19072
|
markForTrain: boolean().optional(),
|
|
19052
19073
|
/** Operator marked this track for diagnostic attention. */
|
|
19053
19074
|
debug: boolean().optional(),
|
|
19075
|
+
/**
|
|
19076
|
+
* What the operator wants CHECKED on this track, in their own words.
|
|
19077
|
+
*
|
|
19078
|
+
* The flag alone says "look at this" and nothing about what for; a debug set
|
|
19079
|
+
* reviewed hours later is a list of tracks with no question attached. Bound
|
|
19080
|
+
* to `debug` on the WRITE side — the body clears it when `debug` goes off,
|
|
19081
|
+
* and refuses it on a track whose debug is off — so a note can never outlive
|
|
19082
|
+
* the attention it belongs to.
|
|
19083
|
+
*
|
|
19084
|
+
* `''` is a real value ("marked, nothing to add"); the ABSENT key means
|
|
19085
|
+
* "leave whatever is stored alone", which is what lets a surface turn debug
|
|
19086
|
+
* on without a note (a cancelled prompt) and what lets it edit the note
|
|
19087
|
+
* without touching the flag.
|
|
19088
|
+
*/
|
|
19089
|
+
debugNote: string().max(500).optional(),
|
|
19054
19090
|
/** Operator favourited this track. Pins it against pruning. */
|
|
19055
19091
|
favourited: boolean().optional()
|
|
19056
19092
|
};
|
|
@@ -19077,6 +19113,12 @@ var TrackFlagsSchema = object({
|
|
|
19077
19113
|
trackId: string(),
|
|
19078
19114
|
markForTrain: boolean(),
|
|
19079
19115
|
debug: boolean(),
|
|
19116
|
+
/** The note as it STANDS after the write — never absent here (a track with no
|
|
19117
|
+
* note reports `''`), for the same reason the booleans are required: a
|
|
19118
|
+
* surface that has just written must be able to render the note it now owns
|
|
19119
|
+
* without a re-fetch, and an absent key would read as "unchanged" on a
|
|
19120
|
+
* screen that has no previous value to keep. */
|
|
19121
|
+
debugNote: string(),
|
|
19080
19122
|
favourited: boolean(),
|
|
19081
19123
|
/** The lifecycle state the boolean was derived from. Required here (unlike on
|
|
19082
19124
|
* a track row) because this shape is only ever produced by the write body,
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
//#endregion
|
|
6
|
-
const require_dist = require("../dist-
|
|
6
|
+
const require_dist = require("../dist-BI0EGQ5s.js");
|
|
7
7
|
let node_crypto = require("node:crypto");
|
|
8
8
|
//#region src/ha-export/topics.ts
|
|
9
9
|
/**
|
|
@@ -5772,6 +5772,23 @@ function projectSynthetic(input, nowMs) {
|
|
|
5772
5772
|
return values;
|
|
5773
5773
|
}
|
|
5774
5774
|
//#endregion
|
|
5775
|
+
//#region src/ha-export/node-reads.ts
|
|
5776
|
+
var UNREAD = {
|
|
5777
|
+
footageUsedBytes: null,
|
|
5778
|
+
footageFreePercent: null
|
|
5779
|
+
};
|
|
5780
|
+
function footageForNode(nodeId, usage) {
|
|
5781
|
+
if (usage === null || usage.nodeId !== nodeId) return UNREAD;
|
|
5782
|
+
const freePercents = (usage.locations ?? []).filter((loc) => loc.availableBytes !== null && loc.totalBytes !== null && loc.totalBytes > 0).map((loc) => loc.availableBytes / loc.totalBytes * 100);
|
|
5783
|
+
return {
|
|
5784
|
+
footageUsedBytes: usage.totalUsedBytes,
|
|
5785
|
+
footageFreePercent: freePercents.length > 0 ? Math.min(...freePercents) : null
|
|
5786
|
+
};
|
|
5787
|
+
}
|
|
5788
|
+
function shouldReadPackageStatus(node) {
|
|
5789
|
+
return !node.isHub && node.isOnline;
|
|
5790
|
+
}
|
|
5791
|
+
//#endregion
|
|
5775
5792
|
//#region src/ha-export/rule-triggers.ts
|
|
5776
5793
|
function reduceOne(row) {
|
|
5777
5794
|
return {
|
|
@@ -6803,35 +6820,33 @@ var HaExportAddon = class extends require_dist.BaseAddon {
|
|
|
6803
6820
|
}
|
|
6804
6821
|
}
|
|
6805
6822
|
/**
|
|
6806
|
-
* Per-node disk usage (Task D2) and per-AGENT package status (Task D3)
|
|
6807
|
-
*
|
|
6808
|
-
*
|
|
6823
|
+
* Per-node disk usage (Task D2) and per-AGENT package status (Task D3).
|
|
6824
|
+
* `recording` is a singleton cap, so its usage is read ONCE, unpinned, and
|
|
6825
|
+
* attributed to the node the answer names (`footageForNode`); package
|
|
6826
|
+
* status is asked only of online agents (`shouldReadPackageStatus`). A node
|
|
6827
|
+
* that is not read stays `unknown` — unread, never failed.
|
|
6809
6828
|
*/
|
|
6810
6829
|
async buildSyntheticNodes(topology) {
|
|
6830
|
+
const usage = await this.ctx.api.recording.getStorageUsage.query({}).catch((err) => {
|
|
6831
|
+
this.ctx.logger.warn("ha-export: could not read storage usage, the footage entities go unknown", { meta: { error: errMsg(err) } });
|
|
6832
|
+
return null;
|
|
6833
|
+
});
|
|
6811
6834
|
let oldestFootageMs = null;
|
|
6835
|
+
for (const device of usage?.devices ?? []) {
|
|
6836
|
+
const oldest = device.oldestMs;
|
|
6837
|
+
if (oldest === null || oldest === void 0) continue;
|
|
6838
|
+
if (oldestFootageMs === null || oldest < oldestFootageMs) oldestFootageMs = oldest;
|
|
6839
|
+
}
|
|
6812
6840
|
return {
|
|
6813
6841
|
nodes: await Promise.all(topology.map(async (node) => {
|
|
6814
|
-
const
|
|
6815
|
-
|
|
6816
|
-
nodeId: node.id,
|
|
6817
|
-
error: errMsg(err)
|
|
6818
|
-
} });
|
|
6819
|
-
return null;
|
|
6820
|
-
});
|
|
6821
|
-
const freePercents = (disk?.locations ?? []).filter((loc) => loc.availableBytes !== null && loc.totalBytes !== null && loc.totalBytes > 0).map((loc) => loc.availableBytes / loc.totalBytes * 100);
|
|
6822
|
-
const footageFreePercent = freePercents.length > 0 ? Math.min(...freePercents) : null;
|
|
6823
|
-
for (const device of disk?.devices ?? []) {
|
|
6824
|
-
const oldest = device.oldestMs;
|
|
6825
|
-
if (oldest === null || oldest === void 0) continue;
|
|
6826
|
-
if (oldestFootageMs === null || oldest < oldestFootageMs) oldestFootageMs = oldest;
|
|
6827
|
-
}
|
|
6828
|
-
const packageStatus = node.isHub ? null : await this.ctx.api.serverManagement.getServerPackageStatus.query({ nodeId: node.id }).catch((err) => {
|
|
6842
|
+
const footage = footageForNode(node.id, usage);
|
|
6843
|
+
const packageStatus = shouldReadPackageStatus(node) ? await this.ctx.api.serverManagement.getServerPackageStatus.query({ nodeId: node.id }).catch((err) => {
|
|
6829
6844
|
this.ctx.logger.warn("ha-export: could not read package status for an agent node, its update entities go unknown", { meta: {
|
|
6830
6845
|
nodeId: node.id,
|
|
6831
6846
|
error: errMsg(err)
|
|
6832
6847
|
} });
|
|
6833
6848
|
return null;
|
|
6834
|
-
});
|
|
6849
|
+
}) : null;
|
|
6835
6850
|
return {
|
|
6836
6851
|
id: node.id,
|
|
6837
6852
|
name: node.name,
|
|
@@ -6840,8 +6855,8 @@ var HaExportAddon = class extends require_dist.BaseAddon {
|
|
|
6840
6855
|
memoryPercent: node.memoryPercent,
|
|
6841
6856
|
uptime: node.uptime,
|
|
6842
6857
|
isHub: node.isHub,
|
|
6843
|
-
footageUsedBytes:
|
|
6844
|
-
footageFreePercent,
|
|
6858
|
+
footageUsedBytes: footage.footageUsedBytes,
|
|
6859
|
+
footageFreePercent: footage.footageFreePercent,
|
|
6845
6860
|
rootPackageVersion: node.rootPackage?.version ?? null,
|
|
6846
6861
|
updateAvailable: packageStatus?.updateAvailable ?? null
|
|
6847
6862
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { At as EventCategory, C as buildAddonRouteProvider, Et as string, N as deviceExportCapability, X as oauthIntegrationCapability, a as COCO_TO_MACRO, c as FanDirectionSchema, i as CAMERA_SWITCH_ORDER, l as HvacModeSchema, o as CameraSwitchIdSchema, p as addonRoutesCapability, pt as BaseAddon, t as AlarmArmModeSchema, u as MediaPlayerRepeatSchema, vt as nodePin } from "../dist-
|
|
1
|
+
import { At as EventCategory, C as buildAddonRouteProvider, Et as string, N as deviceExportCapability, X as oauthIntegrationCapability, a as COCO_TO_MACRO, c as FanDirectionSchema, i as CAMERA_SWITCH_ORDER, l as HvacModeSchema, o as CameraSwitchIdSchema, p as addonRoutesCapability, pt as BaseAddon, t as AlarmArmModeSchema, u as MediaPlayerRepeatSchema, vt as nodePin } from "../dist-CXuG5e6V.mjs";
|
|
2
2
|
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
3
3
|
//#region src/ha-export/topics.ts
|
|
4
4
|
/**
|
|
@@ -5767,6 +5767,23 @@ function projectSynthetic(input, nowMs) {
|
|
|
5767
5767
|
return values;
|
|
5768
5768
|
}
|
|
5769
5769
|
//#endregion
|
|
5770
|
+
//#region src/ha-export/node-reads.ts
|
|
5771
|
+
var UNREAD = {
|
|
5772
|
+
footageUsedBytes: null,
|
|
5773
|
+
footageFreePercent: null
|
|
5774
|
+
};
|
|
5775
|
+
function footageForNode(nodeId, usage) {
|
|
5776
|
+
if (usage === null || usage.nodeId !== nodeId) return UNREAD;
|
|
5777
|
+
const freePercents = (usage.locations ?? []).filter((loc) => loc.availableBytes !== null && loc.totalBytes !== null && loc.totalBytes > 0).map((loc) => loc.availableBytes / loc.totalBytes * 100);
|
|
5778
|
+
return {
|
|
5779
|
+
footageUsedBytes: usage.totalUsedBytes,
|
|
5780
|
+
footageFreePercent: freePercents.length > 0 ? Math.min(...freePercents) : null
|
|
5781
|
+
};
|
|
5782
|
+
}
|
|
5783
|
+
function shouldReadPackageStatus(node) {
|
|
5784
|
+
return !node.isHub && node.isOnline;
|
|
5785
|
+
}
|
|
5786
|
+
//#endregion
|
|
5770
5787
|
//#region src/ha-export/rule-triggers.ts
|
|
5771
5788
|
function reduceOne(row) {
|
|
5772
5789
|
return {
|
|
@@ -6798,35 +6815,33 @@ var HaExportAddon = class extends BaseAddon {
|
|
|
6798
6815
|
}
|
|
6799
6816
|
}
|
|
6800
6817
|
/**
|
|
6801
|
-
* Per-node disk usage (Task D2) and per-AGENT package status (Task D3)
|
|
6802
|
-
*
|
|
6803
|
-
*
|
|
6818
|
+
* Per-node disk usage (Task D2) and per-AGENT package status (Task D3).
|
|
6819
|
+
* `recording` is a singleton cap, so its usage is read ONCE, unpinned, and
|
|
6820
|
+
* attributed to the node the answer names (`footageForNode`); package
|
|
6821
|
+
* status is asked only of online agents (`shouldReadPackageStatus`). A node
|
|
6822
|
+
* that is not read stays `unknown` — unread, never failed.
|
|
6804
6823
|
*/
|
|
6805
6824
|
async buildSyntheticNodes(topology) {
|
|
6825
|
+
const usage = await this.ctx.api.recording.getStorageUsage.query({}).catch((err) => {
|
|
6826
|
+
this.ctx.logger.warn("ha-export: could not read storage usage, the footage entities go unknown", { meta: { error: errMsg(err) } });
|
|
6827
|
+
return null;
|
|
6828
|
+
});
|
|
6806
6829
|
let oldestFootageMs = null;
|
|
6830
|
+
for (const device of usage?.devices ?? []) {
|
|
6831
|
+
const oldest = device.oldestMs;
|
|
6832
|
+
if (oldest === null || oldest === void 0) continue;
|
|
6833
|
+
if (oldestFootageMs === null || oldest < oldestFootageMs) oldestFootageMs = oldest;
|
|
6834
|
+
}
|
|
6807
6835
|
return {
|
|
6808
6836
|
nodes: await Promise.all(topology.map(async (node) => {
|
|
6809
|
-
const
|
|
6810
|
-
|
|
6811
|
-
nodeId: node.id,
|
|
6812
|
-
error: errMsg(err)
|
|
6813
|
-
} });
|
|
6814
|
-
return null;
|
|
6815
|
-
});
|
|
6816
|
-
const freePercents = (disk?.locations ?? []).filter((loc) => loc.availableBytes !== null && loc.totalBytes !== null && loc.totalBytes > 0).map((loc) => loc.availableBytes / loc.totalBytes * 100);
|
|
6817
|
-
const footageFreePercent = freePercents.length > 0 ? Math.min(...freePercents) : null;
|
|
6818
|
-
for (const device of disk?.devices ?? []) {
|
|
6819
|
-
const oldest = device.oldestMs;
|
|
6820
|
-
if (oldest === null || oldest === void 0) continue;
|
|
6821
|
-
if (oldestFootageMs === null || oldest < oldestFootageMs) oldestFootageMs = oldest;
|
|
6822
|
-
}
|
|
6823
|
-
const packageStatus = node.isHub ? null : await this.ctx.api.serverManagement.getServerPackageStatus.query({ nodeId: node.id }).catch((err) => {
|
|
6837
|
+
const footage = footageForNode(node.id, usage);
|
|
6838
|
+
const packageStatus = shouldReadPackageStatus(node) ? await this.ctx.api.serverManagement.getServerPackageStatus.query({ nodeId: node.id }).catch((err) => {
|
|
6824
6839
|
this.ctx.logger.warn("ha-export: could not read package status for an agent node, its update entities go unknown", { meta: {
|
|
6825
6840
|
nodeId: node.id,
|
|
6826
6841
|
error: errMsg(err)
|
|
6827
6842
|
} });
|
|
6828
6843
|
return null;
|
|
6829
|
-
});
|
|
6844
|
+
}) : null;
|
|
6830
6845
|
return {
|
|
6831
6846
|
id: node.id,
|
|
6832
6847
|
name: node.name,
|
|
@@ -6835,8 +6850,8 @@ var HaExportAddon = class extends BaseAddon {
|
|
|
6835
6850
|
memoryPercent: node.memoryPercent,
|
|
6836
6851
|
uptime: node.uptime,
|
|
6837
6852
|
isHub: node.isHub,
|
|
6838
|
-
footageUsedBytes:
|
|
6839
|
-
footageFreePercent,
|
|
6853
|
+
footageUsedBytes: footage.footageUsedBytes,
|
|
6854
|
+
footageFreePercent: footage.footageFreePercent,
|
|
6840
6855
|
rootPackageVersion: node.rootPackage?.version ?? null,
|
|
6841
6856
|
updateAvailable: packageStatus?.updateAvailable ?? null
|
|
6842
6857
|
};
|