@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
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
5
|
+
const require_dist = require("../dist-VrW5no7b.js");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
7
|
node_fs = require_dist.__toESM(node_fs, 1);
|
|
8
8
|
let node_path = require("node:path");
|
|
@@ -2047,6 +2047,7 @@ function fail(condition) {
|
|
|
2047
2047
|
*/
|
|
2048
2048
|
function presentConditionIds(c) {
|
|
2049
2049
|
const ids = [];
|
|
2050
|
+
if (c.systemEvent !== void 0) ids.push("systemEvent");
|
|
2050
2051
|
if (c.devices !== void 0 && c.devices.length > 0) ids.push("devices");
|
|
2051
2052
|
if (c.source !== void 0 && c.source !== "any") ids.push("source");
|
|
2052
2053
|
if (c.classes !== void 0 && c.classes.length > 0) ids.push("classes");
|
|
@@ -2140,19 +2141,34 @@ function referencesAudioClass(classes) {
|
|
|
2140
2141
|
if (classes === void 0) return false;
|
|
2141
2142
|
return classes.some((c) => c.trim().toLowerCase().startsWith("audio-"));
|
|
2142
2143
|
}
|
|
2144
|
+
function matchesSystemEvent(condition, subject) {
|
|
2145
|
+
if (!condition.kinds.includes(subject.kind)) return false;
|
|
2146
|
+
if (condition.deviceIds !== void 0 && (subject.deviceId === void 0 || !condition.deviceIds.includes(subject.deviceId))) return false;
|
|
2147
|
+
if (condition.nodeIds !== void 0 && (subject.nodeId === void 0 || !condition.nodeIds.includes(subject.nodeId))) return false;
|
|
2148
|
+
if (condition.packageNames !== void 0 && (subject.packageName === void 0 || !condition.packageNames.includes(subject.packageName))) return false;
|
|
2149
|
+
return true;
|
|
2150
|
+
}
|
|
2143
2151
|
function evaluateRule(rule, subject, deviceState) {
|
|
2144
|
-
if (subject.kind === "
|
|
2152
|
+
if (subject.kind === "system-event") {
|
|
2153
|
+
if (rule.delivery !== "system-event") return fail("delivery");
|
|
2154
|
+
const condition = rule.conditions.systemEvent;
|
|
2155
|
+
if (condition === void 0 || subject.systemEvent === void 0 || !matchesSystemEvent(condition, subject.systemEvent)) return fail("systemEvent");
|
|
2156
|
+
if (rule.conditions.occupancy !== void 0) return fail("occupancy");
|
|
2157
|
+
} else if (subject.kind === "occupancy-event") {
|
|
2145
2158
|
if (rule.delivery !== "device-event") return fail("delivery");
|
|
2146
2159
|
const occ = rule.conditions.occupancy;
|
|
2147
2160
|
if (occ === void 0) return fail("occupancy");
|
|
2148
2161
|
if (subject.occupancy === void 0 || !matchesOccupancy(occ, subject.occupancy)) return fail("occupancy");
|
|
2162
|
+
if (rule.conditions.systemEvent !== void 0) return fail("systemEvent");
|
|
2149
2163
|
} else if (subject.kind === "audio-event") {
|
|
2150
2164
|
if (rule.delivery !== "immediate") return fail("delivery");
|
|
2151
2165
|
if (!referencesAudioClass(rule.conditions.classes)) return fail("classes");
|
|
2152
2166
|
if (rule.conditions.occupancy !== void 0) return fail("occupancy");
|
|
2167
|
+
if (rule.conditions.systemEvent !== void 0) return fail("systemEvent");
|
|
2153
2168
|
} else {
|
|
2154
2169
|
if ((rule.delivery === "immediate" ? "object-event" : rule.delivery) !== subject.kind) return fail("delivery");
|
|
2155
2170
|
if (rule.conditions.occupancy !== void 0) return fail("occupancy");
|
|
2171
|
+
if (rule.conditions.systemEvent !== void 0) return fail("systemEvent");
|
|
2156
2172
|
}
|
|
2157
2173
|
const c = rule.conditions;
|
|
2158
2174
|
if (c.deviceState !== void 0) {
|
|
@@ -2312,7 +2328,8 @@ function matchesDeviceScope(scope, subject) {
|
|
|
2312
2328
|
function cooldownKey(rule, subject) {
|
|
2313
2329
|
const first = subject.classNames[0];
|
|
2314
2330
|
const classKey = keysPerClass(rule, subject) && first !== void 0 ? `:c:${first}` : "";
|
|
2315
|
-
|
|
2331
|
+
const scopeRef = subject.systemEvent !== void 0 ? `s:${subject.systemEvent.subject}` : `d:${subject.deviceId}`;
|
|
2332
|
+
return rule.throttle.scope === "rule" ? `r:${rule.id}${classKey}` : `r:${rule.id}:${scopeRef}${classKey}`;
|
|
2316
2333
|
}
|
|
2317
2334
|
/** True when the rule fired within its cooldown window before `now`. */
|
|
2318
2335
|
function isCoolingDown(rule, lastFiredAt, now) {
|
|
@@ -2709,10 +2726,12 @@ var NcDispatcher = class {
|
|
|
2709
2726
|
}
|
|
2710
2727
|
async buildNotification(entry, target) {
|
|
2711
2728
|
const subject = entry.payload.subject;
|
|
2712
|
-
const
|
|
2713
|
-
const
|
|
2729
|
+
const systemEvent = subject.systemEvent;
|
|
2730
|
+
const displayDeviceId = systemEvent?.deviceId ?? subject.deviceId;
|
|
2731
|
+
const deviceName = systemEvent !== void 0 && systemEvent.deviceId === void 0 ? "system" : await this.deps.getDeviceName(displayDeviceId).catch(() => null) ?? `camera ${displayDeviceId}`;
|
|
2732
|
+
const zoneLabels = systemEvent !== void 0 ? [] : await resolveZoneLabels(this.deps.getZoneNames, subject.deviceId, subject.zones);
|
|
2714
2733
|
const vars = buildTemplateVars(entry, deviceName, zoneLabels);
|
|
2715
|
-
const title = renderTemplate(entry.payload.template?.title, vars) ?? entry.payload.ruleName;
|
|
2734
|
+
const title = renderTemplate(entry.payload.template?.title, vars) ?? systemEvent?.title ?? entry.payload.ruleName;
|
|
2716
2735
|
const body = renderTemplate(entry.payload.template?.body, vars) ?? defaultBody(entry, deviceName, zoneLabels);
|
|
2717
2736
|
const attachments = await this.withArtifactUrls(await this.resolveAttachments(entry));
|
|
2718
2737
|
const params = pickParams(entry.payload.params);
|
|
@@ -2723,8 +2742,13 @@ var NcDispatcher = class {
|
|
|
2723
2742
|
priority: clampPriority(paramNumber(entry.payload.params, "priority") ?? entry.payload.priority),
|
|
2724
2743
|
...params,
|
|
2725
2744
|
tag: entry.ruleId,
|
|
2726
|
-
deviceId: subject.deviceId,
|
|
2745
|
+
...systemEvent !== void 0 ? systemEvent.deviceId !== void 0 ? { deviceId: systemEvent.deviceId } : {} : { deviceId: subject.deviceId },
|
|
2727
2746
|
...subject.eventId !== void 0 ? { eventId: subject.eventId } : {},
|
|
2747
|
+
...systemEvent !== void 0 ? { metadata: {
|
|
2748
|
+
systemEventKind: systemEvent.kind,
|
|
2749
|
+
subject: systemEvent.subject,
|
|
2750
|
+
...systemEvent.data
|
|
2751
|
+
} } : {},
|
|
2728
2752
|
...attachments.length > 0 ? { attachments } : {},
|
|
2729
2753
|
...actions.length > 0 ? { actions } : {}
|
|
2730
2754
|
};
|
|
@@ -2951,6 +2975,7 @@ async function resolveZoneLabels(getZoneNames, deviceId, zoneIds) {
|
|
|
2951
2975
|
function buildTemplateVars(entry, deviceName, zoneLabels) {
|
|
2952
2976
|
const subject = entry.payload.subject;
|
|
2953
2977
|
const occupancy = subject.occupancy;
|
|
2978
|
+
const systemEvent = subject.systemEvent;
|
|
2954
2979
|
return {
|
|
2955
2980
|
camera: deviceName,
|
|
2956
2981
|
class: subject.className,
|
|
@@ -2962,7 +2987,13 @@ function buildTemplateVars(entry, deviceName, zoneLabels) {
|
|
|
2962
2987
|
rule: entry.payload.ruleName,
|
|
2963
2988
|
count: occupancy !== void 0 ? `${occupancy.count}` : "",
|
|
2964
2989
|
capacity: occupancy !== void 0 ? `${occupancy.capacity}` : "",
|
|
2965
|
-
op: occupancy !== void 0 ? occupancyOpWord(occupancy.occupied) : ""
|
|
2990
|
+
op: occupancy !== void 0 ? occupancyOpWord(occupancy.occupied) : "",
|
|
2991
|
+
eventKind: systemEvent?.kind ?? "",
|
|
2992
|
+
subject: systemEvent?.subject ?? "",
|
|
2993
|
+
node: systemEvent?.nodeId ?? "",
|
|
2994
|
+
package: systemEvent?.packageName ?? "",
|
|
2995
|
+
currentVersion: typeof systemEvent?.data["currentVersion"] === "string" ? systemEvent.data["currentVersion"] : "",
|
|
2996
|
+
latestVersion: typeof systemEvent?.data["latestVersion"] === "string" ? systemEvent.data["latestVersion"] : ""
|
|
2966
2997
|
};
|
|
2967
2998
|
}
|
|
2968
2999
|
/** The human-readable edge polarity used by `{{op}}` and the default body. */
|
|
@@ -2976,6 +3007,7 @@ function renderTemplate(template, vars) {
|
|
|
2976
3007
|
}
|
|
2977
3008
|
function defaultBody(entry, deviceName, zoneLabels) {
|
|
2978
3009
|
const subject = entry.payload.subject;
|
|
3010
|
+
if (subject.systemEvent !== void 0) return subject.systemEvent.body;
|
|
2979
3011
|
const occupancy = subject.occupancy;
|
|
2980
3012
|
if (occupancy !== void 0) return `${occupancy.zone ?? deviceName} ${occupancyOpWord(occupancy.occupied)} (${occupancy.count}/${occupancy.capacity})`;
|
|
2981
3013
|
const label = subject.label !== void 0 ? ` (${subject.label})` : "";
|
|
@@ -3107,6 +3139,146 @@ function incomingFromOccupancyEdge(edge) {
|
|
|
3107
3139
|
})
|
|
3108
3140
|
};
|
|
3109
3141
|
}
|
|
3142
|
+
function stringField(data, key) {
|
|
3143
|
+
const value = data[key];
|
|
3144
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
3145
|
+
}
|
|
3146
|
+
function numberField(data, key) {
|
|
3147
|
+
const value = data[key];
|
|
3148
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
3149
|
+
}
|
|
3150
|
+
function recordField(data, key) {
|
|
3151
|
+
const value = data[key];
|
|
3152
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
3153
|
+
}
|
|
3154
|
+
function systemSubject(input) {
|
|
3155
|
+
const data = {
|
|
3156
|
+
...input.event.data,
|
|
3157
|
+
category: input.event.category
|
|
3158
|
+
};
|
|
3159
|
+
const deviceId = input.deviceId ?? 0;
|
|
3160
|
+
const tags = input.deviceId !== void 0 ? { deviceId: input.deviceId } : {};
|
|
3161
|
+
return {
|
|
3162
|
+
kind: "system-event",
|
|
3163
|
+
origin: "system",
|
|
3164
|
+
subject: {
|
|
3165
|
+
kind: "system-event",
|
|
3166
|
+
recordId: input.event.id,
|
|
3167
|
+
deviceId,
|
|
3168
|
+
timestamp: input.event.timestamp.getTime(),
|
|
3169
|
+
classNames: [],
|
|
3170
|
+
zones: [],
|
|
3171
|
+
systemEvent: {
|
|
3172
|
+
kind: input.kind,
|
|
3173
|
+
subject: input.subject,
|
|
3174
|
+
title: input.title,
|
|
3175
|
+
body: input.body,
|
|
3176
|
+
...input.deviceId !== void 0 ? { deviceId: input.deviceId } : {},
|
|
3177
|
+
...input.nodeId !== void 0 ? { nodeId: input.nodeId } : {},
|
|
3178
|
+
...input.packageName !== void 0 ? { packageName: input.packageName } : {},
|
|
3179
|
+
data
|
|
3180
|
+
}
|
|
3181
|
+
},
|
|
3182
|
+
log: () => ({
|
|
3183
|
+
tags,
|
|
3184
|
+
meta: {
|
|
3185
|
+
eventId: input.event.id,
|
|
3186
|
+
category: input.event.category,
|
|
3187
|
+
kind: input.kind,
|
|
3188
|
+
subject: input.subject
|
|
3189
|
+
}
|
|
3190
|
+
})
|
|
3191
|
+
};
|
|
3192
|
+
}
|
|
3193
|
+
/**
|
|
3194
|
+
* Normalize the infrastructure categories consumed by Notification Center.
|
|
3195
|
+
* Malformed payloads are rejected instead of guessing an identity.
|
|
3196
|
+
*/
|
|
3197
|
+
function incomingFromSystemEvent(event) {
|
|
3198
|
+
const data = event.data;
|
|
3199
|
+
switch (event.category) {
|
|
3200
|
+
case "device.state-changed": {
|
|
3201
|
+
const deviceId = numberField(data, "deviceId");
|
|
3202
|
+
const capName = stringField(data, "capName");
|
|
3203
|
+
const online = recordField(data, "slice")?.["online"];
|
|
3204
|
+
if (deviceId === void 0 || capName !== "device-status" || typeof online !== "boolean") return null;
|
|
3205
|
+
return systemSubject({
|
|
3206
|
+
event,
|
|
3207
|
+
kind: online ? "camera-online" : "camera-offline",
|
|
3208
|
+
subject: `camera:${deviceId}`,
|
|
3209
|
+
title: online ? "Camera online" : "Camera offline",
|
|
3210
|
+
body: `Camera ${deviceId} is ${online ? "online" : "offline"}`,
|
|
3211
|
+
deviceId
|
|
3212
|
+
});
|
|
3213
|
+
}
|
|
3214
|
+
case "device.online":
|
|
3215
|
+
case "device.offline": {
|
|
3216
|
+
const deviceId = numberField(data, "deviceId");
|
|
3217
|
+
if (deviceId === void 0) return null;
|
|
3218
|
+
const online = event.category === "device.online";
|
|
3219
|
+
return systemSubject({
|
|
3220
|
+
event,
|
|
3221
|
+
kind: online ? "camera-online" : "camera-offline",
|
|
3222
|
+
subject: `camera:${deviceId}`,
|
|
3223
|
+
title: online ? "Camera online" : "Camera offline",
|
|
3224
|
+
body: `Camera ${deviceId} is ${online ? "online" : "offline"}`,
|
|
3225
|
+
deviceId
|
|
3226
|
+
});
|
|
3227
|
+
}
|
|
3228
|
+
case "stream.online":
|
|
3229
|
+
case "stream.offline": {
|
|
3230
|
+
const deviceId = numberField(data, "deviceId");
|
|
3231
|
+
const camStreamId = stringField(data, "camStreamId");
|
|
3232
|
+
if (deviceId === void 0 || camStreamId === void 0) return null;
|
|
3233
|
+
const online = event.category === "stream.online";
|
|
3234
|
+
const profile = stringField(data, "profile");
|
|
3235
|
+
return systemSubject({
|
|
3236
|
+
event,
|
|
3237
|
+
kind: online ? "stream-online" : "stream-offline",
|
|
3238
|
+
subject: `stream:${camStreamId}`,
|
|
3239
|
+
title: online ? "Stream online" : "Stream offline",
|
|
3240
|
+
body: `${profile !== void 0 ? `${profile} stream` : "Stream"} for camera ${deviceId} is ${online ? "online" : "offline"}`,
|
|
3241
|
+
deviceId
|
|
3242
|
+
});
|
|
3243
|
+
}
|
|
3244
|
+
case "agent.online":
|
|
3245
|
+
case "agent.offline":
|
|
3246
|
+
case "worker.online":
|
|
3247
|
+
case "worker.offline": {
|
|
3248
|
+
const agent = event.category.startsWith("agent.");
|
|
3249
|
+
const nodeId = stringField(data, agent ? "agentId" : "workerId");
|
|
3250
|
+
if (nodeId === void 0) return null;
|
|
3251
|
+
const online = event.category.endsWith(".online");
|
|
3252
|
+
return systemSubject({
|
|
3253
|
+
event,
|
|
3254
|
+
kind: online ? "node-online" : "node-offline",
|
|
3255
|
+
subject: `node:${nodeId}`,
|
|
3256
|
+
title: online ? "Node online" : "Node offline",
|
|
3257
|
+
body: `${agent ? "Agent" : "Worker"} ${nodeId} is ${online ? "online" : "offline"}`,
|
|
3258
|
+
nodeId
|
|
3259
|
+
});
|
|
3260
|
+
}
|
|
3261
|
+
case "update.available": {
|
|
3262
|
+
const target = stringField(data, "target");
|
|
3263
|
+
const packageName = stringField(data, "packageName");
|
|
3264
|
+
const currentVersion = stringField(data, "currentVersion");
|
|
3265
|
+
const latestVersion = stringField(data, "latestVersion");
|
|
3266
|
+
if (target !== "addon" && target !== "server" || packageName === void 0 || currentVersion === void 0 || latestVersion === void 0) return null;
|
|
3267
|
+
const addon = target === "addon";
|
|
3268
|
+
const nodeId = stringField(data, "nodeId");
|
|
3269
|
+
return systemSubject({
|
|
3270
|
+
event,
|
|
3271
|
+
kind: addon ? "addon-update-available" : "server-update-available",
|
|
3272
|
+
subject: addon ? `package:${nodeId ?? "hub"}:${packageName}` : `package:${packageName}`,
|
|
3273
|
+
title: addon ? "Addon update available" : "Server update available",
|
|
3274
|
+
body: `${packageName} ${latestVersion} is available (current ${currentVersion})${nodeId !== void 0 ? ` on node ${nodeId}` : ""}`,
|
|
3275
|
+
packageName,
|
|
3276
|
+
...nodeId !== void 0 ? { nodeId } : {}
|
|
3277
|
+
});
|
|
3278
|
+
}
|
|
3279
|
+
default: return null;
|
|
3280
|
+
}
|
|
3281
|
+
}
|
|
3110
3282
|
/** Re-stamp a live-producer envelope as a boot-reconcile replay of the same
|
|
3111
3283
|
* record — same subject, honest origin in the log. */
|
|
3112
3284
|
function asReconcile(event) {
|
|
@@ -3950,7 +4122,8 @@ var OUTBOX_RECORD_KINDS = new Set([
|
|
|
3950
4122
|
"track-end",
|
|
3951
4123
|
"device-event",
|
|
3952
4124
|
"package-event",
|
|
3953
|
-
"audio-event"
|
|
4125
|
+
"audio-event",
|
|
4126
|
+
"system-event"
|
|
3954
4127
|
]);
|
|
3955
4128
|
function isOutboxRecordKind(x) {
|
|
3956
4129
|
return typeof x === "string" && OUTBOX_RECORD_KINDS.has(x);
|
|
@@ -5466,7 +5639,8 @@ function outboxEntryToHistory(entry) {
|
|
|
5466
5639
|
...s.label !== void 0 ? { label: s.label } : {},
|
|
5467
5640
|
...s.confidence !== void 0 ? { confidence: s.confidence } : {},
|
|
5468
5641
|
zones: [...s.zones],
|
|
5469
|
-
timestamp: s.timestamp
|
|
5642
|
+
timestamp: s.timestamp,
|
|
5643
|
+
...s.systemEvent !== void 0 ? { systemEvent: s.systemEvent } : {}
|
|
5470
5644
|
}
|
|
5471
5645
|
};
|
|
5472
5646
|
}
|
|
@@ -5515,6 +5689,9 @@ var NotificationCenter = class NotificationCenter {
|
|
|
5515
5689
|
/** Same rate-limit pair for the per-camera mute drop — see `reportMutedDrop`. */
|
|
5516
5690
|
lastMutedReportAt = /* @__PURE__ */ new Map();
|
|
5517
5691
|
mutedSuppressed = /* @__PURE__ */ new Map();
|
|
5692
|
+
/** Dedupes the explicit liveness category and device-status fallback when
|
|
5693
|
+
* both describe the same edge. */
|
|
5694
|
+
lastSystemLiveness = /* @__PURE__ */ new Map();
|
|
5518
5695
|
/**
|
|
5519
5696
|
* Serialized evaluation chain. The persist hooks are fire-and-forget for
|
|
5520
5697
|
* the frame path, but two concurrent evaluations of the same device
|
|
@@ -5992,6 +6169,17 @@ var NotificationCenter = class NotificationCenter {
|
|
|
5992
6169
|
onOccupancyEdge(edge) {
|
|
5993
6170
|
this.consumeEvent(incomingFromOccupancyEdge(edge));
|
|
5994
6171
|
}
|
|
6172
|
+
/** Event-bus infrastructure/update intake. Invalid payloads are ignored. */
|
|
6173
|
+
onSystemEvent(event) {
|
|
6174
|
+
const incoming = incomingFromSystemEvent(event);
|
|
6175
|
+
if (incoming === null) return;
|
|
6176
|
+
const system = incoming.subject.systemEvent;
|
|
6177
|
+
if (system !== void 0 && (system.kind.startsWith("camera-") || system.kind.startsWith("stream-") || system.kind.startsWith("node-"))) {
|
|
6178
|
+
if (this.lastSystemLiveness.get(system.subject) === system.kind) return;
|
|
6179
|
+
this.lastSystemLiveness.set(system.subject, system.kind);
|
|
6180
|
+
}
|
|
6181
|
+
this.consumeEvent(incoming);
|
|
6182
|
+
}
|
|
5995
6183
|
buildProvider() {
|
|
5996
6184
|
return {
|
|
5997
6185
|
listRules: async () => ({ rules: [...this.rules.list()] }),
|
|
@@ -6384,6 +6572,7 @@ var NotificationCenter = class NotificationCenter {
|
|
|
6384
6572
|
buildEntries(rule, subject, kind, matchedOn, userTargets = [], origin = "pipeline") {
|
|
6385
6573
|
const hasEventMedia = kind === "object-event" || kind === "package-event";
|
|
6386
6574
|
const isTrackScoped = kind === "object-event" || kind === "track-end";
|
|
6575
|
+
const isSystemEvent = kind === "system-event";
|
|
6387
6576
|
const direct = new Set(rule.targets.map((t) => t.targetId));
|
|
6388
6577
|
return [...rule.targets, ...userTargets.filter((t) => !direct.has(t.targetId))].filter((target) => !rule.disabledTargetIds.includes(target.targetId)).map((target) => {
|
|
6389
6578
|
const payload = {
|
|
@@ -6392,15 +6581,15 @@ var NotificationCenter = class NotificationCenter {
|
|
|
6392
6581
|
...origin === "synthetic" ? { synthetic: true } : {},
|
|
6393
6582
|
priority: rule.priority,
|
|
6394
6583
|
...rule.template !== void 0 ? { template: rule.template } : {},
|
|
6395
|
-
media: rule.media.attach,
|
|
6396
|
-
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6584
|
+
media: isSystemEvent ? "none" : rule.media.attach,
|
|
6585
|
+
...!isSystemEvent && rule.media.zoneCrop === true && rule.conditions.zones !== void 0 ? { mediaZoneIds: [...rule.conditions.zones.ids] } : {},
|
|
6586
|
+
...!isSystemEvent && rule.media.frame !== void 0 ? { mediaFrame: rule.media.frame } : {},
|
|
6587
|
+
...!isSystemEvent && rule.media.profile !== void 0 ? { mediaProfile: rule.media.profile } : {},
|
|
6588
|
+
...!isSystemEvent && rule.media.gif === true ? { mediaGif: true } : {},
|
|
6589
|
+
...!isSystemEvent && rule.media.clip === true ? { mediaClip: true } : {},
|
|
6590
|
+
...!isSystemEvent && rule.media.clipPreRollSec !== void 0 ? { mediaClipPreRollSec: rule.media.clipPreRollSec } : {},
|
|
6591
|
+
...!isSystemEvent && rule.media?.clipSpeed !== void 0 ? { mediaClipSpeed: rule.media.clipSpeed } : {},
|
|
6592
|
+
...!isSystemEvent && rule.media.clipPostRollSec !== void 0 ? { mediaClipPostRollSec: rule.media.clipPostRollSec } : {},
|
|
6404
6593
|
...matchedOn !== void 0 && matchedOn.length > 0 ? { matchedOn } : {},
|
|
6405
6594
|
...target.params !== void 0 ? { params: target.params } : {},
|
|
6406
6595
|
subject: {
|
|
@@ -6412,7 +6601,8 @@ var NotificationCenter = class NotificationCenter {
|
|
|
6412
6601
|
...subject.confidence !== void 0 ? { confidence: subject.confidence } : {},
|
|
6413
6602
|
zones: subject.zones,
|
|
6414
6603
|
timestamp: subject.timestamp,
|
|
6415
|
-
...subject.occupancy !== void 0 ? { occupancy: frozenOccupancy(rule, subject.occupancy) } : {}
|
|
6604
|
+
...subject.occupancy !== void 0 ? { occupancy: frozenOccupancy(rule, subject.occupancy) } : {},
|
|
6605
|
+
...subject.systemEvent !== void 0 ? { systemEvent: subject.systemEvent } : {}
|
|
6416
6606
|
}
|
|
6417
6607
|
};
|
|
6418
6608
|
return {
|
|
@@ -6489,7 +6679,7 @@ var NotificationCenter = class NotificationCenter {
|
|
|
6489
6679
|
for (const entry of entries) {
|
|
6490
6680
|
const rule = this.rules.get(entry.ruleId);
|
|
6491
6681
|
if (rule === null) continue;
|
|
6492
|
-
const key = rule.throttle.scope === "rule" ? `r:${rule.id}` : `r:${rule.id}:d:${entry.deviceId}`;
|
|
6682
|
+
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}`;
|
|
6493
6683
|
const prev = this.lastFiredAt.get(key) ?? 0;
|
|
6494
6684
|
if (entry.createdAt > prev) this.lastFiredAt.set(key, entry.createdAt);
|
|
6495
6685
|
}
|
|
@@ -12544,26 +12734,6 @@ function wideCentralSquareLayout(bbox, frame) {
|
|
|
12544
12734
|
frameOriginX
|
|
12545
12735
|
};
|
|
12546
12736
|
}
|
|
12547
|
-
//#endregion
|
|
12548
|
-
//#region src/shared/frame/subject-crop-variants.ts
|
|
12549
|
-
/**
|
|
12550
|
-
* Best-shot subject-crop variants (best-crop fast-load, 2026-07-21; 16:9
|
|
12551
|
-
* central-square reframe, 2026-07-22).
|
|
12552
|
-
*
|
|
12553
|
-
* ONE native fetch (the 16:9 central-square WINDOW — see
|
|
12554
|
-
* {@link wide-central-square-crop}) backs both persisted variants:
|
|
12555
|
-
* - `thumbnail` — the native uncapped 16:9 window JPEG (subject in the
|
|
12556
|
-
* central square, lateral scene context, never upscaled).
|
|
12557
|
-
* - `thumbnailSmall` — the SAME window downscaled to {@link WIDE_THUMBNAIL_SMALL_MAX_WIDTH}
|
|
12558
|
-
* long side (854×480), the reel / lists / grid fast-load
|
|
12559
|
-
* representative.
|
|
12560
|
-
*
|
|
12561
|
-
* The small variant is DERIVED from the already-composed native window — never a
|
|
12562
|
-
* second native round-trip and NEVER upscaled: if the window is already ≤ 854 on
|
|
12563
|
-
* its long side it is stored AS-IS (byte-identical). The window is composed from
|
|
12564
|
-
* the in-frame slab plus lateral letterbox padding for the (rare) part of the
|
|
12565
|
-
* 16:9 window that falls outside the frame at a horizontal edge.
|
|
12566
|
-
*/
|
|
12567
12737
|
/** Gaussian sigma for the blurred-scene letterbox fill. */
|
|
12568
12738
|
var LETTERBOX_BLUR_SIGMA = 25;
|
|
12569
12739
|
/** Brightness factor for the blurred fill — dimmed so the real slab reads as
|
|
@@ -12609,15 +12779,12 @@ async function composeWideCentralSquareThumbnail(slab, layout) {
|
|
|
12609
12779
|
}
|
|
12610
12780
|
/**
|
|
12611
12781
|
* Derive the `thumbnailSmall` JPEG from the composed native 16:9 window.
|
|
12612
|
-
* Downscales to at most {@link WIDE_THUMBNAIL_SMALL_MAX_WIDTH} (
|
|
12613
|
-
* side (aspect preserved →
|
|
12614
|
-
*
|
|
12782
|
+
* Downscales to at most {@link WIDE_THUMBNAIL_SMALL_MAX_WIDTH} (480) on the long
|
|
12783
|
+
* side (aspect preserved → 480×270) and re-encodes at representative quality.
|
|
12784
|
+
* `withoutEnlargement` preserves smaller sources.
|
|
12615
12785
|
*/
|
|
12616
12786
|
async function deriveThumbnailSmall(nativeWideJpeg) {
|
|
12617
|
-
|
|
12618
|
-
const longSide = Math.max(meta.width ?? 0, meta.height ?? 0);
|
|
12619
|
-
if (longSide > 0 && longSide <= 854) return nativeWideJpeg;
|
|
12620
|
-
return (0, sharp.default)(nativeWideJpeg).resize(854, null, { withoutEnlargement: true }).jpeg({ quality: 88 }).toBuffer();
|
|
12787
|
+
return (0, sharp.default)(nativeWideJpeg).resize(480, null, { withoutEnlargement: true }).jpeg({ quality: 75 }).toBuffer();
|
|
12621
12788
|
}
|
|
12622
12789
|
//#endregion
|
|
12623
12790
|
//#region src/shared/frame/keyframe-wide-thumbnail.ts
|
|
@@ -14871,6 +15038,7 @@ function createEventMediaHandler(deps) {
|
|
|
14871
15038
|
}
|
|
14872
15039
|
const variant = parseEventMediaVariant(query);
|
|
14873
15040
|
const preferKind = parseEventMediaKind(query);
|
|
15041
|
+
const resolveStartedAt = performance.now();
|
|
14874
15042
|
let media = null;
|
|
14875
15043
|
try {
|
|
14876
15044
|
media = await deps.getMedia(eventId, variant ?? void 0, preferKind ?? void 0);
|
|
@@ -14878,21 +15046,24 @@ function createEventMediaHandler(deps) {
|
|
|
14878
15046
|
const body = "Internal server error";
|
|
14879
15047
|
res.writeHead(500, {
|
|
14880
15048
|
"content-type": "text/plain",
|
|
14881
|
-
"content-length": String(Buffer.byteLength(body))
|
|
15049
|
+
"content-length": String(Buffer.byteLength(body)),
|
|
15050
|
+
"server-timing": `resolve;dur=${(performance.now() - resolveStartedAt).toFixed(1)}`
|
|
14882
15051
|
});
|
|
14883
15052
|
if (req.method !== "HEAD") res.end(body);
|
|
14884
15053
|
else res.end();
|
|
14885
15054
|
return;
|
|
14886
15055
|
}
|
|
14887
15056
|
if (media === null) {
|
|
14888
|
-
res.writeHead(404).end();
|
|
15057
|
+
res.writeHead(404, { "server-timing": `resolve;dur=${(performance.now() - resolveStartedAt).toFixed(1)}` }).end();
|
|
14889
15058
|
return;
|
|
14890
15059
|
}
|
|
14891
15060
|
const etag = "\"" + media.key + "\"";
|
|
15061
|
+
const serverTiming = `resolve;dur=${(performance.now() - resolveStartedAt).toFixed(1)}`;
|
|
14892
15062
|
if (req.headers["if-none-match"] === etag) {
|
|
14893
15063
|
res.writeHead(304, {
|
|
14894
15064
|
etag,
|
|
14895
|
-
"cache-control": CACHE_CONTROL
|
|
15065
|
+
"cache-control": CACHE_CONTROL,
|
|
15066
|
+
"server-timing": serverTiming
|
|
14896
15067
|
}).end();
|
|
14897
15068
|
return;
|
|
14898
15069
|
}
|
|
@@ -14900,7 +15071,8 @@ function createEventMediaHandler(deps) {
|
|
|
14900
15071
|
"content-type": "image/jpeg",
|
|
14901
15072
|
"cache-control": CACHE_CONTROL,
|
|
14902
15073
|
etag,
|
|
14903
|
-
"content-length": String(media.bytes.byteLength)
|
|
15074
|
+
"content-length": String(media.bytes.byteLength),
|
|
15075
|
+
"server-timing": serverTiming
|
|
14904
15076
|
});
|
|
14905
15077
|
if (req.method === "HEAD") res.end();
|
|
14906
15078
|
else res.end(Buffer.from(media.bytes));
|
|
@@ -26535,6 +26707,18 @@ function wireSubscriptions(deps) {
|
|
|
26535
26707
|
if (nodes === null) return;
|
|
26536
26708
|
deps.onClusterTopology(nodes);
|
|
26537
26709
|
}));
|
|
26710
|
+
unsubs.push(deps.eventBus.subscribe({ category: [
|
|
26711
|
+
require_dist.EventCategory.DeviceOnline,
|
|
26712
|
+
require_dist.EventCategory.DeviceOffline,
|
|
26713
|
+
require_dist.EventCategory.DeviceStateChanged,
|
|
26714
|
+
require_dist.EventCategory.StreamOnline,
|
|
26715
|
+
require_dist.EventCategory.StreamOffline,
|
|
26716
|
+
require_dist.EventCategory.AgentOnline,
|
|
26717
|
+
require_dist.EventCategory.AgentOffline,
|
|
26718
|
+
require_dist.EventCategory.WorkerOnline,
|
|
26719
|
+
require_dist.EventCategory.WorkerOffline,
|
|
26720
|
+
require_dist.EventCategory.UpdateAvailable
|
|
26721
|
+
] }, (ev) => deps.onSystemEvent(ev)));
|
|
26538
26722
|
}
|
|
26539
26723
|
unsubs.push(deps.eventBus.subscribe({ category: require_dist.EventCategory.DeviceBindingsChanged }, (ev) => {
|
|
26540
26724
|
deps.onBindingsChanged(ev.data);
|
|
@@ -27627,9 +27811,9 @@ var EventMediaDispatcher = class {
|
|
|
27627
27811
|
* the runner's retained native surface with NO `maxWidth` (uncapped TRUE
|
|
27628
27812
|
* native). It is composed into the full 16:9 window (lateral letterbox only for
|
|
27629
27813
|
* the part outside the frame) → the `thumbnail`. The `thumbnailSmall` is
|
|
27630
|
-
* DERIVED by downscaling that SAME window to the
|
|
27814
|
+
* DERIVED by downscaling that SAME window to the 480 long-side cap (480×270) —
|
|
27631
27815
|
* never a second `getNativeCropJpeg`, never upscaled ({@link deriveThumbnailSmall}
|
|
27632
|
-
*
|
|
27816
|
+
* never upscales a smaller window).
|
|
27633
27817
|
*
|
|
27634
27818
|
* Both variants share the SAME framing + central-square containment guarantee:
|
|
27635
27819
|
* wide consumers use the 16:9 image as-is (subject centered, no cut); square
|
|
@@ -30888,6 +31072,7 @@ var MOTION_EVENT_HEARTBEAT_MS = 5e3;
|
|
|
30888
31072
|
var CLEAN_MEDIA_KINDS = [
|
|
30889
31073
|
"crop",
|
|
30890
31074
|
"thumbnail",
|
|
31075
|
+
"thumbnailSmall",
|
|
30891
31076
|
"fullFrame",
|
|
30892
31077
|
"keyFrame",
|
|
30893
31078
|
"keyFrameSmall"
|
|
@@ -31587,7 +31772,8 @@ var PipelineAnalyticsAddon = class extends require_dist.BaseAddon {
|
|
|
31587
31772
|
onSensorStateChanged: (data, timestampMs) => this.handleSensorStateChanged(data, timestampMs),
|
|
31588
31773
|
onBindingsChanged: (data) => this.handleBindingsChangedEvent(data),
|
|
31589
31774
|
onDeviceUnregistered: (deviceId) => this.handleDeviceUnregisteredEvent(deviceId),
|
|
31590
|
-
onClusterTopology: (nodes) => this.nodeLiveness.applySnapshot(nodes, Date.now())
|
|
31775
|
+
onClusterTopology: (nodes) => this.nodeLiveness.applySnapshot(nodes, Date.now()),
|
|
31776
|
+
onSystemEvent: (event) => this.notificationCenter?.onSystemEvent(event)
|
|
31591
31777
|
});
|
|
31592
31778
|
if (this.isPostProcessingNode) await this.startEmbeddingDispatcher(logger, transport);
|
|
31593
31779
|
this.startSweepTimers();
|
|
@@ -36226,6 +36412,7 @@ var PipelineAnalyticsAddon = class extends require_dist.BaseAddon {
|
|
|
36226
36412
|
* failure the full blob is served (a thumb must never 500 / blank a tile).
|
|
36227
36413
|
*/
|
|
36228
36414
|
async applyThumbVariant(media, variant) {
|
|
36415
|
+
if (media.key.includes(":thumbnailSmall") && media.bytes.byteLength <= 64 * 1024) return media;
|
|
36229
36416
|
try {
|
|
36230
36417
|
return {
|
|
36231
36418
|
bytes: await makeSquareThumb(media.bytes, variant.size),
|
|
@@ -36244,7 +36431,13 @@ var PipelineAnalyticsAddon = class extends require_dist.BaseAddon {
|
|
|
36244
36431
|
const eventFiles = await (this.mediaStore?.listByOwner("event", id) ?? Promise.resolve([]));
|
|
36245
36432
|
if (preferKind !== void 0 && preferKind.length > 0) {
|
|
36246
36433
|
const trackFiles = await (this.mediaStore?.listByOwner("track", id) ?? Promise.resolve([]));
|
|
36247
|
-
const
|
|
36434
|
+
const ownerTrackId = trackFiles.length === 0 ? await (this.eventStore?.getTrackIdForEvent(id) ?? Promise.resolve(null)) : null;
|
|
36435
|
+
const owningTrackFiles = ownerTrackId === null ? [] : await (this.mediaStore?.listByOwner("track", ownerTrackId) ?? Promise.resolve([]));
|
|
36436
|
+
const chosen = resolveCropForcedMedia([
|
|
36437
|
+
...eventFiles,
|
|
36438
|
+
...trackFiles,
|
|
36439
|
+
...owningTrackFiles
|
|
36440
|
+
], (files) => pickCleanMedia(files, preferKind));
|
|
36248
36441
|
if (!chosen) return null;
|
|
36249
36442
|
return {
|
|
36250
36443
|
bytes: Buffer.from(chosen.base64, "base64"),
|