@camstack/addon-post-analysis 1.2.652 → 1.2.653
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/pipeline-analytics/index.js +129 -5
- package/dist/pipeline-analytics/index.mjs +129 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.2.653] - 2026-10-30
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- A node that announced an update is no longer reported offline for 10 minutes; if it comes back nothing is sent, otherwise the offline says it went down while updating
|
|
15
|
+
|
|
10
16
|
## [1.2.652] - 2026-10-29
|
|
11
17
|
|
|
12
18
|
### Changed
|
|
@@ -9063,6 +9063,7 @@ var en_default = {
|
|
|
9063
9063
|
"system.node-offline.body.agent": "Agent {{nodeName}} is offline",
|
|
9064
9064
|
"system.node-offline.body.agent.connection-lost": "Agent {{nodeName}} lost its connection to the hub",
|
|
9065
9065
|
"system.node-offline.body.agent.shutdown": "Agent {{nodeName}} shut down",
|
|
9066
|
+
"system.node-offline.body.agent.updating": "Agent {{nodeName}} went offline while updating and has not come back after {{graceMin}} minutes",
|
|
9066
9067
|
"system.node-inference-unavailable.title": "Node cannot infer — {{nodeId}}",
|
|
9067
9068
|
"system.node-inference-unavailable.body": "Node {{nodeId}} can no longer run inference — every enabled device is unavailable ({{devices}}). It will not receive cameras until one returns.",
|
|
9068
9069
|
"system.addon-crash-loop.title": "Addon crash-loop — {{nodeId}}",
|
|
@@ -9467,6 +9468,7 @@ var it_default = {
|
|
|
9467
9468
|
"system.node-offline.body.agent": "L'agent {{nodeName}} è offline",
|
|
9468
9469
|
"system.node-offline.body.agent.connection-lost": "L'agent {{nodeName}} ha perso la connessione con l'hub",
|
|
9469
9470
|
"system.node-offline.body.agent.shutdown": "L'agent {{nodeName}} si è spento",
|
|
9471
|
+
"system.node-offline.body.agent.updating": "L'agent {{nodeName}} è andato offline durante un aggiornamento e non è tornato dopo {{graceMin}} minuti",
|
|
9470
9472
|
"system.node-inference-unavailable.title": "Nodo senza inferenza — {{nodeId}}",
|
|
9471
9473
|
"system.node-inference-unavailable.body": "Il nodo {{nodeId}} non può più eseguire inferenza — tutti i dispositivi abilitati non sono disponibili ({{devices}}). Non riceverà camere finché uno non torna disponibile.",
|
|
9472
9474
|
"system.addon-crash-loop.title": "Crash-loop addon — {{nodeId}}",
|
|
@@ -90273,13 +90275,17 @@ var DeviceLivenessHoldoff = class {
|
|
|
90273
90275
|
rememberIfAbsent(subject, state) {
|
|
90274
90276
|
if (!this.lastNotified.has(subject)) this.lastNotified.set(subject, state);
|
|
90275
90277
|
}
|
|
90276
|
-
/**
|
|
90277
|
-
|
|
90278
|
+
/**
|
|
90279
|
+
* A real ledger flip. Starts / resets the trailing timer. `delayMs` replaces
|
|
90280
|
+
* the default delay for THIS arm only (a node's planned-update grace).
|
|
90281
|
+
*/
|
|
90282
|
+
arm(subject, incoming, delayMs) {
|
|
90283
|
+
const delay = delayMs ?? this.delayMs;
|
|
90278
90284
|
this.pending.set(subject, incoming);
|
|
90279
90285
|
this.trackDeparture(subject, incoming);
|
|
90280
90286
|
const existing = this.timers.get(subject);
|
|
90281
90287
|
if (existing !== void 0) this.cancel(existing);
|
|
90282
|
-
if (
|
|
90288
|
+
if (delay <= 0) {
|
|
90283
90289
|
this.timers.delete(subject);
|
|
90284
90290
|
this.fire(subject);
|
|
90285
90291
|
return;
|
|
@@ -90287,7 +90293,7 @@ var DeviceLivenessHoldoff = class {
|
|
|
90287
90293
|
const id = this.schedule(() => {
|
|
90288
90294
|
this.timers.delete(subject);
|
|
90289
90295
|
this.fire(subject);
|
|
90290
|
-
},
|
|
90296
|
+
}, delay);
|
|
90291
90297
|
this.timers.set(subject, id);
|
|
90292
90298
|
}
|
|
90293
90299
|
dispose() {
|
|
@@ -92934,6 +92940,71 @@ var NcRuleStore = class NcRuleStore {
|
|
|
92934
92940
|
}
|
|
92935
92941
|
};
|
|
92936
92942
|
//#endregion
|
|
92943
|
+
//#region src/notification-center/planned-update-window.ts
|
|
92944
|
+
/**
|
|
92945
|
+
* A node that ANNOUNCED an update is expected to go offline — the window that
|
|
92946
|
+
* says so lives here.
|
|
92947
|
+
*
|
|
92948
|
+
* `system.restarting` becomes `node-updating` / `node-restarting`; the centre
|
|
92949
|
+
* records the announcement per node (RAM, refreshed by the event, never by a
|
|
92950
|
+
* read — D49). An offline for that node inside {@link PLANNED_UPDATE_OFFLINE_GRACE_MS}
|
|
92951
|
+
* of the announcement is held for the whole window instead of the usual 60 s
|
|
92952
|
+
* hold-off: back in time means no offline notification at all, not back means
|
|
92953
|
+
* one offline that says it happened during an update. A lost announcement
|
|
92954
|
+
* (events may be dropped, D8) simply behaves as before.
|
|
92955
|
+
*/
|
|
92956
|
+
/** How long after an announcement an offline is held, and how long the announcement counts. */
|
|
92957
|
+
var PLANNED_UPDATE_OFFLINE_GRACE_MS = 10 * 6e4;
|
|
92958
|
+
var NC_PLANNED_UPDATE_NODES_MAX = 256;
|
|
92959
|
+
var NcPlannedUpdateWindow = class {
|
|
92960
|
+
graceMs;
|
|
92961
|
+
/** Insertion-ordered: the oldest node is evicted first. */
|
|
92962
|
+
announcedAt = /* @__PURE__ */ new Map();
|
|
92963
|
+
/** When an offline was put on hold, per node. */
|
|
92964
|
+
heldAt = /* @__PURE__ */ new Map();
|
|
92965
|
+
constructor(graceMs = PLANNED_UPDATE_OFFLINE_GRACE_MS) {
|
|
92966
|
+
this.graceMs = graceMs;
|
|
92967
|
+
}
|
|
92968
|
+
get windowMs() {
|
|
92969
|
+
return this.graceMs;
|
|
92970
|
+
}
|
|
92971
|
+
get graceMinutes() {
|
|
92972
|
+
return Math.round(this.graceMs / 6e4);
|
|
92973
|
+
}
|
|
92974
|
+
/** Feed every system subject the intake accepted; only the two announcements are kept. */
|
|
92975
|
+
observe(system, atMs) {
|
|
92976
|
+
if (system.kind !== "node-updating" && system.kind !== "node-restarting") return;
|
|
92977
|
+
const nodeId = system.nodeId;
|
|
92978
|
+
if (nodeId === void 0) return;
|
|
92979
|
+
this.announcedAt.delete(nodeId);
|
|
92980
|
+
this.announcedAt.set(nodeId, atMs);
|
|
92981
|
+
while (this.announcedAt.size > NC_PLANNED_UPDATE_NODES_MAX) {
|
|
92982
|
+
const oldest = this.announcedAt.keys().next();
|
|
92983
|
+
if (oldest.done === true) break;
|
|
92984
|
+
this.announcedAt.delete(oldest.value);
|
|
92985
|
+
}
|
|
92986
|
+
}
|
|
92987
|
+
/** True when the node announced an update no longer than the window ago. */
|
|
92988
|
+
isPlanned(nodeId, atMs) {
|
|
92989
|
+
const at = this.announcedAt.get(nodeId);
|
|
92990
|
+
return at !== void 0 && atMs - at <= this.graceMs;
|
|
92991
|
+
}
|
|
92992
|
+
/** An offline was put on hold for this node. */
|
|
92993
|
+
hold(nodeId, atMs) {
|
|
92994
|
+
this.heldAt.set(nodeId, atMs);
|
|
92995
|
+
}
|
|
92996
|
+
/**
|
|
92997
|
+
* The node is back: seconds the held offline lasted, or `null` when no offline
|
|
92998
|
+
* was held, or its window already ran out (the offline was sent).
|
|
92999
|
+
*/
|
|
93000
|
+
release(nodeId, atMs) {
|
|
93001
|
+
const at = this.heldAt.get(nodeId);
|
|
93002
|
+
if (at === void 0) return null;
|
|
93003
|
+
this.heldAt.delete(nodeId);
|
|
93004
|
+
return atMs - at < this.graceMs ? Math.round((atMs - at) / 1e3) : null;
|
|
93005
|
+
}
|
|
93006
|
+
};
|
|
93007
|
+
//#endregion
|
|
92937
93008
|
//#region src/notification-center/restart-supersede.ts
|
|
92938
93009
|
/** How many landings are remembered — one per node per update, so a fleet's worth. */
|
|
92939
93010
|
var NC_UPDATE_LANDINGS_MAX = 256;
|
|
@@ -101894,6 +101965,7 @@ function onSystemEvent(host, event) {
|
|
|
101894
101965
|
const system = incoming.subject.systemEvent;
|
|
101895
101966
|
if (system !== void 0) host.stateSummary.observeSystem(system, host.now());
|
|
101896
101967
|
if (system !== void 0) host.updateLandings.observe(system, host.now());
|
|
101968
|
+
if (system !== void 0) host.plannedUpdates.observe(system, host.now());
|
|
101897
101969
|
const observation = system !== void 0 ? ledgeredLiveness(system) : null;
|
|
101898
101970
|
if (observation !== null) {
|
|
101899
101971
|
const previous = host.liveness.stateOf(observation.subject);
|
|
@@ -101920,7 +101992,11 @@ function onSystemEvent(host, event) {
|
|
|
101920
101992
|
});
|
|
101921
101993
|
return;
|
|
101922
101994
|
}
|
|
101923
|
-
if (
|
|
101995
|
+
if (isNodeLivenessKind(observation.kind) && system !== void 0) {
|
|
101996
|
+
armNodeLiveness(host, holdoff, observation.subject, incoming, system);
|
|
101997
|
+
return;
|
|
101998
|
+
}
|
|
101999
|
+
if (isDeviceLivenessKind(observation.kind)) {
|
|
101924
102000
|
holdoff.arm(observation.subject, incoming);
|
|
101925
102001
|
return;
|
|
101926
102002
|
}
|
|
@@ -101931,6 +102007,50 @@ function onSystemEvent(host, event) {
|
|
|
101931
102007
|
host.consumeEvent(incoming);
|
|
101932
102008
|
}
|
|
101933
102009
|
/**
|
|
102010
|
+
* Arm a node liveness flip. An OFFLINE of a node that announced an update is
|
|
102011
|
+
* held for the whole planned-update window and worded as such if it is still
|
|
102012
|
+
* sent; the node's return inside the window is logged and sends nothing (the
|
|
102013
|
+
* hold-off sees the state bounce back to the one last notified).
|
|
102014
|
+
*/
|
|
102015
|
+
function armNodeLiveness(host, holdoff, subject, incoming, system) {
|
|
102016
|
+
const nodeId = system.nodeId;
|
|
102017
|
+
const now = host.now();
|
|
102018
|
+
if (nodeId === void 0) {
|
|
102019
|
+
holdoff.arm(subject, incoming);
|
|
102020
|
+
return;
|
|
102021
|
+
}
|
|
102022
|
+
const window = host.plannedUpdates;
|
|
102023
|
+
if (system.kind === "node-offline" && window.isPlanned(nodeId, now)) {
|
|
102024
|
+
window.hold(nodeId, now);
|
|
102025
|
+
holdoff.arm(subject, withPlannedUpdateWording(incoming, system, window.graceMinutes), window.windowMs);
|
|
102026
|
+
return;
|
|
102027
|
+
}
|
|
102028
|
+
if (system.kind === "node-online") {
|
|
102029
|
+
const backAfterSec = window.release(nodeId, now);
|
|
102030
|
+
if (backAfterSec !== null) host.logger.info(`node ${nodeId}: offline suppressed: planned update, back after ${backAfterSec}s`, { meta: {
|
|
102031
|
+
nodeId,
|
|
102032
|
+
backAfterSec
|
|
102033
|
+
} });
|
|
102034
|
+
}
|
|
102035
|
+
holdoff.arm(subject, incoming);
|
|
102036
|
+
}
|
|
102037
|
+
function withPlannedUpdateWording(incoming, system, graceMin) {
|
|
102038
|
+
return {
|
|
102039
|
+
...incoming,
|
|
102040
|
+
subject: {
|
|
102041
|
+
...incoming.subject,
|
|
102042
|
+
systemEvent: {
|
|
102043
|
+
...system,
|
|
102044
|
+
bodyKey: "system.node-offline.body.agent.updating",
|
|
102045
|
+
textParams: {
|
|
102046
|
+
...system.textParams,
|
|
102047
|
+
graceMin: String(graceMin)
|
|
102048
|
+
}
|
|
102049
|
+
}
|
|
102050
|
+
}
|
|
102051
|
+
};
|
|
102052
|
+
}
|
|
102053
|
+
/**
|
|
101934
102054
|
* One edge of an alert episode, from the bus or from the reconcile. The
|
|
101935
102055
|
* ledger decides whether it is news; only news reaches the rules.
|
|
101936
102056
|
*/
|
|
@@ -105749,6 +105869,7 @@ var NotificationCenter = class {
|
|
|
105749
105869
|
stateSummary;
|
|
105750
105870
|
/** Every `server-updated` heard, so a stale `node-updating` is not sent after it (D723). */
|
|
105751
105871
|
updateLandings = new NcUpdateLandings();
|
|
105872
|
+
plannedUpdates = new NcPlannedUpdateWindow();
|
|
105752
105873
|
/** States the `deviceState` rule gate reads. Refreshed on the reload tick;
|
|
105753
105874
|
* read with no I/O on the persist hook. */
|
|
105754
105875
|
deviceStates;
|
|
@@ -107141,6 +107262,9 @@ var NotificationCenter = class {
|
|
|
107141
107262
|
get timelapseRules() {
|
|
107142
107263
|
return self.timelapseRules;
|
|
107143
107264
|
},
|
|
107265
|
+
get plannedUpdates() {
|
|
107266
|
+
return self.plannedUpdates;
|
|
107267
|
+
},
|
|
107144
107268
|
get updateLandings() {
|
|
107145
107269
|
return self.updateLandings;
|
|
107146
107270
|
},
|
|
@@ -9055,6 +9055,7 @@ var en_default = {
|
|
|
9055
9055
|
"system.node-offline.body.agent": "Agent {{nodeName}} is offline",
|
|
9056
9056
|
"system.node-offline.body.agent.connection-lost": "Agent {{nodeName}} lost its connection to the hub",
|
|
9057
9057
|
"system.node-offline.body.agent.shutdown": "Agent {{nodeName}} shut down",
|
|
9058
|
+
"system.node-offline.body.agent.updating": "Agent {{nodeName}} went offline while updating and has not come back after {{graceMin}} minutes",
|
|
9058
9059
|
"system.node-inference-unavailable.title": "Node cannot infer — {{nodeId}}",
|
|
9059
9060
|
"system.node-inference-unavailable.body": "Node {{nodeId}} can no longer run inference — every enabled device is unavailable ({{devices}}). It will not receive cameras until one returns.",
|
|
9060
9061
|
"system.addon-crash-loop.title": "Addon crash-loop — {{nodeId}}",
|
|
@@ -9459,6 +9460,7 @@ var it_default = {
|
|
|
9459
9460
|
"system.node-offline.body.agent": "L'agent {{nodeName}} è offline",
|
|
9460
9461
|
"system.node-offline.body.agent.connection-lost": "L'agent {{nodeName}} ha perso la connessione con l'hub",
|
|
9461
9462
|
"system.node-offline.body.agent.shutdown": "L'agent {{nodeName}} si è spento",
|
|
9463
|
+
"system.node-offline.body.agent.updating": "L'agent {{nodeName}} è andato offline durante un aggiornamento e non è tornato dopo {{graceMin}} minuti",
|
|
9462
9464
|
"system.node-inference-unavailable.title": "Nodo senza inferenza — {{nodeId}}",
|
|
9463
9465
|
"system.node-inference-unavailable.body": "Il nodo {{nodeId}} non può più eseguire inferenza — tutti i dispositivi abilitati non sono disponibili ({{devices}}). Non riceverà camere finché uno non torna disponibile.",
|
|
9464
9466
|
"system.addon-crash-loop.title": "Crash-loop addon — {{nodeId}}",
|
|
@@ -90178,13 +90180,17 @@ var DeviceLivenessHoldoff = class {
|
|
|
90178
90180
|
rememberIfAbsent(subject, state) {
|
|
90179
90181
|
if (!this.lastNotified.has(subject)) this.lastNotified.set(subject, state);
|
|
90180
90182
|
}
|
|
90181
|
-
/**
|
|
90182
|
-
|
|
90183
|
+
/**
|
|
90184
|
+
* A real ledger flip. Starts / resets the trailing timer. `delayMs` replaces
|
|
90185
|
+
* the default delay for THIS arm only (a node's planned-update grace).
|
|
90186
|
+
*/
|
|
90187
|
+
arm(subject, incoming, delayMs) {
|
|
90188
|
+
const delay = delayMs ?? this.delayMs;
|
|
90183
90189
|
this.pending.set(subject, incoming);
|
|
90184
90190
|
this.trackDeparture(subject, incoming);
|
|
90185
90191
|
const existing = this.timers.get(subject);
|
|
90186
90192
|
if (existing !== void 0) this.cancel(existing);
|
|
90187
|
-
if (
|
|
90193
|
+
if (delay <= 0) {
|
|
90188
90194
|
this.timers.delete(subject);
|
|
90189
90195
|
this.fire(subject);
|
|
90190
90196
|
return;
|
|
@@ -90192,7 +90198,7 @@ var DeviceLivenessHoldoff = class {
|
|
|
90192
90198
|
const id = this.schedule(() => {
|
|
90193
90199
|
this.timers.delete(subject);
|
|
90194
90200
|
this.fire(subject);
|
|
90195
|
-
},
|
|
90201
|
+
}, delay);
|
|
90196
90202
|
this.timers.set(subject, id);
|
|
90197
90203
|
}
|
|
90198
90204
|
dispose() {
|
|
@@ -92839,6 +92845,71 @@ var NcRuleStore = class NcRuleStore {
|
|
|
92839
92845
|
}
|
|
92840
92846
|
};
|
|
92841
92847
|
//#endregion
|
|
92848
|
+
//#region src/notification-center/planned-update-window.ts
|
|
92849
|
+
/**
|
|
92850
|
+
* A node that ANNOUNCED an update is expected to go offline — the window that
|
|
92851
|
+
* says so lives here.
|
|
92852
|
+
*
|
|
92853
|
+
* `system.restarting` becomes `node-updating` / `node-restarting`; the centre
|
|
92854
|
+
* records the announcement per node (RAM, refreshed by the event, never by a
|
|
92855
|
+
* read — D49). An offline for that node inside {@link PLANNED_UPDATE_OFFLINE_GRACE_MS}
|
|
92856
|
+
* of the announcement is held for the whole window instead of the usual 60 s
|
|
92857
|
+
* hold-off: back in time means no offline notification at all, not back means
|
|
92858
|
+
* one offline that says it happened during an update. A lost announcement
|
|
92859
|
+
* (events may be dropped, D8) simply behaves as before.
|
|
92860
|
+
*/
|
|
92861
|
+
/** How long after an announcement an offline is held, and how long the announcement counts. */
|
|
92862
|
+
var PLANNED_UPDATE_OFFLINE_GRACE_MS = 10 * 6e4;
|
|
92863
|
+
var NC_PLANNED_UPDATE_NODES_MAX = 256;
|
|
92864
|
+
var NcPlannedUpdateWindow = class {
|
|
92865
|
+
graceMs;
|
|
92866
|
+
/** Insertion-ordered: the oldest node is evicted first. */
|
|
92867
|
+
announcedAt = /* @__PURE__ */ new Map();
|
|
92868
|
+
/** When an offline was put on hold, per node. */
|
|
92869
|
+
heldAt = /* @__PURE__ */ new Map();
|
|
92870
|
+
constructor(graceMs = PLANNED_UPDATE_OFFLINE_GRACE_MS) {
|
|
92871
|
+
this.graceMs = graceMs;
|
|
92872
|
+
}
|
|
92873
|
+
get windowMs() {
|
|
92874
|
+
return this.graceMs;
|
|
92875
|
+
}
|
|
92876
|
+
get graceMinutes() {
|
|
92877
|
+
return Math.round(this.graceMs / 6e4);
|
|
92878
|
+
}
|
|
92879
|
+
/** Feed every system subject the intake accepted; only the two announcements are kept. */
|
|
92880
|
+
observe(system, atMs) {
|
|
92881
|
+
if (system.kind !== "node-updating" && system.kind !== "node-restarting") return;
|
|
92882
|
+
const nodeId = system.nodeId;
|
|
92883
|
+
if (nodeId === void 0) return;
|
|
92884
|
+
this.announcedAt.delete(nodeId);
|
|
92885
|
+
this.announcedAt.set(nodeId, atMs);
|
|
92886
|
+
while (this.announcedAt.size > NC_PLANNED_UPDATE_NODES_MAX) {
|
|
92887
|
+
const oldest = this.announcedAt.keys().next();
|
|
92888
|
+
if (oldest.done === true) break;
|
|
92889
|
+
this.announcedAt.delete(oldest.value);
|
|
92890
|
+
}
|
|
92891
|
+
}
|
|
92892
|
+
/** True when the node announced an update no longer than the window ago. */
|
|
92893
|
+
isPlanned(nodeId, atMs) {
|
|
92894
|
+
const at = this.announcedAt.get(nodeId);
|
|
92895
|
+
return at !== void 0 && atMs - at <= this.graceMs;
|
|
92896
|
+
}
|
|
92897
|
+
/** An offline was put on hold for this node. */
|
|
92898
|
+
hold(nodeId, atMs) {
|
|
92899
|
+
this.heldAt.set(nodeId, atMs);
|
|
92900
|
+
}
|
|
92901
|
+
/**
|
|
92902
|
+
* The node is back: seconds the held offline lasted, or `null` when no offline
|
|
92903
|
+
* was held, or its window already ran out (the offline was sent).
|
|
92904
|
+
*/
|
|
92905
|
+
release(nodeId, atMs) {
|
|
92906
|
+
const at = this.heldAt.get(nodeId);
|
|
92907
|
+
if (at === void 0) return null;
|
|
92908
|
+
this.heldAt.delete(nodeId);
|
|
92909
|
+
return atMs - at < this.graceMs ? Math.round((atMs - at) / 1e3) : null;
|
|
92910
|
+
}
|
|
92911
|
+
};
|
|
92912
|
+
//#endregion
|
|
92842
92913
|
//#region src/notification-center/restart-supersede.ts
|
|
92843
92914
|
/** How many landings are remembered — one per node per update, so a fleet's worth. */
|
|
92844
92915
|
var NC_UPDATE_LANDINGS_MAX = 256;
|
|
@@ -101799,6 +101870,7 @@ function onSystemEvent(host, event) {
|
|
|
101799
101870
|
const system = incoming.subject.systemEvent;
|
|
101800
101871
|
if (system !== void 0) host.stateSummary.observeSystem(system, host.now());
|
|
101801
101872
|
if (system !== void 0) host.updateLandings.observe(system, host.now());
|
|
101873
|
+
if (system !== void 0) host.plannedUpdates.observe(system, host.now());
|
|
101802
101874
|
const observation = system !== void 0 ? ledgeredLiveness(system) : null;
|
|
101803
101875
|
if (observation !== null) {
|
|
101804
101876
|
const previous = host.liveness.stateOf(observation.subject);
|
|
@@ -101825,7 +101897,11 @@ function onSystemEvent(host, event) {
|
|
|
101825
101897
|
});
|
|
101826
101898
|
return;
|
|
101827
101899
|
}
|
|
101828
|
-
if (
|
|
101900
|
+
if (isNodeLivenessKind(observation.kind) && system !== void 0) {
|
|
101901
|
+
armNodeLiveness(host, holdoff, observation.subject, incoming, system);
|
|
101902
|
+
return;
|
|
101903
|
+
}
|
|
101904
|
+
if (isDeviceLivenessKind(observation.kind)) {
|
|
101829
101905
|
holdoff.arm(observation.subject, incoming);
|
|
101830
101906
|
return;
|
|
101831
101907
|
}
|
|
@@ -101836,6 +101912,50 @@ function onSystemEvent(host, event) {
|
|
|
101836
101912
|
host.consumeEvent(incoming);
|
|
101837
101913
|
}
|
|
101838
101914
|
/**
|
|
101915
|
+
* Arm a node liveness flip. An OFFLINE of a node that announced an update is
|
|
101916
|
+
* held for the whole planned-update window and worded as such if it is still
|
|
101917
|
+
* sent; the node's return inside the window is logged and sends nothing (the
|
|
101918
|
+
* hold-off sees the state bounce back to the one last notified).
|
|
101919
|
+
*/
|
|
101920
|
+
function armNodeLiveness(host, holdoff, subject, incoming, system) {
|
|
101921
|
+
const nodeId = system.nodeId;
|
|
101922
|
+
const now = host.now();
|
|
101923
|
+
if (nodeId === void 0) {
|
|
101924
|
+
holdoff.arm(subject, incoming);
|
|
101925
|
+
return;
|
|
101926
|
+
}
|
|
101927
|
+
const window = host.plannedUpdates;
|
|
101928
|
+
if (system.kind === "node-offline" && window.isPlanned(nodeId, now)) {
|
|
101929
|
+
window.hold(nodeId, now);
|
|
101930
|
+
holdoff.arm(subject, withPlannedUpdateWording(incoming, system, window.graceMinutes), window.windowMs);
|
|
101931
|
+
return;
|
|
101932
|
+
}
|
|
101933
|
+
if (system.kind === "node-online") {
|
|
101934
|
+
const backAfterSec = window.release(nodeId, now);
|
|
101935
|
+
if (backAfterSec !== null) host.logger.info(`node ${nodeId}: offline suppressed: planned update, back after ${backAfterSec}s`, { meta: {
|
|
101936
|
+
nodeId,
|
|
101937
|
+
backAfterSec
|
|
101938
|
+
} });
|
|
101939
|
+
}
|
|
101940
|
+
holdoff.arm(subject, incoming);
|
|
101941
|
+
}
|
|
101942
|
+
function withPlannedUpdateWording(incoming, system, graceMin) {
|
|
101943
|
+
return {
|
|
101944
|
+
...incoming,
|
|
101945
|
+
subject: {
|
|
101946
|
+
...incoming.subject,
|
|
101947
|
+
systemEvent: {
|
|
101948
|
+
...system,
|
|
101949
|
+
bodyKey: "system.node-offline.body.agent.updating",
|
|
101950
|
+
textParams: {
|
|
101951
|
+
...system.textParams,
|
|
101952
|
+
graceMin: String(graceMin)
|
|
101953
|
+
}
|
|
101954
|
+
}
|
|
101955
|
+
}
|
|
101956
|
+
};
|
|
101957
|
+
}
|
|
101958
|
+
/**
|
|
101839
101959
|
* One edge of an alert episode, from the bus or from the reconcile. The
|
|
101840
101960
|
* ledger decides whether it is news; only news reaches the rules.
|
|
101841
101961
|
*/
|
|
@@ -105654,6 +105774,7 @@ var NotificationCenter = class {
|
|
|
105654
105774
|
stateSummary;
|
|
105655
105775
|
/** Every `server-updated` heard, so a stale `node-updating` is not sent after it (D723). */
|
|
105656
105776
|
updateLandings = new NcUpdateLandings();
|
|
105777
|
+
plannedUpdates = new NcPlannedUpdateWindow();
|
|
105657
105778
|
/** States the `deviceState` rule gate reads. Refreshed on the reload tick;
|
|
105658
105779
|
* read with no I/O on the persist hook. */
|
|
105659
105780
|
deviceStates;
|
|
@@ -107046,6 +107167,9 @@ var NotificationCenter = class {
|
|
|
107046
107167
|
get timelapseRules() {
|
|
107047
107168
|
return self.timelapseRules;
|
|
107048
107169
|
},
|
|
107170
|
+
get plannedUpdates() {
|
|
107171
|
+
return self.plannedUpdates;
|
|
107172
|
+
},
|
|
107049
107173
|
get updateLandings() {
|
|
107050
107174
|
return self.updateLandings;
|
|
107051
107175
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-post-analysis",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.653",
|
|
4
4
|
"description": "Post-Analysis bundle — enrichment, embedding-encoder, pipeline-analytics. Multi-entry npm package shipping addons that consume pipeline output.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|