@camstack/addon-post-analysis 1.2.58 → 1.2.60

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.
@@ -1,4 +1,4 @@
1
- import { $ as array, B as subKindsOf, C as addonWidgetsSourceCapability, D as cosineSimilarity, E as buildEventKindDescriptor, F as kebabToCamel, G as BaseAddon, H as videoclipsCapability, I as notificationRulesCapability, J as hydrateSchema, K as DeviceType, L as pipelineAnalyticsCapability, M as faceGalleryCapability, O as customAction, P as isScheduleActive, Q as _enum, R as plateGalleryCapability, S as TrackSourceSchema, T as audioMetricsCapability, U as zoneAnalyticsCapability, V as vectorDimFromBase64, W as errMsg, X as nodePin, Y as isDeviceScopedCap, Z as sleep, _ as NcTaxonomySchema, a as EVENT_PAD_MS, at as string, b as TimelapseRuleInputSchema, c as NC_CONDITION_CATALOG, d as NcRuleInputSchema, et as boolean, f as NcRulePatchSchema, g as NcSnoozeSuppressedSchema, h as NcSnoozeSchema, i as EVENT_KIND_BY_CAP, it as record, j as encodeVectorBase64, k as defineCustomActions, l as NC_TAXONOMY, m as NcSnoozeInputSchema, n as DEFAULT_EVENT_COLOR, nt as number, o as LabelAttributionSchema, ot as unknown, p as NcRuleSchema, q as createEvent, r as DeclaredDevices, rt as object, s as MACRO_LABELS, st as EventCategory, t as BaseDevice, tt as literal, u as NcConditionDescriptorSchema, v as OpsLogEntrySchema, w as alarmPanelCapability, x as TimelapseRuleSchema, y as RetrainStatusSchema, z as readDeviceStateFrom } from "../dist-CI2VspUN.mjs";
1
+ import { $ as array, B as subKindsOf, C as addonWidgetsSourceCapability, D as cosineSimilarity, E as buildEventKindDescriptor, F as kebabToCamel, G as BaseAddon, H as videoclipsCapability, I as notificationRulesCapability, J as hydrateSchema, K as DeviceType, L as pipelineAnalyticsCapability, M as faceGalleryCapability, O as customAction, P as isScheduleActive, Q as _enum, R as plateGalleryCapability, S as TrackSourceSchema, T as audioMetricsCapability, U as zoneAnalyticsCapability, V as vectorDimFromBase64, W as errMsg, X as nodePin, Y as isDeviceScopedCap, Z as sleep, _ as NcTaxonomySchema, a as EVENT_PAD_MS, at as string, b as TimelapseRuleInputSchema, c as NC_CONDITION_CATALOG, d as NcRuleInputSchema, et as boolean, f as NcRulePatchSchema, g as NcSnoozeSuppressedSchema, h as NcSnoozeSchema, i as EVENT_KIND_BY_CAP, it as record, j as encodeVectorBase64, k as defineCustomActions, l as NC_TAXONOMY, m as NcSnoozeInputSchema, n as DEFAULT_EVENT_COLOR, nt as number, o as LabelAttributionSchema, ot as unknown, p as NcRuleSchema, q as createEvent, r as DeclaredDevices, rt as object, s as MACRO_LABELS, st as EventCategory, t as BaseDevice, tt as literal, u as NcConditionDescriptorSchema, v as OpsLogEntrySchema, w as alarmPanelCapability, x as TimelapseRuleSchema, y as RetrainStatusSchema, z as readDeviceStateFrom } from "../dist-WvtopI3-.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";
@@ -2042,6 +2042,7 @@ function fail(condition) {
2042
2042
  */
2043
2043
  function presentConditionIds(c) {
2044
2044
  const ids = [];
2045
+ if (c.systemEvent !== void 0) ids.push("systemEvent");
2045
2046
  if (c.devices !== void 0 && c.devices.length > 0) ids.push("devices");
2046
2047
  if (c.source !== void 0 && c.source !== "any") ids.push("source");
2047
2048
  if (c.classes !== void 0 && c.classes.length > 0) ids.push("classes");
@@ -2135,19 +2136,34 @@ function referencesAudioClass(classes) {
2135
2136
  if (classes === void 0) return false;
2136
2137
  return classes.some((c) => c.trim().toLowerCase().startsWith("audio-"));
2137
2138
  }
2139
+ function matchesSystemEvent(condition, subject) {
2140
+ if (!condition.kinds.includes(subject.kind)) return false;
2141
+ if (condition.deviceIds !== void 0 && (subject.deviceId === void 0 || !condition.deviceIds.includes(subject.deviceId))) return false;
2142
+ if (condition.nodeIds !== void 0 && (subject.nodeId === void 0 || !condition.nodeIds.includes(subject.nodeId))) return false;
2143
+ if (condition.packageNames !== void 0 && (subject.packageName === void 0 || !condition.packageNames.includes(subject.packageName))) return false;
2144
+ return true;
2145
+ }
2138
2146
  function evaluateRule(rule, subject, deviceState) {
2139
- if (subject.kind === "occupancy-event") {
2147
+ if (subject.kind === "system-event") {
2148
+ if (rule.delivery !== "system-event") return fail("delivery");
2149
+ const condition = rule.conditions.systemEvent;
2150
+ if (condition === void 0 || subject.systemEvent === void 0 || !matchesSystemEvent(condition, subject.systemEvent)) return fail("systemEvent");
2151
+ if (rule.conditions.occupancy !== void 0) return fail("occupancy");
2152
+ } else if (subject.kind === "occupancy-event") {
2140
2153
  if (rule.delivery !== "device-event") return fail("delivery");
2141
2154
  const occ = rule.conditions.occupancy;
2142
2155
  if (occ === void 0) return fail("occupancy");
2143
2156
  if (subject.occupancy === void 0 || !matchesOccupancy(occ, subject.occupancy)) return fail("occupancy");
2157
+ if (rule.conditions.systemEvent !== void 0) return fail("systemEvent");
2144
2158
  } else if (subject.kind === "audio-event") {
2145
2159
  if (rule.delivery !== "immediate") return fail("delivery");
2146
2160
  if (!referencesAudioClass(rule.conditions.classes)) return fail("classes");
2147
2161
  if (rule.conditions.occupancy !== void 0) return fail("occupancy");
2162
+ if (rule.conditions.systemEvent !== void 0) return fail("systemEvent");
2148
2163
  } else {
2149
2164
  if ((rule.delivery === "immediate" ? "object-event" : rule.delivery) !== subject.kind) return fail("delivery");
2150
2165
  if (rule.conditions.occupancy !== void 0) return fail("occupancy");
2166
+ if (rule.conditions.systemEvent !== void 0) return fail("systemEvent");
2151
2167
  }
2152
2168
  const c = rule.conditions;
2153
2169
  if (c.deviceState !== void 0) {
@@ -2307,7 +2323,8 @@ function matchesDeviceScope(scope, subject) {
2307
2323
  function cooldownKey(rule, subject) {
2308
2324
  const first = subject.classNames[0];
2309
2325
  const classKey = keysPerClass(rule, subject) && first !== void 0 ? `:c:${first}` : "";
2310
- return rule.throttle.scope === "rule" ? `r:${rule.id}${classKey}` : `r:${rule.id}:d:${subject.deviceId}${classKey}`;
2326
+ const scopeRef = subject.systemEvent !== void 0 ? `s:${subject.systemEvent.subject}` : `d:${subject.deviceId}`;
2327
+ return rule.throttle.scope === "rule" ? `r:${rule.id}${classKey}` : `r:${rule.id}:${scopeRef}${classKey}`;
2311
2328
  }
2312
2329
  /** True when the rule fired within its cooldown window before `now`. */
2313
2330
  function isCoolingDown(rule, lastFiredAt, now) {
@@ -2704,10 +2721,12 @@ var NcDispatcher = class {
2704
2721
  }
2705
2722
  async buildNotification(entry, target) {
2706
2723
  const subject = entry.payload.subject;
2707
- const deviceName = await this.deps.getDeviceName(subject.deviceId).catch(() => null) ?? `camera ${subject.deviceId}`;
2708
- const zoneLabels = await resolveZoneLabels(this.deps.getZoneNames, subject.deviceId, subject.zones);
2724
+ const systemEvent = subject.systemEvent;
2725
+ const displayDeviceId = systemEvent?.deviceId ?? subject.deviceId;
2726
+ const deviceName = systemEvent !== void 0 && systemEvent.deviceId === void 0 ? "system" : await this.deps.getDeviceName(displayDeviceId).catch(() => null) ?? `camera ${displayDeviceId}`;
2727
+ const zoneLabels = systemEvent !== void 0 ? [] : await resolveZoneLabels(this.deps.getZoneNames, subject.deviceId, subject.zones);
2709
2728
  const vars = buildTemplateVars(entry, deviceName, zoneLabels);
2710
- const title = renderTemplate(entry.payload.template?.title, vars) ?? entry.payload.ruleName;
2729
+ const title = renderTemplate(entry.payload.template?.title, vars) ?? systemEvent?.title ?? entry.payload.ruleName;
2711
2730
  const body = renderTemplate(entry.payload.template?.body, vars) ?? defaultBody(entry, deviceName, zoneLabels);
2712
2731
  const attachments = await this.withArtifactUrls(await this.resolveAttachments(entry));
2713
2732
  const params = pickParams(entry.payload.params);
@@ -2718,8 +2737,13 @@ var NcDispatcher = class {
2718
2737
  priority: clampPriority(paramNumber(entry.payload.params, "priority") ?? entry.payload.priority),
2719
2738
  ...params,
2720
2739
  tag: entry.ruleId,
2721
- deviceId: subject.deviceId,
2740
+ ...systemEvent !== void 0 ? systemEvent.deviceId !== void 0 ? { deviceId: systemEvent.deviceId } : {} : { deviceId: subject.deviceId },
2722
2741
  ...subject.eventId !== void 0 ? { eventId: subject.eventId } : {},
2742
+ ...systemEvent !== void 0 ? { metadata: {
2743
+ systemEventKind: systemEvent.kind,
2744
+ subject: systemEvent.subject,
2745
+ ...systemEvent.data
2746
+ } } : {},
2723
2747
  ...attachments.length > 0 ? { attachments } : {},
2724
2748
  ...actions.length > 0 ? { actions } : {}
2725
2749
  };
@@ -2946,6 +2970,7 @@ async function resolveZoneLabels(getZoneNames, deviceId, zoneIds) {
2946
2970
  function buildTemplateVars(entry, deviceName, zoneLabels) {
2947
2971
  const subject = entry.payload.subject;
2948
2972
  const occupancy = subject.occupancy;
2973
+ const systemEvent = subject.systemEvent;
2949
2974
  return {
2950
2975
  camera: deviceName,
2951
2976
  class: subject.className,
@@ -2957,7 +2982,13 @@ function buildTemplateVars(entry, deviceName, zoneLabels) {
2957
2982
  rule: entry.payload.ruleName,
2958
2983
  count: occupancy !== void 0 ? `${occupancy.count}` : "",
2959
2984
  capacity: occupancy !== void 0 ? `${occupancy.capacity}` : "",
2960
- op: occupancy !== void 0 ? occupancyOpWord(occupancy.occupied) : ""
2985
+ op: occupancy !== void 0 ? occupancyOpWord(occupancy.occupied) : "",
2986
+ eventKind: systemEvent?.kind ?? "",
2987
+ subject: systemEvent?.subject ?? "",
2988
+ node: systemEvent?.nodeId ?? "",
2989
+ package: systemEvent?.packageName ?? "",
2990
+ currentVersion: typeof systemEvent?.data["currentVersion"] === "string" ? systemEvent.data["currentVersion"] : "",
2991
+ latestVersion: typeof systemEvent?.data["latestVersion"] === "string" ? systemEvent.data["latestVersion"] : ""
2961
2992
  };
2962
2993
  }
2963
2994
  /** The human-readable edge polarity used by `{{op}}` and the default body. */
@@ -2971,6 +3002,7 @@ function renderTemplate(template, vars) {
2971
3002
  }
2972
3003
  function defaultBody(entry, deviceName, zoneLabels) {
2973
3004
  const subject = entry.payload.subject;
3005
+ if (subject.systemEvent !== void 0) return subject.systemEvent.body;
2974
3006
  const occupancy = subject.occupancy;
2975
3007
  if (occupancy !== void 0) return `${occupancy.zone ?? deviceName} ${occupancyOpWord(occupancy.occupied)} (${occupancy.count}/${occupancy.capacity})`;
2976
3008
  const label = subject.label !== void 0 ? ` (${subject.label})` : "";
@@ -3102,6 +3134,146 @@ function incomingFromOccupancyEdge(edge) {
3102
3134
  })
3103
3135
  };
3104
3136
  }
3137
+ function stringField(data, key) {
3138
+ const value = data[key];
3139
+ return typeof value === "string" && value.length > 0 ? value : void 0;
3140
+ }
3141
+ function numberField(data, key) {
3142
+ const value = data[key];
3143
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
3144
+ }
3145
+ function recordField(data, key) {
3146
+ const value = data[key];
3147
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
3148
+ }
3149
+ function systemSubject(input) {
3150
+ const data = {
3151
+ ...input.event.data,
3152
+ category: input.event.category
3153
+ };
3154
+ const deviceId = input.deviceId ?? 0;
3155
+ const tags = input.deviceId !== void 0 ? { deviceId: input.deviceId } : {};
3156
+ return {
3157
+ kind: "system-event",
3158
+ origin: "system",
3159
+ subject: {
3160
+ kind: "system-event",
3161
+ recordId: input.event.id,
3162
+ deviceId,
3163
+ timestamp: input.event.timestamp.getTime(),
3164
+ classNames: [],
3165
+ zones: [],
3166
+ systemEvent: {
3167
+ kind: input.kind,
3168
+ subject: input.subject,
3169
+ title: input.title,
3170
+ body: input.body,
3171
+ ...input.deviceId !== void 0 ? { deviceId: input.deviceId } : {},
3172
+ ...input.nodeId !== void 0 ? { nodeId: input.nodeId } : {},
3173
+ ...input.packageName !== void 0 ? { packageName: input.packageName } : {},
3174
+ data
3175
+ }
3176
+ },
3177
+ log: () => ({
3178
+ tags,
3179
+ meta: {
3180
+ eventId: input.event.id,
3181
+ category: input.event.category,
3182
+ kind: input.kind,
3183
+ subject: input.subject
3184
+ }
3185
+ })
3186
+ };
3187
+ }
3188
+ /**
3189
+ * Normalize the infrastructure categories consumed by Notification Center.
3190
+ * Malformed payloads are rejected instead of guessing an identity.
3191
+ */
3192
+ function incomingFromSystemEvent(event) {
3193
+ const data = event.data;
3194
+ switch (event.category) {
3195
+ case "device.state-changed": {
3196
+ const deviceId = numberField(data, "deviceId");
3197
+ const capName = stringField(data, "capName");
3198
+ const online = recordField(data, "slice")?.["online"];
3199
+ if (deviceId === void 0 || capName !== "device-status" || typeof online !== "boolean") return null;
3200
+ return systemSubject({
3201
+ event,
3202
+ kind: online ? "camera-online" : "camera-offline",
3203
+ subject: `camera:${deviceId}`,
3204
+ title: online ? "Camera online" : "Camera offline",
3205
+ body: `Camera ${deviceId} is ${online ? "online" : "offline"}`,
3206
+ deviceId
3207
+ });
3208
+ }
3209
+ case "device.online":
3210
+ case "device.offline": {
3211
+ const deviceId = numberField(data, "deviceId");
3212
+ if (deviceId === void 0) return null;
3213
+ const online = event.category === "device.online";
3214
+ return systemSubject({
3215
+ event,
3216
+ kind: online ? "camera-online" : "camera-offline",
3217
+ subject: `camera:${deviceId}`,
3218
+ title: online ? "Camera online" : "Camera offline",
3219
+ body: `Camera ${deviceId} is ${online ? "online" : "offline"}`,
3220
+ deviceId
3221
+ });
3222
+ }
3223
+ case "stream.online":
3224
+ case "stream.offline": {
3225
+ const deviceId = numberField(data, "deviceId");
3226
+ const camStreamId = stringField(data, "camStreamId");
3227
+ if (deviceId === void 0 || camStreamId === void 0) return null;
3228
+ const online = event.category === "stream.online";
3229
+ const profile = stringField(data, "profile");
3230
+ return systemSubject({
3231
+ event,
3232
+ kind: online ? "stream-online" : "stream-offline",
3233
+ subject: `stream:${camStreamId}`,
3234
+ title: online ? "Stream online" : "Stream offline",
3235
+ body: `${profile !== void 0 ? `${profile} stream` : "Stream"} for camera ${deviceId} is ${online ? "online" : "offline"}`,
3236
+ deviceId
3237
+ });
3238
+ }
3239
+ case "agent.online":
3240
+ case "agent.offline":
3241
+ case "worker.online":
3242
+ case "worker.offline": {
3243
+ const agent = event.category.startsWith("agent.");
3244
+ const nodeId = stringField(data, agent ? "agentId" : "workerId");
3245
+ if (nodeId === void 0) return null;
3246
+ const online = event.category.endsWith(".online");
3247
+ return systemSubject({
3248
+ event,
3249
+ kind: online ? "node-online" : "node-offline",
3250
+ subject: `node:${nodeId}`,
3251
+ title: online ? "Node online" : "Node offline",
3252
+ body: `${agent ? "Agent" : "Worker"} ${nodeId} is ${online ? "online" : "offline"}`,
3253
+ nodeId
3254
+ });
3255
+ }
3256
+ case "update.available": {
3257
+ const target = stringField(data, "target");
3258
+ const packageName = stringField(data, "packageName");
3259
+ const currentVersion = stringField(data, "currentVersion");
3260
+ const latestVersion = stringField(data, "latestVersion");
3261
+ if (target !== "addon" && target !== "server" || packageName === void 0 || currentVersion === void 0 || latestVersion === void 0) return null;
3262
+ const addon = target === "addon";
3263
+ const nodeId = stringField(data, "nodeId");
3264
+ return systemSubject({
3265
+ event,
3266
+ kind: addon ? "addon-update-available" : "server-update-available",
3267
+ subject: addon ? `package:${nodeId ?? "hub"}:${packageName}` : `package:${packageName}`,
3268
+ title: addon ? "Addon update available" : "Server update available",
3269
+ body: `${packageName} ${latestVersion} is available (current ${currentVersion})${nodeId !== void 0 ? ` on node ${nodeId}` : ""}`,
3270
+ packageName,
3271
+ ...nodeId !== void 0 ? { nodeId } : {}
3272
+ });
3273
+ }
3274
+ default: return null;
3275
+ }
3276
+ }
3105
3277
  /** Re-stamp a live-producer envelope as a boot-reconcile replay of the same
3106
3278
  * record — same subject, honest origin in the log. */
3107
3279
  function asReconcile(event) {
@@ -3945,7 +4117,8 @@ var OUTBOX_RECORD_KINDS = new Set([
3945
4117
  "track-end",
3946
4118
  "device-event",
3947
4119
  "package-event",
3948
- "audio-event"
4120
+ "audio-event",
4121
+ "system-event"
3949
4122
  ]);
3950
4123
  function isOutboxRecordKind(x) {
3951
4124
  return typeof x === "string" && OUTBOX_RECORD_KINDS.has(x);
@@ -5453,7 +5626,8 @@ function outboxEntryToHistory(entry) {
5453
5626
  ...s.label !== void 0 ? { label: s.label } : {},
5454
5627
  ...s.confidence !== void 0 ? { confidence: s.confidence } : {},
5455
5628
  zones: [...s.zones],
5456
- timestamp: s.timestamp
5629
+ timestamp: s.timestamp,
5630
+ ...s.systemEvent !== void 0 ? { systemEvent: s.systemEvent } : {}
5457
5631
  }
5458
5632
  };
5459
5633
  }
@@ -5502,6 +5676,9 @@ var NotificationCenter = class NotificationCenter {
5502
5676
  /** Same rate-limit pair for the per-camera mute drop — see `reportMutedDrop`. */
5503
5677
  lastMutedReportAt = /* @__PURE__ */ new Map();
5504
5678
  mutedSuppressed = /* @__PURE__ */ new Map();
5679
+ /** Dedupes the explicit liveness category and device-status fallback when
5680
+ * both describe the same edge. */
5681
+ lastSystemLiveness = /* @__PURE__ */ new Map();
5505
5682
  /**
5506
5683
  * Serialized evaluation chain. The persist hooks are fire-and-forget for
5507
5684
  * the frame path, but two concurrent evaluations of the same device
@@ -5979,6 +6156,17 @@ var NotificationCenter = class NotificationCenter {
5979
6156
  onOccupancyEdge(edge) {
5980
6157
  this.consumeEvent(incomingFromOccupancyEdge(edge));
5981
6158
  }
6159
+ /** Event-bus infrastructure/update intake. Invalid payloads are ignored. */
6160
+ onSystemEvent(event) {
6161
+ const incoming = incomingFromSystemEvent(event);
6162
+ if (incoming === null) return;
6163
+ const system = incoming.subject.systemEvent;
6164
+ if (system !== void 0 && (system.kind.startsWith("camera-") || system.kind.startsWith("stream-") || system.kind.startsWith("node-"))) {
6165
+ if (this.lastSystemLiveness.get(system.subject) === system.kind) return;
6166
+ this.lastSystemLiveness.set(system.subject, system.kind);
6167
+ }
6168
+ this.consumeEvent(incoming);
6169
+ }
5982
6170
  buildProvider() {
5983
6171
  return {
5984
6172
  listRules: async () => ({ rules: [...this.rules.list()] }),
@@ -6371,6 +6559,7 @@ var NotificationCenter = class NotificationCenter {
6371
6559
  buildEntries(rule, subject, kind, matchedOn, userTargets = [], origin = "pipeline") {
6372
6560
  const hasEventMedia = kind === "object-event" || kind === "package-event";
6373
6561
  const isTrackScoped = kind === "object-event" || kind === "track-end";
6562
+ const isSystemEvent = kind === "system-event";
6374
6563
  const direct = new Set(rule.targets.map((t) => t.targetId));
6375
6564
  return [...rule.targets, ...userTargets.filter((t) => !direct.has(t.targetId))].filter((target) => !rule.disabledTargetIds.includes(target.targetId)).map((target) => {
6376
6565
  const payload = {
@@ -6379,15 +6568,15 @@ var NotificationCenter = class NotificationCenter {
6379
6568
  ...origin === "synthetic" ? { synthetic: true } : {},
6380
6569
  priority: rule.priority,
6381
6570
  ...rule.template !== void 0 ? { template: rule.template } : {},
6382
- media: rule.media.attach,
6383
- ...rule.media.zoneCrop === true && rule.conditions.zones !== void 0 ? { mediaZoneIds: [...rule.conditions.zones.ids] } : {},
6384
- ...rule.media.frame !== void 0 ? { mediaFrame: rule.media.frame } : {},
6385
- ...rule.media.profile !== void 0 ? { mediaProfile: rule.media.profile } : {},
6386
- ...rule.media.gif === true ? { mediaGif: true } : {},
6387
- ...rule.media.clip === true ? { mediaClip: true } : {},
6388
- ...rule.media.clipPreRollSec !== void 0 ? { mediaClipPreRollSec: rule.media.clipPreRollSec } : {},
6389
- ...rule.media?.clipSpeed !== void 0 ? { mediaClipSpeed: rule.media.clipSpeed } : {},
6390
- ...rule.media.clipPostRollSec !== void 0 ? { mediaClipPostRollSec: rule.media.clipPostRollSec } : {},
6571
+ media: isSystemEvent ? "none" : rule.media.attach,
6572
+ ...!isSystemEvent && rule.media.zoneCrop === true && rule.conditions.zones !== void 0 ? { mediaZoneIds: [...rule.conditions.zones.ids] } : {},
6573
+ ...!isSystemEvent && rule.media.frame !== void 0 ? { mediaFrame: rule.media.frame } : {},
6574
+ ...!isSystemEvent && rule.media.profile !== void 0 ? { mediaProfile: rule.media.profile } : {},
6575
+ ...!isSystemEvent && rule.media.gif === true ? { mediaGif: true } : {},
6576
+ ...!isSystemEvent && rule.media.clip === true ? { mediaClip: true } : {},
6577
+ ...!isSystemEvent && rule.media.clipPreRollSec !== void 0 ? { mediaClipPreRollSec: rule.media.clipPreRollSec } : {},
6578
+ ...!isSystemEvent && rule.media?.clipSpeed !== void 0 ? { mediaClipSpeed: rule.media.clipSpeed } : {},
6579
+ ...!isSystemEvent && rule.media.clipPostRollSec !== void 0 ? { mediaClipPostRollSec: rule.media.clipPostRollSec } : {},
6391
6580
  ...matchedOn !== void 0 && matchedOn.length > 0 ? { matchedOn } : {},
6392
6581
  ...target.params !== void 0 ? { params: target.params } : {},
6393
6582
  subject: {
@@ -6399,7 +6588,8 @@ var NotificationCenter = class NotificationCenter {
6399
6588
  ...subject.confidence !== void 0 ? { confidence: subject.confidence } : {},
6400
6589
  zones: subject.zones,
6401
6590
  timestamp: subject.timestamp,
6402
- ...subject.occupancy !== void 0 ? { occupancy: frozenOccupancy(rule, subject.occupancy) } : {}
6591
+ ...subject.occupancy !== void 0 ? { occupancy: frozenOccupancy(rule, subject.occupancy) } : {},
6592
+ ...subject.systemEvent !== void 0 ? { systemEvent: subject.systemEvent } : {}
6403
6593
  }
6404
6594
  };
6405
6595
  return {
@@ -6476,7 +6666,7 @@ var NotificationCenter = class NotificationCenter {
6476
6666
  for (const entry of entries) {
6477
6667
  const rule = this.rules.get(entry.ruleId);
6478
6668
  if (rule === null) continue;
6479
- const key = rule.throttle.scope === "rule" ? `r:${rule.id}` : `r:${rule.id}:d:${entry.deviceId}`;
6669
+ const key = rule.throttle.scope === "rule" ? `r:${rule.id}` : entry.payload.subject.systemEvent !== void 0 ? `r:${rule.id}:s:${entry.payload.subject.systemEvent.subject}` : `r:${rule.id}:d:${entry.deviceId}`;
6480
6670
  const prev = this.lastFiredAt.get(key) ?? 0;
6481
6671
  if (entry.createdAt > prev) this.lastFiredAt.set(key, entry.createdAt);
6482
6672
  }
@@ -26504,6 +26694,18 @@ function wireSubscriptions(deps) {
26504
26694
  if (nodes === null) return;
26505
26695
  deps.onClusterTopology(nodes);
26506
26696
  }));
26697
+ unsubs.push(deps.eventBus.subscribe({ category: [
26698
+ EventCategory.DeviceOnline,
26699
+ EventCategory.DeviceOffline,
26700
+ EventCategory.DeviceStateChanged,
26701
+ EventCategory.StreamOnline,
26702
+ EventCategory.StreamOffline,
26703
+ EventCategory.AgentOnline,
26704
+ EventCategory.AgentOffline,
26705
+ EventCategory.WorkerOnline,
26706
+ EventCategory.WorkerOffline,
26707
+ EventCategory.UpdateAvailable
26708
+ ] }, (ev) => deps.onSystemEvent(ev)));
26507
26709
  }
26508
26710
  unsubs.push(deps.eventBus.subscribe({ category: EventCategory.DeviceBindingsChanged }, (ev) => {
26509
26711
  deps.onBindingsChanged(ev.data);
@@ -31557,7 +31759,8 @@ var PipelineAnalyticsAddon = class extends BaseAddon {
31557
31759
  onSensorStateChanged: (data, timestampMs) => this.handleSensorStateChanged(data, timestampMs),
31558
31760
  onBindingsChanged: (data) => this.handleBindingsChangedEvent(data),
31559
31761
  onDeviceUnregistered: (deviceId) => this.handleDeviceUnregisteredEvent(deviceId),
31560
- onClusterTopology: (nodes) => this.nodeLiveness.applySnapshot(nodes, Date.now())
31762
+ onClusterTopology: (nodes) => this.nodeLiveness.applySnapshot(nodes, Date.now()),
31763
+ onSystemEvent: (event) => this.notificationCenter?.onSystemEvent(event)
31561
31764
  });
31562
31765
  if (this.isPostProcessingNode) await this.startEmbeddingDispatcher(logger, transport);
31563
31766
  this.startSweepTimers();
@@ -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-CUxRQmzz.mjs")).catch((e) => {
33
+ return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-7Yz3KszP.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.58",
3
+ "version": "1.2.60",
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",