@camstack/addon-post-analysis 1.2.56 → 1.2.59
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-CAC3R7XW.mjs → dist-DqEv8qMO.mjs} +431 -13
- package/dist/{dist-CcS9NwDl.js → dist-VrW5no7b.js} +431 -13
- package/dist/embedding-encoder/index.js +4 -3
- package/dist/embedding-encoder/index.mjs +5 -3
- package/dist/pipeline-analytics/_stub.js +1 -1
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-ABX4r2Sy.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-ChhzqbFf.mjs} +3 -3
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DsSPqkLL.mjs +26 -0
- package/dist/pipeline-analytics/{hostInit-5_dMMZLO.mjs → hostInit-D5KDh5mc.mjs} +3 -3
- package/dist/pipeline-analytics/index.js +249 -56
- package/dist/pipeline-analytics/index.mjs +249 -56
- 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_ui_mf_2_library__loadShare__.js-qqYR0iVH.mjs +0 -26
|
@@ -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-
|
|
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-DqEv8qMO.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 === "
|
|
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
|
-
|
|
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
|
|
2708
|
-
const
|
|
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
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
|
|
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
|
}
|
|
@@ -12531,26 +12721,6 @@ function wideCentralSquareLayout(bbox, frame) {
|
|
|
12531
12721
|
frameOriginX
|
|
12532
12722
|
};
|
|
12533
12723
|
}
|
|
12534
|
-
//#endregion
|
|
12535
|
-
//#region src/shared/frame/subject-crop-variants.ts
|
|
12536
|
-
/**
|
|
12537
|
-
* Best-shot subject-crop variants (best-crop fast-load, 2026-07-21; 16:9
|
|
12538
|
-
* central-square reframe, 2026-07-22).
|
|
12539
|
-
*
|
|
12540
|
-
* ONE native fetch (the 16:9 central-square WINDOW — see
|
|
12541
|
-
* {@link wide-central-square-crop}) backs both persisted variants:
|
|
12542
|
-
* - `thumbnail` — the native uncapped 16:9 window JPEG (subject in the
|
|
12543
|
-
* central square, lateral scene context, never upscaled).
|
|
12544
|
-
* - `thumbnailSmall` — the SAME window downscaled to {@link WIDE_THUMBNAIL_SMALL_MAX_WIDTH}
|
|
12545
|
-
* long side (854×480), the reel / lists / grid fast-load
|
|
12546
|
-
* representative.
|
|
12547
|
-
*
|
|
12548
|
-
* The small variant is DERIVED from the already-composed native window — never a
|
|
12549
|
-
* second native round-trip and NEVER upscaled: if the window is already ≤ 854 on
|
|
12550
|
-
* its long side it is stored AS-IS (byte-identical). The window is composed from
|
|
12551
|
-
* the in-frame slab plus lateral letterbox padding for the (rare) part of the
|
|
12552
|
-
* 16:9 window that falls outside the frame at a horizontal edge.
|
|
12553
|
-
*/
|
|
12554
12724
|
/** Gaussian sigma for the blurred-scene letterbox fill. */
|
|
12555
12725
|
var LETTERBOX_BLUR_SIGMA = 25;
|
|
12556
12726
|
/** Brightness factor for the blurred fill — dimmed so the real slab reads as
|
|
@@ -12596,15 +12766,12 @@ async function composeWideCentralSquareThumbnail(slab, layout) {
|
|
|
12596
12766
|
}
|
|
12597
12767
|
/**
|
|
12598
12768
|
* Derive the `thumbnailSmall` JPEG from the composed native 16:9 window.
|
|
12599
|
-
* Downscales to at most {@link WIDE_THUMBNAIL_SMALL_MAX_WIDTH} (
|
|
12600
|
-
* side (aspect preserved →
|
|
12601
|
-
*
|
|
12769
|
+
* Downscales to at most {@link WIDE_THUMBNAIL_SMALL_MAX_WIDTH} (480) on the long
|
|
12770
|
+
* side (aspect preserved → 480×270) and re-encodes at representative quality.
|
|
12771
|
+
* `withoutEnlargement` preserves smaller sources.
|
|
12602
12772
|
*/
|
|
12603
12773
|
async function deriveThumbnailSmall(nativeWideJpeg) {
|
|
12604
|
-
|
|
12605
|
-
const longSide = Math.max(meta.width ?? 0, meta.height ?? 0);
|
|
12606
|
-
if (longSide > 0 && longSide <= 854) return nativeWideJpeg;
|
|
12607
|
-
return sharp(nativeWideJpeg).resize(854, null, { withoutEnlargement: true }).jpeg({ quality: 88 }).toBuffer();
|
|
12774
|
+
return sharp(nativeWideJpeg).resize(480, null, { withoutEnlargement: true }).jpeg({ quality: 75 }).toBuffer();
|
|
12608
12775
|
}
|
|
12609
12776
|
//#endregion
|
|
12610
12777
|
//#region src/shared/frame/keyframe-wide-thumbnail.ts
|
|
@@ -14858,6 +15025,7 @@ function createEventMediaHandler(deps) {
|
|
|
14858
15025
|
}
|
|
14859
15026
|
const variant = parseEventMediaVariant(query);
|
|
14860
15027
|
const preferKind = parseEventMediaKind(query);
|
|
15028
|
+
const resolveStartedAt = performance.now();
|
|
14861
15029
|
let media = null;
|
|
14862
15030
|
try {
|
|
14863
15031
|
media = await deps.getMedia(eventId, variant ?? void 0, preferKind ?? void 0);
|
|
@@ -14865,21 +15033,24 @@ function createEventMediaHandler(deps) {
|
|
|
14865
15033
|
const body = "Internal server error";
|
|
14866
15034
|
res.writeHead(500, {
|
|
14867
15035
|
"content-type": "text/plain",
|
|
14868
|
-
"content-length": String(Buffer.byteLength(body))
|
|
15036
|
+
"content-length": String(Buffer.byteLength(body)),
|
|
15037
|
+
"server-timing": `resolve;dur=${(performance.now() - resolveStartedAt).toFixed(1)}`
|
|
14869
15038
|
});
|
|
14870
15039
|
if (req.method !== "HEAD") res.end(body);
|
|
14871
15040
|
else res.end();
|
|
14872
15041
|
return;
|
|
14873
15042
|
}
|
|
14874
15043
|
if (media === null) {
|
|
14875
|
-
res.writeHead(404).end();
|
|
15044
|
+
res.writeHead(404, { "server-timing": `resolve;dur=${(performance.now() - resolveStartedAt).toFixed(1)}` }).end();
|
|
14876
15045
|
return;
|
|
14877
15046
|
}
|
|
14878
15047
|
const etag = "\"" + media.key + "\"";
|
|
15048
|
+
const serverTiming = `resolve;dur=${(performance.now() - resolveStartedAt).toFixed(1)}`;
|
|
14879
15049
|
if (req.headers["if-none-match"] === etag) {
|
|
14880
15050
|
res.writeHead(304, {
|
|
14881
15051
|
etag,
|
|
14882
|
-
"cache-control": CACHE_CONTROL
|
|
15052
|
+
"cache-control": CACHE_CONTROL,
|
|
15053
|
+
"server-timing": serverTiming
|
|
14883
15054
|
}).end();
|
|
14884
15055
|
return;
|
|
14885
15056
|
}
|
|
@@ -14887,7 +15058,8 @@ function createEventMediaHandler(deps) {
|
|
|
14887
15058
|
"content-type": "image/jpeg",
|
|
14888
15059
|
"cache-control": CACHE_CONTROL,
|
|
14889
15060
|
etag,
|
|
14890
|
-
"content-length": String(media.bytes.byteLength)
|
|
15061
|
+
"content-length": String(media.bytes.byteLength),
|
|
15062
|
+
"server-timing": serverTiming
|
|
14891
15063
|
});
|
|
14892
15064
|
if (req.method === "HEAD") res.end();
|
|
14893
15065
|
else res.end(Buffer.from(media.bytes));
|
|
@@ -26522,6 +26694,18 @@ function wireSubscriptions(deps) {
|
|
|
26522
26694
|
if (nodes === null) return;
|
|
26523
26695
|
deps.onClusterTopology(nodes);
|
|
26524
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)));
|
|
26525
26709
|
}
|
|
26526
26710
|
unsubs.push(deps.eventBus.subscribe({ category: EventCategory.DeviceBindingsChanged }, (ev) => {
|
|
26527
26711
|
deps.onBindingsChanged(ev.data);
|
|
@@ -27614,9 +27798,9 @@ var EventMediaDispatcher = class {
|
|
|
27614
27798
|
* the runner's retained native surface with NO `maxWidth` (uncapped TRUE
|
|
27615
27799
|
* native). It is composed into the full 16:9 window (lateral letterbox only for
|
|
27616
27800
|
* the part outside the frame) → the `thumbnail`. The `thumbnailSmall` is
|
|
27617
|
-
* DERIVED by downscaling that SAME window to the
|
|
27801
|
+
* DERIVED by downscaling that SAME window to the 480 long-side cap (480×270) —
|
|
27618
27802
|
* never a second `getNativeCropJpeg`, never upscaled ({@link deriveThumbnailSmall}
|
|
27619
|
-
*
|
|
27803
|
+
* never upscales a smaller window).
|
|
27620
27804
|
*
|
|
27621
27805
|
* Both variants share the SAME framing + central-square containment guarantee:
|
|
27622
27806
|
* wide consumers use the 16:9 image as-is (subject centered, no cut); square
|
|
@@ -30875,6 +31059,7 @@ var MOTION_EVENT_HEARTBEAT_MS = 5e3;
|
|
|
30875
31059
|
var CLEAN_MEDIA_KINDS = [
|
|
30876
31060
|
"crop",
|
|
30877
31061
|
"thumbnail",
|
|
31062
|
+
"thumbnailSmall",
|
|
30878
31063
|
"fullFrame",
|
|
30879
31064
|
"keyFrame",
|
|
30880
31065
|
"keyFrameSmall"
|
|
@@ -31574,7 +31759,8 @@ var PipelineAnalyticsAddon = class extends BaseAddon {
|
|
|
31574
31759
|
onSensorStateChanged: (data, timestampMs) => this.handleSensorStateChanged(data, timestampMs),
|
|
31575
31760
|
onBindingsChanged: (data) => this.handleBindingsChangedEvent(data),
|
|
31576
31761
|
onDeviceUnregistered: (deviceId) => this.handleDeviceUnregisteredEvent(deviceId),
|
|
31577
|
-
onClusterTopology: (nodes) => this.nodeLiveness.applySnapshot(nodes, Date.now())
|
|
31762
|
+
onClusterTopology: (nodes) => this.nodeLiveness.applySnapshot(nodes, Date.now()),
|
|
31763
|
+
onSystemEvent: (event) => this.notificationCenter?.onSystemEvent(event)
|
|
31578
31764
|
});
|
|
31579
31765
|
if (this.isPostProcessingNode) await this.startEmbeddingDispatcher(logger, transport);
|
|
31580
31766
|
this.startSweepTimers();
|
|
@@ -36213,6 +36399,7 @@ var PipelineAnalyticsAddon = class extends BaseAddon {
|
|
|
36213
36399
|
* failure the full blob is served (a thumb must never 500 / blank a tile).
|
|
36214
36400
|
*/
|
|
36215
36401
|
async applyThumbVariant(media, variant) {
|
|
36402
|
+
if (media.key.includes(":thumbnailSmall") && media.bytes.byteLength <= 64 * 1024) return media;
|
|
36216
36403
|
try {
|
|
36217
36404
|
return {
|
|
36218
36405
|
bytes: await makeSquareThumb(media.bytes, variant.size),
|
|
@@ -36231,7 +36418,13 @@ var PipelineAnalyticsAddon = class extends BaseAddon {
|
|
|
36231
36418
|
const eventFiles = await (this.mediaStore?.listByOwner("event", id) ?? Promise.resolve([]));
|
|
36232
36419
|
if (preferKind !== void 0 && preferKind.length > 0) {
|
|
36233
36420
|
const trackFiles = await (this.mediaStore?.listByOwner("track", id) ?? Promise.resolve([]));
|
|
36234
|
-
const
|
|
36421
|
+
const ownerTrackId = trackFiles.length === 0 ? await (this.eventStore?.getTrackIdForEvent(id) ?? Promise.resolve(null)) : null;
|
|
36422
|
+
const owningTrackFiles = ownerTrackId === null ? [] : await (this.mediaStore?.listByOwner("track", ownerTrackId) ?? Promise.resolve([]));
|
|
36423
|
+
const chosen = resolveCropForcedMedia([
|
|
36424
|
+
...eventFiles,
|
|
36425
|
+
...trackFiles,
|
|
36426
|
+
...owningTrackFiles
|
|
36427
|
+
], (files) => pickCleanMedia(files, preferKind));
|
|
36235
36428
|
if (!chosen) return null;
|
|
36236
36429
|
return {
|
|
36237
36430
|
bytes: Buffer.from(chosen.base64, "base64"),
|
|
@@ -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-ChhzqbFf.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.59",
|
|
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",
|