@camstack/addon-post-analysis 1.2.277 → 1.2.278
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/{dist-MPbaDp6L.js → dist-BUtk8EU2.js} +105 -4
- package/dist/{dist-D8G7jV1C.mjs → dist-D0jvZ8dq.mjs} +105 -4
- package/dist/embedding-encoder/index.js +1 -1
- package/dist/embedding-encoder/index.mjs +1 -1
- package/dist/pipeline-analytics/_stub.js +2 -2
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-CHNFeWfB.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-CkyY7n6X.mjs} +2 -2
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BwQ85CFd.mjs +26 -0
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-B62fofgN.mjs +26 -0
- package/dist/pipeline-analytics/{hostInit-CN-6SOYG.mjs → hostInit-nmySmpNF.mjs} +2 -2
- package/dist/pipeline-analytics/index.js +310 -120
- package/dist/pipeline-analytics/index.mjs +310 -120
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-B7oKeWXX.mjs +0 -26
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BZetaopl.mjs +0 -26
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as RECORDING_SOURCE_CAMSTACK_ADDON, $t as CamProfileSchema, At as isScheduleActive, B as NcRuleUpdateInputSchema, Bt as readDeviceStateFrom, C as MAX_BIRTH_DECISION_RECORDS, Ct as faceGalleryCapability, D as NC_ALARM_SYSTEM_EVENT_KINDS, Dt as isEventOwnerType, E as MediaFileKindEnum, Et as isDetectionMacroClass, F as NcConditionDescriptorSchema, Ft as occupancyScope, G as NcSystemEventKindSchema, Gt as storageOccupancyCapability, H as NcSnoozeInputSchema, Ht as resolveLocationMode, I as NcRuleInputSchema, J as NcTemplatePreviewSchema, Jt as templateVarsFor, K as NcTaxonomySchema, Kt as subKindsOf, L as NcRulePatchSchema, Lt as pickClusterStepModels, M as NC_TEMPLATE_VARS, Mt as kebabToCamel, N as NcAlarmConfigSchema, Nt as mayWriteToLocation, O as NC_CONDITION_CATALOG, Ot as isKnownTemplateVar, P as NcAlarmSettingsPatchSchema, Pt as notificationRulesCapability, Q as RECORDING_EXPORT_MAX_READ_BYTES, Qt as BaseAddon, R as NcRuleSchema, Rt as pipelineAnalyticsCapability, S as MAX_ARCHIVED_DEBUG_NOTES, St as evictionPolicyOfLocation, T as MOTION_CLOSE_AFTER_MS, U as NcSnoozeSchema, V as NcScheduleSchema, Vt as readTimelapseGeneratedAt, W as NcSnoozeSuppressedSchema, Wt as sceneMonitorCapability, X as OpsLogEntrySchema, Xt as zoneAnalyticsCapability, Y as NcTemplateVarDescriptorSchema, Yt as vectorDimFromBase64, Zt as errMsg$1, _ as FIRST_LEVEL_MACRO_CLASSES, _n as string, _t as cosineSimilarity$1, a as BirthDecisionRecordSchema, an as isDeviceScopedCap, at as SceneMonitorSchema, b as LabelAttributionSchema, bt as encodeVectorBase64, c as CoverStateSchema, cn as _enum, ct as TimelapseRulePatchSchema, dn as discriminatedUnion, dt as addonWidgetsSourceCapability, en as DeviceType, et as RetrainStatusSchema, f as DETECTION_MACRO_CLASSES, fn as literal, ft as alarmPanelCapability, g as EVENT_OWNER_TYPES, gn as record, gt as buildEventKindDescriptor, h as EVENT_KIND_BY_CAP, hn as partialRecord, ht as audioModeOf, i as BaseDevice, in as hydrateSchema, it as SCENE_DIVERGED, j as NC_TAXONOMY, jt as isSourceCap, k as NC_DEFAULT_SNOOZE_MINUTES, kt as isMediaOwnerType, l as DEFAULT_EVENT_COLOR, ln as array, lt as TimelapseRuleSchema, m as DeclaredDevices, mn as object, mt as audioMetricsCapability, n as AlarmArmModeSchema, nn as customAction, nt as SCENE_DEFAULT_ANCHOR_THRESHOLD, o as CLUSTER_MODEL_SCOPED_STEPS, on as nodePin, ot as TIMELAPSE_DENSE_FLOOR_SEC, pn as number, pt as assertTimelapseCadences, q as NcTemplatePreviewInputSchema, qt as systemEventFilterApplies, r as ArchivedDebugNoteSchema, rn as defineCustomActions, rt as SCENE_DEFAULT_UNCOVERED_POLICY, s as COCO_TO_MACRO, sn as sleep$1, st as TimelapseRuleInputSchema, t as AUDIO_MACRO_LABELS, tn as createEvent, un as boolean, ut as TrackSourceSchema, v as FULL_IMAGE_BBOX, vn as unknown, vt as deriveRecordingMode, wt as failureContributionCapability, x as LockStateSchema, xt as evaluateSensorEdge, y as FailureCounters, yn as EventCategory, z as NcRuleTargetSchema, zt as plateGalleryCapability } from "../dist-
|
|
1
|
+
import { $ as RECORDING_SOURCE_CAMSTACK_ADDON, $t as CamProfileSchema, At as isScheduleActive, B as NcRuleUpdateInputSchema, Bt as readDeviceStateFrom, C as MAX_BIRTH_DECISION_RECORDS, Ct as faceGalleryCapability, D as NC_ALARM_SYSTEM_EVENT_KINDS, Dt as isEventOwnerType, E as MediaFileKindEnum, Et as isDetectionMacroClass, F as NcConditionDescriptorSchema, Ft as occupancyScope, G as NcSystemEventKindSchema, Gt as storageOccupancyCapability, H as NcSnoozeInputSchema, Ht as resolveLocationMode, I as NcRuleInputSchema, J as NcTemplatePreviewSchema, Jt as templateVarsFor, K as NcTaxonomySchema, Kt as subKindsOf, L as NcRulePatchSchema, Lt as pickClusterStepModels, M as NC_TEMPLATE_VARS, Mt as kebabToCamel, N as NcAlarmConfigSchema, Nt as mayWriteToLocation, O as NC_CONDITION_CATALOG, Ot as isKnownTemplateVar, P as NcAlarmSettingsPatchSchema, Pt as notificationRulesCapability, Q as RECORDING_EXPORT_MAX_READ_BYTES, Qt as BaseAddon, R as NcRuleSchema, Rt as pipelineAnalyticsCapability, S as MAX_ARCHIVED_DEBUG_NOTES, St as evictionPolicyOfLocation, T as MOTION_CLOSE_AFTER_MS, U as NcSnoozeSchema, V as NcScheduleSchema, Vt as readTimelapseGeneratedAt, W as NcSnoozeSuppressedSchema, Wt as sceneMonitorCapability, X as OpsLogEntrySchema, Xt as zoneAnalyticsCapability, Y as NcTemplateVarDescriptorSchema, Yt as vectorDimFromBase64, Zt as errMsg$1, _ as FIRST_LEVEL_MACRO_CLASSES, _n as string, _t as cosineSimilarity$1, a as BirthDecisionRecordSchema, an as isDeviceScopedCap, at as SceneMonitorSchema, b as LabelAttributionSchema, bt as encodeVectorBase64, c as CoverStateSchema, cn as _enum, ct as TimelapseRulePatchSchema, dn as discriminatedUnion, dt as addonWidgetsSourceCapability, en as DeviceType, et as RetrainStatusSchema, f as DETECTION_MACRO_CLASSES, fn as literal, ft as alarmPanelCapability, g as EVENT_OWNER_TYPES, gn as record, gt as buildEventKindDescriptor, h as EVENT_KIND_BY_CAP, hn as partialRecord, ht as audioModeOf, i as BaseDevice, in as hydrateSchema, it as SCENE_DIVERGED, j as NC_TAXONOMY, jt as isSourceCap, k as NC_DEFAULT_SNOOZE_MINUTES, kt as isMediaOwnerType, l as DEFAULT_EVENT_COLOR, ln as array, lt as TimelapseRuleSchema, m as DeclaredDevices, mn as object, mt as audioMetricsCapability, n as AlarmArmModeSchema, nn as customAction, nt as SCENE_DEFAULT_ANCHOR_THRESHOLD, o as CLUSTER_MODEL_SCOPED_STEPS, on as nodePin, ot as TIMELAPSE_DENSE_FLOOR_SEC, pn as number, pt as assertTimelapseCadences, q as NcTemplatePreviewInputSchema, qt as systemEventFilterApplies, r as ArchivedDebugNoteSchema, rn as defineCustomActions, rt as SCENE_DEFAULT_UNCOVERED_POLICY, s as COCO_TO_MACRO, sn as sleep$1, st as TimelapseRuleInputSchema, t as AUDIO_MACRO_LABELS, tn as createEvent, un as boolean, ut as TrackSourceSchema, v as FULL_IMAGE_BBOX, vn as unknown, vt as deriveRecordingMode, wt as failureContributionCapability, x as LockStateSchema, xt as evaluateSensorEdge, y as FailureCounters, yn as EventCategory, z as NcRuleTargetSchema, zt as plateGalleryCapability } from "../dist-D0jvZ8dq.mjs";
|
|
2
2
|
import { t as __exportAll } from "../embedding-encoder/index.mjs";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import { promises } from "node:fs";
|
|
@@ -8212,6 +8212,99 @@ var NcAlarmLiveReadLog = class {
|
|
|
8212
8212
|
}
|
|
8213
8213
|
};
|
|
8214
8214
|
//#endregion
|
|
8215
|
+
//#region src/notification-center/alerts/alert-episode.ts
|
|
8216
|
+
function decideAlert(input) {
|
|
8217
|
+
const previous = input.previous;
|
|
8218
|
+
if (previous === void 0) return input.alerting ? { kind: "raise" } : { kind: "seeded" };
|
|
8219
|
+
if (previous.alerting !== input.alerting) {
|
|
8220
|
+
if (input.alerting) return { kind: "raise" };
|
|
8221
|
+
if (previous.lastNotifiedAt <= 0) return { kind: "silent" };
|
|
8222
|
+
return input.notifyRecovery ? { kind: "recover" } : { kind: "silent" };
|
|
8223
|
+
}
|
|
8224
|
+
if (!input.alerting) return { kind: "silent" };
|
|
8225
|
+
if (input.renotifyMs <= 0) return { kind: "silent" };
|
|
8226
|
+
if (previous.lastNotifiedAt <= 0) return { kind: "silent" };
|
|
8227
|
+
if (input.nowMs - previous.lastNotifiedAt < input.renotifyMs) return { kind: "silent" };
|
|
8228
|
+
return {
|
|
8229
|
+
kind: "remind",
|
|
8230
|
+
reminderIndex: previous.reminders + 1
|
|
8231
|
+
};
|
|
8232
|
+
}
|
|
8233
|
+
/**
|
|
8234
|
+
* The row that survives a verdict.
|
|
8235
|
+
*
|
|
8236
|
+
* Split from {@link decideAlert} rather than returned with it because the
|
|
8237
|
+
* caller must be able to persist a row for a verdict it did NOT deliver — the
|
|
8238
|
+
* suppressed recovery is the whole reason (rule 3), and so is the silent seed.
|
|
8239
|
+
*/
|
|
8240
|
+
function nextAlertRow(subject, previous, alerting, verdict, nowMs) {
|
|
8241
|
+
switch (verdict.kind) {
|
|
8242
|
+
case "seeded": return {
|
|
8243
|
+
subject,
|
|
8244
|
+
alerting,
|
|
8245
|
+
since: nowMs,
|
|
8246
|
+
lastNotifiedAt: 0,
|
|
8247
|
+
reminders: 0
|
|
8248
|
+
};
|
|
8249
|
+
case "raise":
|
|
8250
|
+
case "recover": return {
|
|
8251
|
+
subject,
|
|
8252
|
+
alerting,
|
|
8253
|
+
since: nowMs,
|
|
8254
|
+
lastNotifiedAt: nowMs,
|
|
8255
|
+
reminders: 0
|
|
8256
|
+
};
|
|
8257
|
+
case "remind": return {
|
|
8258
|
+
subject,
|
|
8259
|
+
alerting,
|
|
8260
|
+
since: previous?.since ?? nowMs,
|
|
8261
|
+
lastNotifiedAt: nowMs,
|
|
8262
|
+
reminders: verdict.reminderIndex
|
|
8263
|
+
};
|
|
8264
|
+
case "silent":
|
|
8265
|
+
if (previous === void 0) return {
|
|
8266
|
+
subject,
|
|
8267
|
+
alerting,
|
|
8268
|
+
since: nowMs,
|
|
8269
|
+
lastNotifiedAt: 0,
|
|
8270
|
+
reminders: 0
|
|
8271
|
+
};
|
|
8272
|
+
if (previous.alerting !== alerting) return {
|
|
8273
|
+
subject,
|
|
8274
|
+
alerting,
|
|
8275
|
+
since: nowMs,
|
|
8276
|
+
lastNotifiedAt: previous.lastNotifiedAt,
|
|
8277
|
+
reminders: 0
|
|
8278
|
+
};
|
|
8279
|
+
return previous;
|
|
8280
|
+
}
|
|
8281
|
+
}
|
|
8282
|
+
/**
|
|
8283
|
+
* The `recordId` a notification for this episode carries — and therefore, via
|
|
8284
|
+
* the outbox's fallback, its `dedupRef`.
|
|
8285
|
+
*
|
|
8286
|
+
* `reminderIndex: 0` is the opening notification (and the recovery, which
|
|
8287
|
+
* opens the `normal` episode). Every reminder appends `:r<n>`, which is what
|
|
8288
|
+
* stops the 7-day outbox dedup swallowing it.
|
|
8289
|
+
*/
|
|
8290
|
+
function alertRecordId(subject, since, reminderIndex) {
|
|
8291
|
+
const base = `${subject}:${since}`;
|
|
8292
|
+
return reminderIndex > 0 ? `${base}:r${reminderIndex}` : base;
|
|
8293
|
+
}
|
|
8294
|
+
/**
|
|
8295
|
+
* The device a subject is about: `battery:3602` → 3602, and
|
|
8296
|
+
* `consumable:4385:sensor` → 4385. The id is the SECOND segment, never the
|
|
8297
|
+
* last — reading the last one turned every consumable subject into "no
|
|
8298
|
+
* device", which lost the `deviceId` tag on its log lines and the indexed
|
|
8299
|
+
* column on its durable row. `undefined` for a subject that names no device.
|
|
8300
|
+
*/
|
|
8301
|
+
function alertSubjectDeviceId(subject) {
|
|
8302
|
+
const raw = subject.split(":")[1];
|
|
8303
|
+
if (raw === void 0 || raw === "") return void 0;
|
|
8304
|
+
const parsed = Number(raw);
|
|
8305
|
+
return Number.isInteger(parsed) ? parsed : void 0;
|
|
8306
|
+
}
|
|
8307
|
+
//#endregion
|
|
8215
8308
|
//#region src/notification-center/alerts/alert-store.ts
|
|
8216
8309
|
/**
|
|
8217
8310
|
* @durable class=ledger owner=notification-center
|
|
@@ -8269,9 +8362,9 @@ var NC_ALERTS_INDEXES = [{
|
|
|
8269
8362
|
name: "idx_nc_alerts_device",
|
|
8270
8363
|
columns: ["deviceId"]
|
|
8271
8364
|
}];
|
|
8365
|
+
/** The device a subject is about — see {@link alertSubjectDeviceId}. */
|
|
8272
8366
|
function deviceIdOf(subject) {
|
|
8273
|
-
|
|
8274
|
-
return Number.isInteger(parsed) ? parsed : void 0;
|
|
8367
|
+
return alertSubjectDeviceId(subject);
|
|
8275
8368
|
}
|
|
8276
8369
|
var NC_ALERTS_SPEC = {
|
|
8277
8370
|
collection: NC_ALERTS_COLLECTION,
|
|
@@ -8331,7 +8424,8 @@ var NcAlertStore = class {
|
|
|
8331
8424
|
put: (row) => {
|
|
8332
8425
|
this.ledger.put(row).catch(() => void 0);
|
|
8333
8426
|
},
|
|
8334
|
-
all: () => this.ledger.snapshot()
|
|
8427
|
+
all: () => this.ledger.snapshot(),
|
|
8428
|
+
remove: (subject) => this.ledger.forget(subject)
|
|
8335
8429
|
};
|
|
8336
8430
|
}
|
|
8337
8431
|
};
|
|
@@ -9942,6 +10036,10 @@ function systemEventExclusion(condition, subject) {
|
|
|
9942
10036
|
if (condition.deviceIds !== void 0 && applies("deviceIds")) {
|
|
9943
10037
|
if (subject.deviceId === void 0 || !condition.deviceIds.includes(subject.deviceId)) return "deviceIds";
|
|
9944
10038
|
}
|
|
10039
|
+
const excluded = condition.excludeDeviceIds;
|
|
10040
|
+
if (excluded !== void 0 && applies("deviceIds")) {
|
|
10041
|
+
if (subject.deviceId !== void 0 && excluded.includes(subject.deviceId)) return "excludeDeviceIds";
|
|
10042
|
+
}
|
|
9945
10043
|
if (condition.deviceTypes !== void 0 && applies("deviceTypes")) {
|
|
9946
10044
|
if (subject.deviceType === void 0 || !condition.deviceTypes.includes(subject.deviceType)) return "deviceTypes";
|
|
9947
10045
|
}
|
|
@@ -11504,85 +11602,6 @@ function deliveryForKind(kind) {
|
|
|
11504
11602
|
return kind;
|
|
11505
11603
|
}
|
|
11506
11604
|
//#endregion
|
|
11507
|
-
//#region src/notification-center/alerts/alert-episode.ts
|
|
11508
|
-
function decideAlert(input) {
|
|
11509
|
-
const previous = input.previous;
|
|
11510
|
-
if (previous === void 0) return input.alerting ? { kind: "raise" } : { kind: "seeded" };
|
|
11511
|
-
if (previous.alerting !== input.alerting) {
|
|
11512
|
-
if (input.alerting) return { kind: "raise" };
|
|
11513
|
-
return input.notifyRecovery ? { kind: "recover" } : { kind: "silent" };
|
|
11514
|
-
}
|
|
11515
|
-
if (!input.alerting) return { kind: "silent" };
|
|
11516
|
-
if (input.renotifyMs <= 0) return { kind: "silent" };
|
|
11517
|
-
if (previous.lastNotifiedAt <= 0) return { kind: "silent" };
|
|
11518
|
-
if (input.nowMs - previous.lastNotifiedAt < input.renotifyMs) return { kind: "silent" };
|
|
11519
|
-
return {
|
|
11520
|
-
kind: "remind",
|
|
11521
|
-
reminderIndex: previous.reminders + 1
|
|
11522
|
-
};
|
|
11523
|
-
}
|
|
11524
|
-
/**
|
|
11525
|
-
* The row that survives a verdict.
|
|
11526
|
-
*
|
|
11527
|
-
* Split from {@link decideAlert} rather than returned with it because the
|
|
11528
|
-
* caller must be able to persist a row for a verdict it did NOT deliver — the
|
|
11529
|
-
* suppressed recovery is the whole reason (rule 3), and so is the silent seed.
|
|
11530
|
-
*/
|
|
11531
|
-
function nextAlertRow(subject, previous, alerting, verdict, nowMs) {
|
|
11532
|
-
switch (verdict.kind) {
|
|
11533
|
-
case "seeded": return {
|
|
11534
|
-
subject,
|
|
11535
|
-
alerting,
|
|
11536
|
-
since: nowMs,
|
|
11537
|
-
lastNotifiedAt: 0,
|
|
11538
|
-
reminders: 0
|
|
11539
|
-
};
|
|
11540
|
-
case "raise":
|
|
11541
|
-
case "recover": return {
|
|
11542
|
-
subject,
|
|
11543
|
-
alerting,
|
|
11544
|
-
since: nowMs,
|
|
11545
|
-
lastNotifiedAt: nowMs,
|
|
11546
|
-
reminders: 0
|
|
11547
|
-
};
|
|
11548
|
-
case "remind": return {
|
|
11549
|
-
subject,
|
|
11550
|
-
alerting,
|
|
11551
|
-
since: previous?.since ?? nowMs,
|
|
11552
|
-
lastNotifiedAt: nowMs,
|
|
11553
|
-
reminders: verdict.reminderIndex
|
|
11554
|
-
};
|
|
11555
|
-
case "silent":
|
|
11556
|
-
if (previous === void 0) return {
|
|
11557
|
-
subject,
|
|
11558
|
-
alerting,
|
|
11559
|
-
since: nowMs,
|
|
11560
|
-
lastNotifiedAt: 0,
|
|
11561
|
-
reminders: 0
|
|
11562
|
-
};
|
|
11563
|
-
if (previous.alerting !== alerting) return {
|
|
11564
|
-
subject,
|
|
11565
|
-
alerting,
|
|
11566
|
-
since: nowMs,
|
|
11567
|
-
lastNotifiedAt: previous.lastNotifiedAt,
|
|
11568
|
-
reminders: 0
|
|
11569
|
-
};
|
|
11570
|
-
return previous;
|
|
11571
|
-
}
|
|
11572
|
-
}
|
|
11573
|
-
/**
|
|
11574
|
-
* The `recordId` a notification for this episode carries — and therefore, via
|
|
11575
|
-
* the outbox's fallback, its `dedupRef`.
|
|
11576
|
-
*
|
|
11577
|
-
* `reminderIndex: 0` is the opening notification (and the recovery, which
|
|
11578
|
-
* opens the `normal` episode). Every reminder appends `:r<n>`, which is what
|
|
11579
|
-
* stops the 7-day outbox dedup swallowing it.
|
|
11580
|
-
*/
|
|
11581
|
-
function alertRecordId(subject, since, reminderIndex) {
|
|
11582
|
-
const base = `${subject}:${since}`;
|
|
11583
|
-
return reminderIndex > 0 ? `${base}:r${reminderIndex}` : base;
|
|
11584
|
-
}
|
|
11585
|
-
//#endregion
|
|
11586
11605
|
//#region src/notification-center/alerts/battery-band.ts
|
|
11587
11606
|
/**
|
|
11588
11607
|
* The stand-in a provider writes for a binary NORMAL. Anything below it, on a
|
|
@@ -11644,6 +11663,18 @@ function deriveBatteryBand(input) {
|
|
|
11644
11663
|
* that is already a FAULT — see `alert-episode.ts` rule 2 for why that is D141
|
|
11645
11664
|
* rather than a loophole.
|
|
11646
11665
|
*/
|
|
11666
|
+
/** One hour — the longest a pending raise waits before it is offered again. */
|
|
11667
|
+
var PENDING_CADENCE_MAX_MS = 36e5;
|
|
11668
|
+
/**
|
|
11669
|
+
* How often a pending raise is offered again with the rules unchanged: the
|
|
11670
|
+
* re-notify interval, capped at one hour. The cap matters because the
|
|
11671
|
+
* cadence counts from the raise: with a 12 h interval, a rule whose schedule
|
|
11672
|
+
* opens for one hour a day could keep being missed. Reminders off ("say it
|
|
11673
|
+
* once") still has to say it once, hourly.
|
|
11674
|
+
*/
|
|
11675
|
+
function pendingCadenceMs(settings) {
|
|
11676
|
+
return settings.renotifyMinutes > 0 ? Math.min(settings.renotifyMinutes * 6e4, PENDING_CADENCE_MAX_MS) : PENDING_CADENCE_MAX_MS;
|
|
11677
|
+
}
|
|
11647
11678
|
var NcDeviceAlerts = class {
|
|
11648
11679
|
deps;
|
|
11649
11680
|
now;
|
|
@@ -11657,6 +11688,13 @@ var NcDeviceAlerts = class {
|
|
|
11657
11688
|
lastReading = /* @__PURE__ */ new Map();
|
|
11658
11689
|
/** The last reading per consumable SUBJECT, for the reminder sweep. */
|
|
11659
11690
|
lastConsumable = /* @__PURE__ */ new Map();
|
|
11691
|
+
/**
|
|
11692
|
+
* Subject → WHEN its PENDING raise was last offered, and to which
|
|
11693
|
+
* {@link NcDeviceAlertsDeps.rulesVersion}. RAM only, on purpose: after a
|
|
11694
|
+
* restart every pending raise is offered once more, which is bounded by the
|
|
11695
|
+
* number of open episodes.
|
|
11696
|
+
*/
|
|
11697
|
+
offeredAt = /* @__PURE__ */ new Map();
|
|
11660
11698
|
constructor(deps) {
|
|
11661
11699
|
this.deps = deps;
|
|
11662
11700
|
this.now = deps.now ?? Date.now;
|
|
@@ -11742,34 +11780,94 @@ var NcDeviceAlerts = class {
|
|
|
11742
11780
|
*/
|
|
11743
11781
|
tick() {
|
|
11744
11782
|
const settings = this.deps.settings();
|
|
11783
|
+
this.retryPending(settings);
|
|
11745
11784
|
if (settings.renotifyMinutes <= 0) return;
|
|
11746
11785
|
for (const row of this.deps.rows.all()) {
|
|
11747
|
-
if (!row.alerting) continue;
|
|
11748
|
-
const
|
|
11749
|
-
if (
|
|
11750
|
-
|
|
11751
|
-
facts,
|
|
11752
|
-
deviceId: consumable.deviceId,
|
|
11753
|
-
band: "low",
|
|
11754
|
-
item: consumable.item,
|
|
11755
|
-
identity: this.deps.lookup(consumable.deviceId)
|
|
11756
|
-
}));
|
|
11757
|
-
continue;
|
|
11758
|
-
}
|
|
11759
|
-
const restatement = this.lastReading.get(row.subject);
|
|
11760
|
-
if (restatement === void 0) continue;
|
|
11761
|
-
this.apply(row.subject, true, settings, (facts) => incomingFromBatteryBand({
|
|
11762
|
-
facts,
|
|
11763
|
-
deviceId: restatement.deviceId,
|
|
11764
|
-
band: "low",
|
|
11765
|
-
reading: restatement.reading,
|
|
11766
|
-
identity: this.deps.lookup(restatement.deviceId)
|
|
11767
|
-
}));
|
|
11786
|
+
if (!row.alerting || isPending(row)) continue;
|
|
11787
|
+
const build = this.restatementOf(row.subject);
|
|
11788
|
+
if (build === null) continue;
|
|
11789
|
+
this.apply(row.subject, true, settings, build);
|
|
11768
11790
|
}
|
|
11769
11791
|
}
|
|
11770
|
-
/**
|
|
11771
|
-
|
|
11792
|
+
/**
|
|
11793
|
+
* Every device that holds an alert row — what the deleted-device reconcile
|
|
11794
|
+
* must look at besides the devices a rule names (a battery device no rule
|
|
11795
|
+
* names still has a row).
|
|
11796
|
+
*/
|
|
11797
|
+
deviceIds() {
|
|
11798
|
+
const ids = /* @__PURE__ */ new Set();
|
|
11799
|
+
for (const row of this.deps.rows.all()) {
|
|
11800
|
+
const id = alertSubjectDeviceId(row.subject);
|
|
11801
|
+
if (id !== void 0) ids.add(id);
|
|
11802
|
+
}
|
|
11803
|
+
return [...ids];
|
|
11804
|
+
}
|
|
11805
|
+
/**
|
|
11806
|
+
* A DELETED device: drop its battery row and every consumable row, durable
|
|
11807
|
+
* and in RAM, so nothing restates it and a re-adoption starts a fresh
|
|
11808
|
+
* episode. Called only by the deleted-device prune (D633), after the second
|
|
11809
|
+
* read agreed the device is gone. Returns how many rows went.
|
|
11810
|
+
*/
|
|
11811
|
+
async forget(deviceId) {
|
|
11812
|
+
const subjects = this.deps.rows.all().map((row) => row.subject).filter((subject) => alertSubjectDeviceId(subject) === deviceId);
|
|
11813
|
+
for (const subject of subjects) {
|
|
11814
|
+
this.lastReading.delete(subject);
|
|
11815
|
+
this.lastConsumable.delete(subject);
|
|
11816
|
+
this.offeredAt.delete(subject);
|
|
11817
|
+
await this.deps.rows.remove(subject);
|
|
11818
|
+
}
|
|
11772
11819
|
this.lastReading.delete(`battery:${deviceId}`);
|
|
11820
|
+
return subjects.length;
|
|
11821
|
+
}
|
|
11822
|
+
/**
|
|
11823
|
+
* Offer every PENDING raise once more — when the rule set changed since its
|
|
11824
|
+
* last offer, OR when {@link pendingCadenceMs} has passed since it. The
|
|
11825
|
+
* cadence is what delivers a raise refused only by a rule's SCHEDULE (or any
|
|
11826
|
+
* other time-dependent gate): the rules do not change when the window
|
|
11827
|
+
* opens. The restatement is RAM: a row whose reading has not arrived since
|
|
11828
|
+
* the restart waits for it (the slice arrives on its own).
|
|
11829
|
+
*/
|
|
11830
|
+
retryPending(settings) {
|
|
11831
|
+
const version = this.deps.rulesVersion();
|
|
11832
|
+
const nowMs = this.now();
|
|
11833
|
+
const cadenceMs = pendingCadenceMs(settings);
|
|
11834
|
+
for (const row of this.deps.rows.all()) {
|
|
11835
|
+
if (!isPending(row)) continue;
|
|
11836
|
+
const last = this.offeredAt.get(row.subject);
|
|
11837
|
+
const changed = last === void 0 || last.version !== version;
|
|
11838
|
+
if (!changed && nowMs - last.at < cadenceMs) continue;
|
|
11839
|
+
const build = this.restatementOf(row.subject);
|
|
11840
|
+
if (build === null) continue;
|
|
11841
|
+
this.logger()?.debug("device alert re-offered — no rule has matched it yet", {
|
|
11842
|
+
...tagsOf(row.subject),
|
|
11843
|
+
meta: {
|
|
11844
|
+
subject: row.subject,
|
|
11845
|
+
since: row.since,
|
|
11846
|
+
reason: changed ? "rules" : "cadence"
|
|
11847
|
+
}
|
|
11848
|
+
});
|
|
11849
|
+
this.speak(row.subject, row, { kind: "raise" }, build);
|
|
11850
|
+
}
|
|
11851
|
+
}
|
|
11852
|
+
/** How to re-word a subject's alert from the last reading, or `null`. */
|
|
11853
|
+
restatementOf(subject) {
|
|
11854
|
+
const consumable = this.lastConsumable.get(subject);
|
|
11855
|
+
if (consumable !== void 0) return (facts) => incomingFromConsumableBand({
|
|
11856
|
+
facts,
|
|
11857
|
+
deviceId: consumable.deviceId,
|
|
11858
|
+
band: "low",
|
|
11859
|
+
item: consumable.item,
|
|
11860
|
+
identity: this.deps.lookup(consumable.deviceId)
|
|
11861
|
+
});
|
|
11862
|
+
const battery = this.lastReading.get(subject);
|
|
11863
|
+
if (battery !== void 0) return (facts) => incomingFromBatteryBand({
|
|
11864
|
+
facts,
|
|
11865
|
+
deviceId: battery.deviceId,
|
|
11866
|
+
band: "low",
|
|
11867
|
+
reading: battery.reading,
|
|
11868
|
+
identity: this.deps.lookup(battery.deviceId)
|
|
11869
|
+
});
|
|
11870
|
+
return null;
|
|
11773
11871
|
}
|
|
11774
11872
|
/**
|
|
11775
11873
|
* The shared half: decide, persist, and speak only when the verdict says to.
|
|
@@ -11794,16 +11892,63 @@ var NcDeviceAlerts = class {
|
|
|
11794
11892
|
this.report(subject, verdict, alerting);
|
|
11795
11893
|
return;
|
|
11796
11894
|
}
|
|
11895
|
+
this.speak(subject, next, verdict, (facts) => build(facts, alerting));
|
|
11896
|
+
}
|
|
11897
|
+
/**
|
|
11898
|
+
* Emit one verdict through the door, and — for a RAISE — hear whether any
|
|
11899
|
+
* rule matched it. A raise no rule matched is put back to PENDING
|
|
11900
|
+
* (`lastNotifiedAt: 0`), unless the row moved meanwhile; it is re-offered
|
|
11901
|
+
* by {@link retryPending} when the rules change. A reminder or a recovery is
|
|
11902
|
+
* not re-offered: the episode was already announced (or is over).
|
|
11903
|
+
*/
|
|
11904
|
+
speak(subject, row, verdict, build) {
|
|
11905
|
+
const nowMs = this.now();
|
|
11797
11906
|
const reminderIndex = verdict.kind === "remind" ? verdict.reminderIndex : 0;
|
|
11798
|
-
|
|
11799
|
-
eventId: alertRecordId(subject,
|
|
11907
|
+
const event = build({
|
|
11908
|
+
eventId: alertRecordId(subject, row.since, reminderIndex),
|
|
11800
11909
|
timestamp: nowMs,
|
|
11801
11910
|
category: EventCategory.DeviceStateChanged,
|
|
11802
11911
|
data: {
|
|
11803
11912
|
alertVerdict: verdict.kind,
|
|
11804
11913
|
reminderIndex
|
|
11805
11914
|
}
|
|
11806
|
-
}
|
|
11915
|
+
});
|
|
11916
|
+
if (verdict.kind !== "raise") {
|
|
11917
|
+
this.deps.emit(event).catch(() => void 0);
|
|
11918
|
+
return;
|
|
11919
|
+
}
|
|
11920
|
+
this.offeredAt.set(subject, {
|
|
11921
|
+
version: this.deps.rulesVersion(),
|
|
11922
|
+
at: nowMs
|
|
11923
|
+
});
|
|
11924
|
+
this.deps.emit(event).then((heard) => this.settleRaise(subject, row.since, heard, nowMs)).catch(() => void 0);
|
|
11925
|
+
}
|
|
11926
|
+
/** The door answered a raise. */
|
|
11927
|
+
settleRaise(subject, since, heard, nowMs) {
|
|
11928
|
+
const current = this.deps.rows.get(subject);
|
|
11929
|
+
if (current === void 0 || !current.alerting || current.since !== since) return;
|
|
11930
|
+
if (heard) {
|
|
11931
|
+
this.offeredAt.delete(subject);
|
|
11932
|
+
if (current.lastNotifiedAt !== nowMs) this.deps.rows.put({
|
|
11933
|
+
...current,
|
|
11934
|
+
lastNotifiedAt: nowMs
|
|
11935
|
+
});
|
|
11936
|
+
return;
|
|
11937
|
+
}
|
|
11938
|
+
if (current.lastNotifiedAt !== 0) this.deps.rows.put({
|
|
11939
|
+
...current,
|
|
11940
|
+
lastNotifiedAt: 0
|
|
11941
|
+
});
|
|
11942
|
+
this.logger()?.info("device alert matched NO rule — kept pending, offered again on a rule change or within the hour", {
|
|
11943
|
+
...tagsOf(subject),
|
|
11944
|
+
meta: {
|
|
11945
|
+
subject,
|
|
11946
|
+
since
|
|
11947
|
+
}
|
|
11948
|
+
});
|
|
11949
|
+
}
|
|
11950
|
+
logger() {
|
|
11951
|
+
return this.deps.logger;
|
|
11807
11952
|
}
|
|
11808
11953
|
/**
|
|
11809
11954
|
* A dropped branch is never silent. The suppressed recovery in particular:
|
|
@@ -11813,7 +11958,7 @@ var NcDeviceAlerts = class {
|
|
|
11813
11958
|
report(subject, verdict, alerting) {
|
|
11814
11959
|
const logger = this.deps.logger;
|
|
11815
11960
|
if (logger === void 0) return;
|
|
11816
|
-
const deviceId =
|
|
11961
|
+
const deviceId = alertSubjectDeviceId(subject);
|
|
11817
11962
|
const tags = deviceId !== void 0 ? { deviceId } : {};
|
|
11818
11963
|
if (verdict.kind === "silent" && !alerting) {
|
|
11819
11964
|
logger.debug("device alert cleared without a notification", {
|
|
@@ -11837,11 +11982,16 @@ var NcDeviceAlerts = class {
|
|
|
11837
11982
|
function speaks(verdict) {
|
|
11838
11983
|
return verdict.kind === "raise" || verdict.kind === "recover" || verdict.kind === "remind";
|
|
11839
11984
|
}
|
|
11840
|
-
/**
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11985
|
+
/**
|
|
11986
|
+
* A raise no rule matched: alerting, and never announced. A row in the
|
|
11987
|
+
* alerting state is otherwise always stamped, because it was raised.
|
|
11988
|
+
*/
|
|
11989
|
+
function isPending(row) {
|
|
11990
|
+
return row.alerting && row.lastNotifiedAt <= 0;
|
|
11991
|
+
}
|
|
11992
|
+
function tagsOf(subject) {
|
|
11993
|
+
const deviceId = alertSubjectDeviceId(subject);
|
|
11994
|
+
return deviceId !== void 0 ? { tags: { deviceId } } : {};
|
|
11845
11995
|
}
|
|
11846
11996
|
//#endregion
|
|
11847
11997
|
//#region src/notification-center/cap-caller.ts
|
|
@@ -19062,6 +19212,7 @@ var NcDeletedSubjectPruner = class {
|
|
|
19062
19212
|
return this.serialise(async () => {
|
|
19063
19213
|
if (!this.ready("event", deviceId)) return;
|
|
19064
19214
|
if (!await this.confirmDeleted(deviceId, "event")) return;
|
|
19215
|
+
await this.forgetAlerts(deviceId, "event");
|
|
19065
19216
|
const deleted = new Set([deviceId]);
|
|
19066
19217
|
await this.apply(planDevicePrune(this.snapshot(), deleted, this.guard()), "event", (fresh) => planDevicePrune(fresh, deleted, this.guard()));
|
|
19067
19218
|
}, deviceId);
|
|
@@ -19071,15 +19222,17 @@ var NcDeletedSubjectPruner = class {
|
|
|
19071
19222
|
return this.serialise(async () => {
|
|
19072
19223
|
if (!this.ready("reconcile")) return;
|
|
19073
19224
|
const directory = this.deps.directory;
|
|
19074
|
-
const
|
|
19225
|
+
const alerting = new Set(this.deps.alerts?.deviceIds() ?? []);
|
|
19226
|
+
const candidates = [...new Set([...referencedDeviceIds(this.snapshot()), ...alerting])].filter((id) => directory.absentFromLastTwoAnswers(id));
|
|
19075
19227
|
if (candidates.length === 0) return;
|
|
19076
19228
|
const first = planDevicePrune(this.snapshot(), new Set(candidates), this.guard());
|
|
19077
|
-
|
|
19078
|
-
|
|
19229
|
+
const subjects = [...new Set([...[...planSubjects(first)].map(Number), ...candidates.filter((id) => alerting.has(id))])];
|
|
19230
|
+
if (subjects.length === 0) return;
|
|
19079
19231
|
if (!this.withinBound("device", subjects.map(String))) return;
|
|
19080
19232
|
const confirmed = /* @__PURE__ */ new Set();
|
|
19081
19233
|
for (const id of subjects) if (await this.confirmDeleted(id, "reconcile")) confirmed.add(id);
|
|
19082
19234
|
if (confirmed.size === 0) return;
|
|
19235
|
+
for (const id of confirmed) if (alerting.has(id)) await this.forgetAlerts(id, "reconcile");
|
|
19083
19236
|
await this.apply(planDevicePrune(this.snapshot(), confirmed, this.guard()), "reconcile", (fresh) => planDevicePrune(fresh, confirmed, this.guard()));
|
|
19084
19237
|
});
|
|
19085
19238
|
}
|
|
@@ -19157,6 +19310,33 @@ var NcDeletedSubjectPruner = class {
|
|
|
19157
19310
|
return false;
|
|
19158
19311
|
}
|
|
19159
19312
|
}
|
|
19313
|
+
/**
|
|
19314
|
+
* Drop a CONFIRMED-deleted device's alert rows. A failure is logged and
|
|
19315
|
+
* retried by the next reconcile, which still sees the row.
|
|
19316
|
+
*/
|
|
19317
|
+
async forgetAlerts(deviceId, source) {
|
|
19318
|
+
const alerts = this.deps.alerts;
|
|
19319
|
+
if (alerts === void 0) return;
|
|
19320
|
+
try {
|
|
19321
|
+
const forgotten = await alerts.forget(deviceId);
|
|
19322
|
+
if (forgotten === 0) return;
|
|
19323
|
+
this.deps.logger.info("deleted device alerts forgotten", {
|
|
19324
|
+
tags: { deviceId },
|
|
19325
|
+
meta: {
|
|
19326
|
+
source,
|
|
19327
|
+
rows: forgotten
|
|
19328
|
+
}
|
|
19329
|
+
});
|
|
19330
|
+
} catch (err) {
|
|
19331
|
+
this.deps.logger.warn("deleted device alerts NOT forgotten — retried next tick", {
|
|
19332
|
+
tags: { deviceId },
|
|
19333
|
+
meta: {
|
|
19334
|
+
source,
|
|
19335
|
+
error: String(err)
|
|
19336
|
+
}
|
|
19337
|
+
});
|
|
19338
|
+
}
|
|
19339
|
+
}
|
|
19160
19340
|
withinBound(subjectKind, subjects) {
|
|
19161
19341
|
if (subjects.length <= 16) {
|
|
19162
19342
|
this.lastAbort.delete(subjectKind);
|
|
@@ -28246,9 +28426,10 @@ var NotificationCenter = class NotificationCenter {
|
|
|
28246
28426
|
logger: this.logger.child("device-alerts")
|
|
28247
28427
|
});
|
|
28248
28428
|
this.deviceAlerts = new NcDeviceAlerts({
|
|
28249
|
-
emit: (event) => {
|
|
28250
|
-
this.
|
|
28429
|
+
emit: async (event) => {
|
|
28430
|
+
return (await this.consumeEventAndReport(event)).outcomes.some((outcome) => outcome.matched);
|
|
28251
28431
|
},
|
|
28432
|
+
rulesVersion: () => this.rulesFingerprint(),
|
|
28252
28433
|
settings: () => this.deviceAlertSettings(),
|
|
28253
28434
|
lookup: (deviceId) => this.deviceDirectory.get(deviceId),
|
|
28254
28435
|
rows: this.alertStore.port(),
|
|
@@ -28350,6 +28531,7 @@ var NotificationCenter = class NotificationCenter {
|
|
|
28350
28531
|
summary: this.summaryRules,
|
|
28351
28532
|
mutes: this.deviceMutes,
|
|
28352
28533
|
alarm: () => this.alarmPanel,
|
|
28534
|
+
alerts: this.deviceAlerts,
|
|
28353
28535
|
directory: this.deviceDirectory,
|
|
28354
28536
|
isDeviceDeleted: deps.isDeviceDeleted,
|
|
28355
28537
|
targetCatalog: () => this.dispatcher.catalogSnapshot()
|
|
@@ -31055,6 +31237,14 @@ var NotificationCenter = class NotificationCenter {
|
|
|
31055
31237
|
* wiring that silently disabled the feature would be indistinguishable from
|
|
31056
31238
|
* a hub with no low batteries on it.
|
|
31057
31239
|
*/
|
|
31240
|
+
/**
|
|
31241
|
+
* Which rules exist, and at which revision — the question "did anything
|
|
31242
|
+
* change that could make an undelivered alert deliverable now?". Cheap: the
|
|
31243
|
+
* rule mirror is in RAM and holds tens of rows.
|
|
31244
|
+
*/
|
|
31245
|
+
rulesFingerprint() {
|
|
31246
|
+
return this.rules.list().map((rule) => `${rule.id}@${String(rule.updatedAt)}`).join("|");
|
|
31247
|
+
}
|
|
31058
31248
|
deviceAlertSettings() {
|
|
31059
31249
|
return this.deps.readDeviceAlertSettings?.() ?? {
|
|
31060
31250
|
batteryLowPercent: NC_DEVICE_ALERT_FALLBACK.batteryLowPercent,
|
|
@@ -30,7 +30,7 @@ async function d(e) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
async function f() {
|
|
33
|
-
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-
|
|
33
|
+
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-CkyY7n6X.mjs")).catch((e) => {
|
|
34
34
|
throw l = void 0, e;
|
|
35
35
|
}), l;
|
|
36
36
|
}
|
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.278",
|
|
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",
|