@camstack/addon-post-analysis 1.2.660 → 1.2.662
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/{clip-model-registry-DAKPBZfa.js → clip-model-registry-C3N1NpST.js} +274 -36
- package/dist/{clip-model-registry-D9BbIQ-h.mjs → clip-model-registry-ELaSS9jq.mjs} +269 -37
- package/dist/embedding-encoder/index.js +1 -1
- package/dist/embedding-encoder/index.mjs +1 -1
- package/dist/pipeline-analytics/_stub.js +2 -2
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-CvrKdp_8.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-BvOlyiL9.mjs} +2 -2
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D4zkNcgf.mjs +26 -0
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-vaatUWY6.mjs +26 -0
- package/dist/pipeline-analytics/{hostInit--CbMNXQy.mjs → hostInit-BjZchMMh.mjs} +2 -2
- package/dist/pipeline-analytics/index.js +506 -172
- package/dist/pipeline-analytics/index.mjs +506 -172
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +2 -2
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BDKliSzv.mjs +0 -26
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BwWOFFOc.mjs +0 -26
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as MAX_TRACK_RELATIONS, $i as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, $n as bundledCamstack, $r as normalizeNcAction, $t as NcTemplateVarDescriptorSchema, A as DETECTION_MACRO_CLASSES, Aa as
|
|
1
|
+
import { $ as MAX_TRACK_RELATIONS, $i as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, $n as bundledCamstack, $r as normalizeNcAction, $t as NcTemplateVarDescriptorSchema, A as DETECTION_MACRO_CLASSES, Aa as strictObject, Ai as sceneMonitorCapability, An as TrackPuritySchema, Ar as isAlertEpisodeOpen, At as NcAlarmConfigSchema, B as EXPORT_DENSE_MAX_RANGES, Bi as sunTimes, Bn as alertEpisodeKind, Br as isLabelSupplyStepId, Bt as NcRuleSchema, C as COCO_TO_MACRO, Ca as discriminatedUnion, Ci as retrainRevisionConflictMessage, Cn as SetTrackRelationInputSchema, Cr as eventKindLabel, Ct as NC_GROUPING_MIN_SEC, D as DEFAULT_DETAIL_CROP_CONVENTION, Da as object, Di as ruleDeviceCompatCapQueries, Dn as TimelapseRulePatchSchema, Dr as gifDeriveSpeed, Dt as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, E as CoverStateSchema, Ea as number, Ei as ruleBelongsToAlarm$1, En as TimelapseRuleInputSchema, Er as failureContributionCapability, Et as NC_STATE_SUMMARY_SECTION_IDS, F as EMBEDDING_REQUIREMENTS_FAILED, Fa as unknown, Fi as storageOccupancyCapability, Fn as activateAlarmProfile, Fr as isDetectionMacroClass, Ft as NcConditionDescriptorSchema, G as LabelAttributionSchema, Gi as systemEventSummaryScheduleOf, Gn as applySecureOnArmEdit, Gr as isSystemDelivery, Gt as NcSnoozeInputSchema, H as FULL_IMAGE_BBOX, Hi as systemEventDeliveryProblems, Hn as applyBlockingEdit, Hr as isRetiredClearKey, Ht as NcRuleUpdateInputSchema, I as EMBEDDING_REQUIREMENTS_UNAVAILABLE, Ia as DeviceType, Ii as subKindsOf, In as addonWidgetsSourceCapability, Ir as isDrawableSubjectPath, It as NcConditionsSchema, J as LockStateSchema, Ji as templateVarsFor, Jn as audioMetricsCapability, Jr as kebabToCamel, Jt as NcStateSummarySectionIdSchema, K as ListTrackRelationsInputSchema, Ki as systemEventSummarySplitOf, Kn as armRemovalReconcile, Kr as isSystemEventSummaryRule, Kt as NcSnoozeSchema, L as EVENT_DENSITY_BATCH_MAX, La as errMsg, Li as subjectPathSampleFromBox, Ln as alarmDeviceSecureOnArm, Lr as isEventKindLabelKey, Lt as NcRuleActionSchema, M as DeclaredDevices, Ma as templateLiteral, Mi as sensorRaisedOf, Mn as TrackRelationSchema, Mr as isAppLinkBase, Mt as NcAlarmSensorsInputSchema, N as DetectionSourceSchema, Na as tuple, Ni as servedTemplateVars, Nn as TrackSideSchema, Nr as isAudioClassName, Nt as NcAlarmSensorsSchema, O as DEFAULT_EVENT_COLOR, Oa as partialRecord, Oi as ruleGroupingApplies, On as TimelapseRuleSchema, Or as gifFromMp4Args, Ot as NC_TAXONOMY, P as EMBEDDING_MODEL_FAILED, Pa as union, Pi as startMoverUnderClearance, Pn as TrackSourceSchema, Pr as isDefaultAlarmProfileId, Pt as NcAlarmSettingsPatchSchema, Q as MAX_TRACK_PURITIES, Qi as zoneAnalyticsCapability, Qn as buildViewerLink, Qr as ncMediaPolicyError, Qt as NcTemplatePreviewSchema, R as EVENT_KIND_BY_CAP, Ra as EventCategory, Ri as subjectPathSvgPoints, Rn as alarmPanelCapability, Rr as isEventOwnerType, Rt as NcRuleInputSchema, S as BucketAccumulator, Sa as boolean, Sn as SetTrackPurityResultSchema, Sr as ensureAlarmProfiles, St as NC_GROUPING_MAX_SEC, T as ClearTrackRelationResultSchema, Ta as looseObject, Ti as ruleAutoTriggersAlarm, Tn as TRACK_RELATIONS_DEFAULT_LIMIT, Tr as faceGalleryCapability, Tt as NC_SNOOZE_MAX_MINUTES, U as FailureCounters, Ui as systemEventFamilyProblems, Un as applyModeDelaysEdits, Ur as isRootSuppliableStepId, Ut as NcScheduleSchema, V as FIRST_LEVEL_MACRO_CLASSES, Vi as syncActiveAlarmProfileSettings, Vn as alertEpisodePayload, Vr as isMediaOwnerType, Vt as NcRuleTargetSchema, W as LABEL_SUPPLY_MACRO, Wi as systemEventFilterApplies, Wn as applyNonBlockingEdit, Wr as isScheduleActive, Wt as NcSharedSequenceSchema, X as MAX_BIRTH_DECISION_RECORDS, Xi as viewerLinkBaseOf, Xn as buildEventKindDescriptor, Xr as mayWriteToLocation, Xt as NcTaxonomySchema, Y as MAX_ARCHIVED_DEBUG_NOTES, Yi as vectorDimFromBase64, Yn as audioModeOf, Yr as linkedStepOf, Yt as NcSystemEventKindSchema, Z as MAX_BIRTH_LATENCY_PROXY_MS, Zi as withSystemEventClasses, Zn as buildSubjectPath, Zr as memoizePinnedFfmpeg, Zt as NcTemplatePreviewInputSchema, _ as AlarmArmModeSchema, _i as resolveDeliveryParams, _n as SCENE_DEFAULT_UNCOVERED_POLICY, _t as NC_CONFIRM_DEFAULT_TIMEOUT_MS, a as CLIP_EMBEDDING_STEP_ID, aa as CamProfileSchema, ai as paletteResultSchema, an as RECORDING_SOURCE_CAMSTACK_ADDON, ar as coreBlockIdFromAddonId, at as NC_ALARM_DELAY_FIELDS, b as BaseDevice, ba as _enum, bi as resolveModeNotifyPolicy, bn as SceneMonitorSchema, bt as NC_DEFAULT_SNOOZE_MINUTES, c as readClusterModelPinStrict, ca as RECORD_QUERY_MAX, ci as pickFaceRescoreIntervalMinutes, cn as RetrainOriginSchema, cr as deleteAlarmProfile, ct as NC_ALARM_SYSTEM_EVENT_KINDS, d as APPEARANCE_BIN_COUNT, da as defineAddonMigrations, di as projectSubjectPath, dn as SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX, dr as deriveRecordingMode, dt as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, ea as canonicalHash, ei as normalizeNcCapTarget, en as OPS_LOG_DEFAULT_LIMIT, er as calendarEventLocalSpan, et as MOTION_CLOSE_AFTER_MS, f as APPEARANCE_BLOCKS, fa as defineCustomActions, fi as readDeviceStateFrom, fn as SCENE_CONFIRM_DEFAULT_TIMEOUT_MS, fr as describeSystemEventDeliveryProblem, ft as NC_CLIP_POST_ROLL_DEFAULT_SEC, g as ActionTargetResolver, ga as nodePin, gi as resolveClipSearchMinScore, gn as SCENE_DEFAULT_QUIET_SECONDS, gt as NC_CONFIRM_DEFAULT_MAX_IMAGE_PX, h as AUDIO_MACRO_LABELS, ha as isDeviceScopedCap, hi as renameAlarmProfile, hn as SCENE_DEFAULT_OBSERVATION_SPACING_SEC, hr as deviceRemovalHookCapability, ht as NC_CONDITION_CATALOG, ia as CAP_ADVANCE_FIELDS, ii as paintHex, in as RECORDING_EXPORT_MAX_READ_BYTES, ir as consumableLowPercentOf, it as NC_ALARM_DEFAULT_TRIGGERED_DURATION_SEC, j as DETECTION_PIPELINE_CAP_NAME, ja as string, ji as secureActuationFor, jn as TrackRelationKindSchema, jr as isAlertEpisodeSeverity, jt as NcAlarmPostTriggeredActionSchema, k as DEFAULT_TIMELAPSE_PREVIEW_TEXT, ka as record, ki as ruleKindOf, kn as TrackPlacementSchema, kr as isAlarmControllableCap, kt as NC_TEMPLATE_VARS, l as resolveClusterModelPin, la as createEvent, li as pipelineAnalyticsCapability, ln as RetrainStatusSchema, lr as deriveDetailCropRect, lt as NC_ALARM_TRIGGERED_MAX_SEC, m as ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT, ma as hydrateSchema, mi as readTimelapseGeneratedAt, mn as SCENE_DEFAULT_CHECK_INTERVAL_SEC, mr as deviceAttentionKind, mt as NC_CLIP_RETENTION_MAX_SEC, na as isSourceCap, ni as notificationRulesCapability, nn as PackageLlmVerdictSchema, nr as cloneAlarmSettings, nt as MotionTriggeredBySchema, o as CLUSTER_MODEL_OWNER_ADDON_ID, oa as InvalidRecordError, oi as parseAlertEpisodePayload, on as RebuildObjectEmbeddingsRefusalSchema, or as cosineSimilarity$1, ot as NC_ALARM_DELAY_MAX_SEC, p as APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT, pa as defineRecordKinds, pi as readMotionTriggeredBy, pn as SCENE_DEFAULT_ANCHOR_THRESHOLD, pr as describeSystemEventFamilyProblem, pt as NC_CLIP_PRE_ROLL_DEFAULT_SEC, q as ListTrackRelationsResultSchema, qi as templateCarriesSummary, qn as assertTimelapseCadences, qr as isVectorIndexDimConflict, qt as NcSnoozeSuppressedSchema, ra as BaseAddon, ri as occupancyScope, rr as consumableFormOf, rt as NC_ALARM_DEFAULT_PROFILE_ID, s as FACE_EMBEDDING_STEP_ID, sa as RECORD_MAX_DATA_BYTES, sn as RetrainDismissedSchema, sr as createAlarmProfile, st as NC_ALARM_NOTIFY_FIELDS, t as BUILTIN_CLIP_MODELS, ta as evaluateSensorEdge, ti as normalizeNcMediaPolicy, tn as OpsLogEntrySchema, tr as classifyRetrainReview, tt as MediaFileKindEnum, u as ACTION_TARGET_INVALIDATION_EVENTS, ua as customAction, ui as plateGalleryCapability, un as RetrainVerdictSubjectSchema, ur as derivePostTriggeredAction, ut as NC_AUDIO_CONFIRM_HITS_DEFAULT, v as ArchivedDebugNoteSchema, va as sleep$1, vi as resolveLocationMode, vn as SCENE_DIVERGED, vr as embeddingRefusalOf, vt as NC_CONSUMABLE_LOW_PERCENT_DEFAULT, w as ClearTrackRelationInputSchema, wa as literal, wi as rootSupplyServes, wn as TIMELAPSE_DENSE_FLOOR_SEC, wr as evictionPolicyOfLocation, wt as NC_SENSOR_TRANSITION_KINDS, x as BirthDecisionRecordSchema, xa as array, xi as resolveNcMediaImage, xn as SetTrackPurityInputSchema, xr as encodeVectorBase64, xt as NC_GROUPING_DEFAULT_SEC, y as BIRTH_DECISION_DEFAULT_LIMIT, ya as ZodObject, yi as resolveModeDelays, yn as SCENE_RESET_RECAPTURES, yt as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, z as EVENT_OWNER_TYPES, zi as summarizeReview, zn as alertEpisodeId, zr as isKnownTemplateVar, zt as NcRulePatchSchema } from "../clip-model-registry-ELaSS9jq.mjs";
|
|
2
2
|
import { t as __exportAll } from "../embedding-encoder/index.mjs";
|
|
3
3
|
import * as fs$1 from "node:fs";
|
|
4
4
|
import { createWriteStream, promises } from "node:fs";
|
|
@@ -8880,11 +8880,25 @@ function cleanSourcePreference(ownerKind) {
|
|
|
8880
8880
|
* The ONE placeholder grammar. `renderTemplate` substitutes what it matches and
|
|
8881
8881
|
* {@link templatePlaceholders} lists it; a second regex here would be a legend
|
|
8882
8882
|
* that disagrees with the renderer about what a variable is, which is the
|
|
8883
|
-
* failure mode where an editor advertises `{{
|
|
8883
|
+
* failure mode where an editor advertises `{{ device }}` as unsupported and the
|
|
8884
8884
|
* notification prints the camera anyway.
|
|
8885
8885
|
*/
|
|
8886
8886
|
var PLACEHOLDER_PATTERN = /\{\{\s*(\w+)\s*\}\}/g;
|
|
8887
8887
|
/**
|
|
8888
|
+
* Names that were renamed and still resolve at render time, mapped to the name
|
|
8889
|
+
* that replaced them. `{{camera}}` became `{{device}}` (a rule on an appliance
|
|
8890
|
+
* names that device, not a camera); a template written by an older client still
|
|
8891
|
+
* prints the right name. An alias is NOT declared in the catalog and no picker
|
|
8892
|
+
* offers it: the stored rules are rewritten by the `pipeline-analytics` template
|
|
8893
|
+
* migration, and this table only covers a client that has not updated yet.
|
|
8894
|
+
*/
|
|
8895
|
+
var NC_DEPRECATED_TEMPLATE_VARS = { camera: "device" };
|
|
8896
|
+
/** The deprecated names a template still uses, in order of first appearance. */
|
|
8897
|
+
function deprecatedPlaceholders(template) {
|
|
8898
|
+
if (template === void 0) return [];
|
|
8899
|
+
return templatePlaceholders(template).filter((name) => name in NC_DEPRECATED_TEMPLATE_VARS);
|
|
8900
|
+
}
|
|
8901
|
+
/**
|
|
8888
8902
|
* The variable names a template names, de-duplicated, in order of first
|
|
8889
8903
|
* appearance.
|
|
8890
8904
|
*
|
|
@@ -8910,19 +8924,35 @@ function templatePlaceholders(template) {
|
|
|
8910
8924
|
*/
|
|
8911
8925
|
function renderTemplate(template, vars) {
|
|
8912
8926
|
if (template === void 0 || template.trim().length === 0) return null;
|
|
8913
|
-
return template.replace(PLACEHOLDER_PATTERN, (_m, name) =>
|
|
8927
|
+
return template.replace(PLACEHOLDER_PATTERN, (_m, name) => {
|
|
8928
|
+
const current = vars[name];
|
|
8929
|
+
if (current !== void 0) return current;
|
|
8930
|
+
const renamed = NC_DEPRECATED_TEMPLATE_VARS[name];
|
|
8931
|
+
return (renamed !== void 0 ? vars[renamed] : void 0) ?? "";
|
|
8932
|
+
});
|
|
8914
8933
|
}
|
|
8915
8934
|
//#endregion
|
|
8916
8935
|
//#region src/notification-center/texts/en.json
|
|
8917
8936
|
var en_default = {
|
|
8918
8937
|
"detection.title": "{{rule}}",
|
|
8919
|
-
"detection.body": "{{subject}} on {{
|
|
8920
|
-
"detection.body.trackEnd": "{{subject}} on {{
|
|
8938
|
+
"detection.body": "{{subject}} on {{device}}{{inZones}}",
|
|
8939
|
+
"detection.body.trackEnd": "{{subject}} on {{device}}{{inZones}} — visit ended",
|
|
8921
8940
|
"detection.subject": "{{classNoun}}",
|
|
8922
8941
|
"detection.subject.labelled": "{{classNoun}} ({{label}})",
|
|
8923
8942
|
"detection.subject.identity": "{{label}}",
|
|
8924
8943
|
"detection.subject.plate": "{{classNoun}} {{label}}",
|
|
8925
8944
|
"detection.inZones": " in {{zones}}",
|
|
8945
|
+
"appliance.finished.title": "{{device}} finished",
|
|
8946
|
+
"appliance.finished.body": "{{device}} finished{{afterDuration}}{{usedEnergy}}",
|
|
8947
|
+
"appliance.finished.duration": " after {{duration}}",
|
|
8948
|
+
"appliance.finished.energy": " and used {{energy}}",
|
|
8949
|
+
"appliance.duration.minutes": {
|
|
8950
|
+
"one": "{{minutes}} minute",
|
|
8951
|
+
"other": "{{minutes}} minutes"
|
|
8952
|
+
},
|
|
8953
|
+
"appliance.duration.hours": "{{hours}} h",
|
|
8954
|
+
"appliance.duration.hoursMinutes": "{{hours}} h {{minutes}} min",
|
|
8955
|
+
"appliance.energy.value": "{{value}} kWh",
|
|
8926
8956
|
"class.person": {
|
|
8927
8957
|
"one": "person",
|
|
8928
8958
|
"other": "people"
|
|
@@ -8989,11 +9019,11 @@ var en_default = {
|
|
|
8989
9019
|
"other": "{{count}} other {{classNoun}}"
|
|
8990
9020
|
},
|
|
8991
9021
|
"package.delivered.title": "Parcel delivered",
|
|
8992
|
-
"package.delivered.body": "Delivered at {{
|
|
9022
|
+
"package.delivered.body": "Delivered at {{device}}{{inZones}}",
|
|
8993
9023
|
"package.delivered.possible.title": "Possible parcel",
|
|
8994
|
-
"package.delivered.possible.body": "Possible parcel at {{
|
|
9024
|
+
"package.delivered.possible.body": "Possible parcel at {{device}}{{inZones}}",
|
|
8995
9025
|
"package.picked-up.title": "Parcel collected",
|
|
8996
|
-
"package.picked-up.body": "Collected from {{
|
|
9026
|
+
"package.picked-up.body": "Collected from {{device}}{{inZones}}",
|
|
8997
9027
|
"occupancy.body": "{{scope}} {{op}} ({{count}}/{{capacity}})",
|
|
8998
9028
|
"occupancy.op.occupied": "occupied",
|
|
8999
9029
|
"occupancy.op.free": "free",
|
|
@@ -9129,7 +9159,7 @@ var en_default = {
|
|
|
9129
9159
|
"system.camera-enabled.title": "Device switched on",
|
|
9130
9160
|
"system.camera-enabled.body": "Device {{deviceName}} was switched back on",
|
|
9131
9161
|
"test.prefix": "[TEST] {{body}}",
|
|
9132
|
-
"timelapse.title": "Timelapse — {{
|
|
9162
|
+
"timelapse.title": "Timelapse — {{device}}",
|
|
9133
9163
|
"timelapse.body.window": "{{rule}} — {{from}}→{{to}}",
|
|
9134
9164
|
"timelapse.body.tooManyEvents": "too many events for dense sampling: video at a uniform cadence",
|
|
9135
9165
|
"timelapse.body.denseRanges": {
|
|
@@ -9143,7 +9173,7 @@ var en_default = {
|
|
|
9143
9173
|
},
|
|
9144
9174
|
"snooze.digest.header": "{{scope}} was snoozed, {{from}}–{{to}}.",
|
|
9145
9175
|
"snooze.digest.header.global": "{{scope}} was snoozed for everyone, {{from}}–{{to}}.",
|
|
9146
|
-
"snooze.digest.line": "• {{rule}} on {{
|
|
9176
|
+
"snooze.digest.line": "• {{rule}} on {{device}} — {{count}}",
|
|
9147
9177
|
"snooze.scope.all": "Everything",
|
|
9148
9178
|
"snooze.scope.anyDevice": "A camera",
|
|
9149
9179
|
"snooze.scope.anyRule": "A rule",
|
|
@@ -9322,13 +9352,24 @@ var en_default = {
|
|
|
9322
9352
|
//#region src/notification-center/texts/it.json
|
|
9323
9353
|
var it_default = {
|
|
9324
9354
|
"detection.title": "{{rule}}",
|
|
9325
|
-
"detection.body": "{{subject}} su {{
|
|
9326
|
-
"detection.body.trackEnd": "{{subject}} su {{
|
|
9355
|
+
"detection.body": "{{subject}} su {{device}}{{inZones}}",
|
|
9356
|
+
"detection.body.trackEnd": "{{subject}} su {{device}}{{inZones}} — visita terminata",
|
|
9327
9357
|
"detection.subject": "{{classNoun}}",
|
|
9328
9358
|
"detection.subject.labelled": "{{classNoun}} ({{label}})",
|
|
9329
9359
|
"detection.subject.identity": "{{label}}",
|
|
9330
9360
|
"detection.subject.plate": "{{classNoun}} {{label}}",
|
|
9331
9361
|
"detection.inZones": " in {{zones}}",
|
|
9362
|
+
"appliance.finished.title": "{{device}} ha terminato",
|
|
9363
|
+
"appliance.finished.body": "{{device}} ha terminato{{afterDuration}}{{usedEnergy}}",
|
|
9364
|
+
"appliance.finished.duration": " dopo {{duration}}",
|
|
9365
|
+
"appliance.finished.energy": " e ha consumato {{energy}}",
|
|
9366
|
+
"appliance.duration.minutes": {
|
|
9367
|
+
"one": "{{minutes}} minuto",
|
|
9368
|
+
"other": "{{minutes}} minuti"
|
|
9369
|
+
},
|
|
9370
|
+
"appliance.duration.hours": "{{hours}} h",
|
|
9371
|
+
"appliance.duration.hoursMinutes": "{{hours}} h {{minutes}} min",
|
|
9372
|
+
"appliance.energy.value": "{{value}} kWh",
|
|
9332
9373
|
"class.person": {
|
|
9333
9374
|
"one": "persona",
|
|
9334
9375
|
"other": "persone"
|
|
@@ -9395,11 +9436,11 @@ var it_default = {
|
|
|
9395
9436
|
"other": "{{count}} altri {{classNoun}}"
|
|
9396
9437
|
},
|
|
9397
9438
|
"package.delivered.title": "Pacco consegnato",
|
|
9398
|
-
"package.delivered.body": "Consegnato su {{
|
|
9439
|
+
"package.delivered.body": "Consegnato su {{device}}{{inZones}}",
|
|
9399
9440
|
"package.delivered.possible.title": "Possibile pacco",
|
|
9400
|
-
"package.delivered.possible.body": "Possibile pacco su {{
|
|
9441
|
+
"package.delivered.possible.body": "Possibile pacco su {{device}}{{inZones}}",
|
|
9401
9442
|
"package.picked-up.title": "Pacco ritirato",
|
|
9402
|
-
"package.picked-up.body": "Ritirato da {{
|
|
9443
|
+
"package.picked-up.body": "Ritirato da {{device}}{{inZones}}",
|
|
9403
9444
|
"occupancy.body": "{{scope}} {{op}} ({{count}}/{{capacity}})",
|
|
9404
9445
|
"occupancy.op.occupied": "occupata",
|
|
9405
9446
|
"occupancy.op.free": "libera",
|
|
@@ -9535,7 +9576,7 @@ var it_default = {
|
|
|
9535
9576
|
"system.camera-enabled.title": "Dispositivo riacceso",
|
|
9536
9577
|
"system.camera-enabled.body": "Il dispositivo {{deviceName}} è stato riacceso",
|
|
9537
9578
|
"test.prefix": "[PROVA] {{body}}",
|
|
9538
|
-
"timelapse.title": "Sequenza — {{
|
|
9579
|
+
"timelapse.title": "Sequenza — {{device}}",
|
|
9539
9580
|
"timelapse.body.window": "{{rule}} — {{from}}→{{to}}",
|
|
9540
9581
|
"timelapse.body.tooManyEvents": "troppi eventi per il campionamento denso: video a cadenza uniforme",
|
|
9541
9582
|
"timelapse.body.denseRanges": {
|
|
@@ -9549,7 +9590,7 @@ var it_default = {
|
|
|
9549
9590
|
},
|
|
9550
9591
|
"snooze.digest.header": "{{scope}} in pausa, {{from}}–{{to}}.",
|
|
9551
9592
|
"snooze.digest.header.global": "{{scope}} in pausa per tutti, {{from}}–{{to}}.",
|
|
9552
|
-
"snooze.digest.line": "• {{rule}} su {{
|
|
9593
|
+
"snooze.digest.line": "• {{rule}} su {{device}} — {{count}}",
|
|
9553
9594
|
"snooze.scope.all": "Tutto",
|
|
9554
9595
|
"snooze.scope.anyDevice": "Una camera",
|
|
9555
9596
|
"snooze.scope.anyRule": "Una regola",
|
|
@@ -9773,7 +9814,7 @@ var it_default = {
|
|
|
9773
9814
|
* as plain strings. {@link renderTemplate} never re-scans a replacement, so
|
|
9774
9815
|
* there is exactly one level of composition and it cannot grow: a fragment that
|
|
9775
9816
|
* names another composite renders it empty, and a value that happens to look
|
|
9776
|
-
* like `{{
|
|
9817
|
+
* like `{{device}}` is printed, not substituted.
|
|
9777
9818
|
*/
|
|
9778
9819
|
/** The languages the hub ships texts for. */
|
|
9779
9820
|
var NC_LANGUAGES = ["en", "it"];
|
|
@@ -56135,6 +56176,258 @@ var ZoneCatalogueCache = class {
|
|
|
56135
56176
|
}
|
|
56136
56177
|
};
|
|
56137
56178
|
//#endregion
|
|
56179
|
+
//#region src/notification-center/record-kinds.ts
|
|
56180
|
+
/**
|
|
56181
|
+
* Record kinds owned by the pipeline-analytics addon (records plan phase 2,
|
|
56182
|
+
* steps 18-24): the notification-center config tables.
|
|
56183
|
+
*
|
|
56184
|
+
* The notification-center module is hosted inside the pipeline-analytics addon.
|
|
56185
|
+
* That addon declares no `execution.group`, so the UDS owner stamp is the addon
|
|
56186
|
+
* id: `pipeline-analytics`. Declared hub-only (agents have no `ctx.records`).
|
|
56187
|
+
* One deploy covers all 7 kinds.
|
|
56188
|
+
*/
|
|
56189
|
+
/**
|
|
56190
|
+
* The hub language and operator-authored per-key overrides.
|
|
56191
|
+
* One row, id `texts`. Losing it degrades to the shipped English catalog.
|
|
56192
|
+
*/
|
|
56193
|
+
var TextsBodySchema = object({
|
|
56194
|
+
language: NcLanguageSchema,
|
|
56195
|
+
overrides: partialRecord(NcLanguageSchema, record(string(), string()))
|
|
56196
|
+
});
|
|
56197
|
+
/**
|
|
56198
|
+
* A shared action sequence (without id, which is the record key).
|
|
56199
|
+
* Extends the wire shape with `createdAt` / `updatedAt` (stored by the legacy table).
|
|
56200
|
+
*/
|
|
56201
|
+
var SequenceBodySchema = NcSharedSequenceSchema.omit({ id: true }).extend({
|
|
56202
|
+
createdAt: number(),
|
|
56203
|
+
updatedAt: number()
|
|
56204
|
+
});
|
|
56205
|
+
/**
|
|
56206
|
+
* The AI section of one ordinary rule. Record id = the rule id.
|
|
56207
|
+
*/
|
|
56208
|
+
var RuleAiBodySchema = object({
|
|
56209
|
+
ai: NcRuleAiSchema,
|
|
56210
|
+
updatedAt: number()
|
|
56211
|
+
});
|
|
56212
|
+
/** A calendar-events rule (without `id`). */
|
|
56213
|
+
var CalendarEventsRuleBodySchema = NcCalendarEventsRuleSchema.omit({ id: true });
|
|
56214
|
+
/** A multi-camera digest rule (without `id`). */
|
|
56215
|
+
var SummaryRuleBodySchema = NcSummaryRuleSchema.omit({ id: true });
|
|
56216
|
+
/** A timelapse rule (without `id`). */
|
|
56217
|
+
var TimelapseRuleBodySchema = TimelapseRuleSchema.omit({ id: true });
|
|
56218
|
+
/** A notification rule (without `id`). */
|
|
56219
|
+
var RuleBodySchema = NcRuleSchema.omit({ id: true });
|
|
56220
|
+
var ncRecordKinds = defineRecordKinds({
|
|
56221
|
+
/**
|
|
56222
|
+
* The hub language + per-key text overrides. One row (id `texts`).
|
|
56223
|
+
*/
|
|
56224
|
+
texts: {
|
|
56225
|
+
schema: TextsBodySchema,
|
|
56226
|
+
class: "config",
|
|
56227
|
+
writeTrigger: "an operator changes the hub language (setLanguage) or replaces the per-key override set (setOverrides)",
|
|
56228
|
+
device: "none",
|
|
56229
|
+
at: "none",
|
|
56230
|
+
retention: { none: "one row (id `texts`); losing it costs the chosen language and household wording, never a notification — every read degrades to the shipped English catalog" }
|
|
56231
|
+
},
|
|
56232
|
+
/**
|
|
56233
|
+
* Shared action sequences — named, ordered runs of steps with their own throttle.
|
|
56234
|
+
* One row per sequence, id = sequence UUID.
|
|
56235
|
+
*/
|
|
56236
|
+
sequences: {
|
|
56237
|
+
schema: SequenceBodySchema,
|
|
56238
|
+
class: "config",
|
|
56239
|
+
writeTrigger: "an admin creates/edits/deletes a shared sequence via notificationRules.createSequence / updateSequence / deleteSequence, or the one-shot boot migration that materialises legacy inline sequences",
|
|
56240
|
+
device: "none",
|
|
56241
|
+
at: "none",
|
|
56242
|
+
retention: { none: "a row goes only when an admin deletes it; bounded by the sequence set a human is willing to author" }
|
|
56243
|
+
},
|
|
56244
|
+
/**
|
|
56245
|
+
* Per-rule AI section: whether and how a rule narrates itself.
|
|
56246
|
+
* Record id = the rule id it belongs to.
|
|
56247
|
+
*/
|
|
56248
|
+
"rule-ai": {
|
|
56249
|
+
schema: RuleAiBodySchema,
|
|
56250
|
+
class: "config",
|
|
56251
|
+
writeTrigger: "an operator switches the AI section of a notification rule on or off, or edits its prompt / word cap / language",
|
|
56252
|
+
device: "none",
|
|
56253
|
+
at: "none",
|
|
56254
|
+
retention: { none: "a row goes when the operator clears the section or deletes the rule; bounded by the rule set a human is willing to author" }
|
|
56255
|
+
},
|
|
56256
|
+
/**
|
|
56257
|
+
* Calendar-events rules. One row per rule, id = rule UUID.
|
|
56258
|
+
*/
|
|
56259
|
+
"calendar-events-rules": {
|
|
56260
|
+
schema: CalendarEventsRuleBodySchema,
|
|
56261
|
+
class: "config",
|
|
56262
|
+
writeTrigger: "an operator creates or edits a calendar-events rule, or the producer stamps a delivered window via markGenerated",
|
|
56263
|
+
device: "none",
|
|
56264
|
+
at: "none",
|
|
56265
|
+
indexes: [{
|
|
56266
|
+
name: "enabled",
|
|
56267
|
+
fields: ["enabled"]
|
|
56268
|
+
}],
|
|
56269
|
+
retention: { none: "a row goes only when the operator deletes the rule; bounded by the rule set a human is willing to author" }
|
|
56270
|
+
},
|
|
56271
|
+
/**
|
|
56272
|
+
* Multi-camera digest rules. One row per rule, id = rule UUID.
|
|
56273
|
+
*/
|
|
56274
|
+
"summary-rules": {
|
|
56275
|
+
schema: SummaryRuleBodySchema,
|
|
56276
|
+
class: "config",
|
|
56277
|
+
writeTrigger: "an operator creates or edits a digest rule, or the producer stamps a delivered window via markGenerated",
|
|
56278
|
+
device: "none",
|
|
56279
|
+
at: "none",
|
|
56280
|
+
indexes: [{
|
|
56281
|
+
name: "enabled",
|
|
56282
|
+
fields: ["enabled"]
|
|
56283
|
+
}],
|
|
56284
|
+
retention: { none: "a row goes only when the operator deletes the rule; bounded by the rule set a human is willing to author" }
|
|
56285
|
+
},
|
|
56286
|
+
/**
|
|
56287
|
+
* Timelapse rules. One row per rule, id = rule UUID.
|
|
56288
|
+
* Three rows on prod (2026-10-18).
|
|
56289
|
+
*/
|
|
56290
|
+
"timelapse-rules": {
|
|
56291
|
+
schema: TimelapseRuleBodySchema,
|
|
56292
|
+
class: "config",
|
|
56293
|
+
writeTrigger: "an operator creates or edits a timelapse rule, or the scheduler stamps a successful per-camera generation via markGenerated",
|
|
56294
|
+
device: "none",
|
|
56295
|
+
at: "none",
|
|
56296
|
+
indexes: [{
|
|
56297
|
+
name: "enabled",
|
|
56298
|
+
fields: ["enabled"]
|
|
56299
|
+
}],
|
|
56300
|
+
retention: { none: "a row goes only when the operator deletes the rule; bounded by the rule set a human is willing to author" }
|
|
56301
|
+
},
|
|
56302
|
+
/**
|
|
56303
|
+
* Notification rules — the main rule set. One row per rule, id = rule UUID.
|
|
56304
|
+
* 18 rows on prod (2026-10-18); most coupled kind in this owner.
|
|
56305
|
+
*/
|
|
56306
|
+
rules: {
|
|
56307
|
+
schema: RuleBodySchema,
|
|
56308
|
+
class: "config",
|
|
56309
|
+
writeTrigger: "an operator creates, edits, enables/disables a rule or opts a target out of it; nothing writes on the evaluation path",
|
|
56310
|
+
device: "none",
|
|
56311
|
+
at: "none",
|
|
56312
|
+
indexes: [{
|
|
56313
|
+
name: "delivery",
|
|
56314
|
+
fields: ["delivery"]
|
|
56315
|
+
}],
|
|
56316
|
+
retention: { none: "a row goes only when the operator deletes the rule; bounded by the rule set a human is willing to author" }
|
|
56317
|
+
}
|
|
56318
|
+
});
|
|
56319
|
+
//#endregion
|
|
56320
|
+
//#region src/migrations/device-template-var.ts
|
|
56321
|
+
/** `{{camera}}` and `{{ camera }}`: the whitespace the renderer allows is kept as written. */
|
|
56322
|
+
var OLD_VARIABLE = /\{\{(\s*)camera(\s*)\}\}/g;
|
|
56323
|
+
/** The template text with the variable renamed; the same string when it names none. */
|
|
56324
|
+
function renameDeviceVariable(text) {
|
|
56325
|
+
return text.replace(OLD_VARIABLE, "{{$1device$2}}");
|
|
56326
|
+
}
|
|
56327
|
+
/** A `{ title, body }` template with both fields renamed; `null` when neither changed. */
|
|
56328
|
+
function renamedTemplate(template) {
|
|
56329
|
+
if (template === void 0) return null;
|
|
56330
|
+
const title = template.title === void 0 ? void 0 : renameDeviceVariable(template.title);
|
|
56331
|
+
const body = template.body === void 0 ? void 0 : renameDeviceVariable(template.body);
|
|
56332
|
+
if (title === template.title && body === template.body) return null;
|
|
56333
|
+
return {
|
|
56334
|
+
...template,
|
|
56335
|
+
...title !== void 0 ? { title } : {},
|
|
56336
|
+
...body !== void 0 ? { body } : {}
|
|
56337
|
+
};
|
|
56338
|
+
}
|
|
56339
|
+
function renamedRule(data) {
|
|
56340
|
+
const template = renamedTemplate(data.template);
|
|
56341
|
+
return template === null ? null : {
|
|
56342
|
+
...data,
|
|
56343
|
+
template
|
|
56344
|
+
};
|
|
56345
|
+
}
|
|
56346
|
+
function renamedTimelapseRule(data) {
|
|
56347
|
+
const template = renamedTemplate(data.template);
|
|
56348
|
+
const previewText = data.previewText === void 0 ? void 0 : renameDeviceVariable(data.previewText);
|
|
56349
|
+
const previewChanged = previewText !== data.previewText;
|
|
56350
|
+
if (template === null && !previewChanged) return null;
|
|
56351
|
+
return {
|
|
56352
|
+
...data,
|
|
56353
|
+
...template !== null ? { template } : {},
|
|
56354
|
+
...previewChanged && previewText !== void 0 ? { previewText } : {}
|
|
56355
|
+
};
|
|
56356
|
+
}
|
|
56357
|
+
function renamedTexts(data) {
|
|
56358
|
+
let changed = false;
|
|
56359
|
+
const overrides = Object.fromEntries(Object.entries(data.overrides).map(([language, table]) => [language, Object.fromEntries(Object.entries(table).map(([key, text]) => {
|
|
56360
|
+
const next = renameDeviceVariable(text);
|
|
56361
|
+
if (next !== text) changed = true;
|
|
56362
|
+
return [key, next];
|
|
56363
|
+
}))]));
|
|
56364
|
+
return changed ? {
|
|
56365
|
+
...data,
|
|
56366
|
+
overrides
|
|
56367
|
+
} : null;
|
|
56368
|
+
}
|
|
56369
|
+
var PAGE$1 = 500;
|
|
56370
|
+
/** Every row of a kind, page by page. */
|
|
56371
|
+
async function allRows(kind) {
|
|
56372
|
+
const rows = [];
|
|
56373
|
+
let cursor;
|
|
56374
|
+
do {
|
|
56375
|
+
const page = await kind.query({
|
|
56376
|
+
limit: PAGE$1,
|
|
56377
|
+
...cursor !== void 0 ? { cursor } : {}
|
|
56378
|
+
});
|
|
56379
|
+
rows.push(...page.records);
|
|
56380
|
+
cursor = page.nextCursor ?? void 0;
|
|
56381
|
+
} while (cursor !== void 0);
|
|
56382
|
+
return rows;
|
|
56383
|
+
}
|
|
56384
|
+
/** Rewrite the rows of one kind that carry the old name; returns how many were written. */
|
|
56385
|
+
async function rewriteKind(kind, rewrite) {
|
|
56386
|
+
let written = 0;
|
|
56387
|
+
for (const row of await allRows(kind)) {
|
|
56388
|
+
const next = rewrite(row.data);
|
|
56389
|
+
if (next === null) continue;
|
|
56390
|
+
await kind.put({
|
|
56391
|
+
id: row.id,
|
|
56392
|
+
data: next
|
|
56393
|
+
}, { ifRev: row.rev });
|
|
56394
|
+
written += 1;
|
|
56395
|
+
}
|
|
56396
|
+
return written;
|
|
56397
|
+
}
|
|
56398
|
+
async function migrateDeviceTemplateVariable(ports) {
|
|
56399
|
+
const rules = await rewriteKind(ports.rules, renamedRule);
|
|
56400
|
+
const timelapseRules = await rewriteKind(ports.timelapseRules, renamedTimelapseRule);
|
|
56401
|
+
const texts = await rewriteKind(ports.texts, renamedTexts);
|
|
56402
|
+
return {
|
|
56403
|
+
outcome: rules + timelapseRules + texts === 0 ? "already-done" : "done",
|
|
56404
|
+
summary: {
|
|
56405
|
+
rules,
|
|
56406
|
+
timelapseRules,
|
|
56407
|
+
texts
|
|
56408
|
+
}
|
|
56409
|
+
};
|
|
56410
|
+
}
|
|
56411
|
+
//#endregion
|
|
56412
|
+
//#region src/migrations/index.ts
|
|
56413
|
+
/** The `pipeline-analytics` catalogue (D987): offered to the engine at the hub's boot. */
|
|
56414
|
+
var ADDON_MIGRATIONS = [{
|
|
56415
|
+
meta: {
|
|
56416
|
+
id: "pipeline-analytics/2026-11-01-template-camera-to-device",
|
|
56417
|
+
owner: "pipeline-analytics",
|
|
56418
|
+
level: "addon-state",
|
|
56419
|
+
seq: 1,
|
|
56420
|
+
dependsOn: [],
|
|
56421
|
+
store: "settings",
|
|
56422
|
+
scope: "cluster",
|
|
56423
|
+
onFailure: "tolerate",
|
|
56424
|
+
bodyKind: "procedure",
|
|
56425
|
+
description: "Rename the {{camera}} template variable to {{device}} in every stored notification rule, timelapse rule and text override",
|
|
56426
|
+
fixtureMark: "the rule name and the trigger conditions the migration does not know"
|
|
56427
|
+
},
|
|
56428
|
+
procedure: migrateDeviceTemplateVariable
|
|
56429
|
+
}];
|
|
56430
|
+
//#endregion
|
|
56138
56431
|
//#region src/pipeline-analytics/clip-space-plan.ts
|
|
56139
56432
|
/**
|
|
56140
56433
|
* Which CLIP feature space a search reads and a rebuild fills — decided in one
|
|
@@ -67033,7 +67326,7 @@ var CaptureScheduler = class {
|
|
|
67033
67326
|
for (let i = lane.queue.length - 1; i >= 0; i -= 1) {
|
|
67034
67327
|
const entry = lane.queue[i];
|
|
67035
67328
|
if (entry === void 0) continue;
|
|
67036
|
-
if (entry.staleAfterMs === void 0 || nowMs - entry.enqueuedAt
|
|
67329
|
+
if (entry.staleAfterMs === void 0 || nowMs - entry.enqueuedAt < entry.staleAfterMs) continue;
|
|
67037
67330
|
lane.queue.splice(i, 1);
|
|
67038
67331
|
this.bump(deviceId, "droppedStale");
|
|
67039
67332
|
this.noteDropped(deviceId, entry, "stale");
|
|
@@ -67109,7 +67402,7 @@ var CaptureScheduler = class {
|
|
|
67109
67402
|
while (lane.inFlight < this.budget && lane.queue.length > 0) {
|
|
67110
67403
|
const entry = lane.queue.shift();
|
|
67111
67404
|
if (entry === void 0) return;
|
|
67112
|
-
if (entry.staleAfterMs !== void 0 && this.now() - entry.enqueuedAt
|
|
67405
|
+
if (entry.staleAfterMs !== void 0 && this.now() - entry.enqueuedAt >= entry.staleAfterMs) {
|
|
67113
67406
|
this.bump(deviceId, "droppedStale");
|
|
67114
67407
|
this.noteDropped(deviceId, entry, "stale");
|
|
67115
67408
|
entry.drop();
|
|
@@ -68337,6 +68630,109 @@ function createAnalyticsWidgetsProvider() {
|
|
|
68337
68630
|
] };
|
|
68338
68631
|
}
|
|
68339
68632
|
//#endregion
|
|
68633
|
+
//#region src/notification-center/appliance-cycle.ts
|
|
68634
|
+
var NC_UNKNOWN_CYCLE_FACTS = {
|
|
68635
|
+
durationMs: null,
|
|
68636
|
+
energyKwh: null
|
|
68637
|
+
};
|
|
68638
|
+
var NC_EMPTY_CYCLE_VARS = {
|
|
68639
|
+
duration: "",
|
|
68640
|
+
energy: "",
|
|
68641
|
+
afterDuration: "",
|
|
68642
|
+
usedEnergy: ""
|
|
68643
|
+
};
|
|
68644
|
+
/** `52 minutes` / `1 h 12 min` / `2 h`; `''` below one minute (never "0 minutes"). */
|
|
68645
|
+
function durationText(texts, durationMs) {
|
|
68646
|
+
if (durationMs === null || !Number.isFinite(durationMs)) return "";
|
|
68647
|
+
const totalMinutes = Math.round(durationMs / 6e4);
|
|
68648
|
+
if (totalMinutes < 1) return "";
|
|
68649
|
+
if (totalMinutes < 60) return texts.text({
|
|
68650
|
+
key: "appliance.duration.minutes",
|
|
68651
|
+
count: totalMinutes,
|
|
68652
|
+
vars: { minutes: `${totalMinutes}` }
|
|
68653
|
+
});
|
|
68654
|
+
const hours = Math.floor(totalMinutes / 60);
|
|
68655
|
+
const minutes = totalMinutes % 60;
|
|
68656
|
+
return minutes === 0 ? texts.text({
|
|
68657
|
+
key: "appliance.duration.hours",
|
|
68658
|
+
vars: { hours: `${hours}` }
|
|
68659
|
+
}) : texts.text({
|
|
68660
|
+
key: "appliance.duration.hoursMinutes",
|
|
68661
|
+
vars: {
|
|
68662
|
+
hours: `${hours}`,
|
|
68663
|
+
minutes: `${minutes}`
|
|
68664
|
+
}
|
|
68665
|
+
});
|
|
68666
|
+
}
|
|
68667
|
+
/** `0,84 kWh` (it) / `0.84 kWh` (en); `''` when unmeasured. */
|
|
68668
|
+
function energyText(texts, energyKwh) {
|
|
68669
|
+
if (energyKwh === null || !Number.isFinite(energyKwh) || energyKwh < 0) return "";
|
|
68670
|
+
const value = energyKwh.toLocaleString(texts.language, {
|
|
68671
|
+
minimumFractionDigits: 2,
|
|
68672
|
+
maximumFractionDigits: 2
|
|
68673
|
+
});
|
|
68674
|
+
return texts.text({
|
|
68675
|
+
key: "appliance.energy.value",
|
|
68676
|
+
vars: { value }
|
|
68677
|
+
});
|
|
68678
|
+
}
|
|
68679
|
+
/** The four variables of a finished cycle, fragments rendered from scalars only. */
|
|
68680
|
+
function ncApplianceCycleVars(texts, facts) {
|
|
68681
|
+
const duration = durationText(texts, facts.durationMs);
|
|
68682
|
+
const energy = energyText(texts, facts.energyKwh);
|
|
68683
|
+
return {
|
|
68684
|
+
duration,
|
|
68685
|
+
energy,
|
|
68686
|
+
afterDuration: duration === "" ? "" : texts.text({
|
|
68687
|
+
key: "appliance.finished.duration",
|
|
68688
|
+
vars: { duration }
|
|
68689
|
+
}),
|
|
68690
|
+
usedEnergy: energy === "" ? "" : texts.text({
|
|
68691
|
+
key: "appliance.finished.energy",
|
|
68692
|
+
vars: { energy }
|
|
68693
|
+
})
|
|
68694
|
+
};
|
|
68695
|
+
}
|
|
68696
|
+
/**
|
|
68697
|
+
* The frozen reference a FINISHED appliance cycle row carries (`{}` for every
|
|
68698
|
+
* other row): kind `appliance-cycle`, edge `cleared`. The appliance is the
|
|
68699
|
+
* sensor itself — a linked camera is only where the row was attributed.
|
|
68700
|
+
*/
|
|
68701
|
+
function applianceCycleOf(subject) {
|
|
68702
|
+
if (subject.sensorKind !== "appliance-cycle" || subject.sensorRaised !== false) return {};
|
|
68703
|
+
return { applianceCycle: { deviceId: subject.linkedSensorId ?? subject.sourceDeviceId ?? subject.deviceId } };
|
|
68704
|
+
}
|
|
68705
|
+
//#endregion
|
|
68706
|
+
//#region src/notification-center/appliance-cycle-runs.ts
|
|
68707
|
+
var CYCLE_FACTS_WAIT_MS = 3e3;
|
|
68708
|
+
var CYCLE_FACTS_POLL_MS = 250;
|
|
68709
|
+
/** A closed run belongs to this finish when it ended within this much of it. */
|
|
68710
|
+
var CYCLE_RUN_MATCH_MS = 10 * 6e4;
|
|
68711
|
+
function factsOfClosed(run, finishedAtMs) {
|
|
68712
|
+
if (run.endedAt === null || Math.abs(run.endedAt - finishedAtMs) > CYCLE_RUN_MATCH_MS) return NC_UNKNOWN_CYCLE_FACTS;
|
|
68713
|
+
return {
|
|
68714
|
+
durationMs: run.durationMs,
|
|
68715
|
+
energyKwh: run.detail.energyKwh
|
|
68716
|
+
};
|
|
68717
|
+
}
|
|
68718
|
+
function applianceCycleFactsFromRuns(ports) {
|
|
68719
|
+
return async ({ deviceId, finishedAtMs }) => {
|
|
68720
|
+
let waited = 0;
|
|
68721
|
+
for (;;) {
|
|
68722
|
+
const run = await ports.newestRun(deviceId);
|
|
68723
|
+
if (run === null) return NC_UNKNOWN_CYCLE_FACTS;
|
|
68724
|
+
if (run.state === "closed") return factsOfClosed(run, finishedAtMs);
|
|
68725
|
+
if (run.startedAt > finishedAtMs) return NC_UNKNOWN_CYCLE_FACTS;
|
|
68726
|
+
if (waited >= CYCLE_FACTS_WAIT_MS) return {
|
|
68727
|
+
durationMs: finishedAtMs - run.startedAt,
|
|
68728
|
+
energyKwh: null
|
|
68729
|
+
};
|
|
68730
|
+
await ports.sleep(CYCLE_FACTS_POLL_MS);
|
|
68731
|
+
waited += CYCLE_FACTS_POLL_MS;
|
|
68732
|
+
}
|
|
68733
|
+
};
|
|
68734
|
+
}
|
|
68735
|
+
//#endregion
|
|
68340
68736
|
//#region src/pipeline-analytics/runtime/wire-subscriptions.ts
|
|
68341
68737
|
/**
|
|
68342
68738
|
* Every category the Notification Center's system-event intake can turn into a
|
|
@@ -70298,6 +70694,7 @@ Object.freeze({
|
|
|
70298
70694
|
"page": 1,
|
|
70299
70695
|
"pageSize": 50
|
|
70300
70696
|
} },
|
|
70697
|
+
"device-runs": { "listRuns": { "limit": 50 } },
|
|
70301
70698
|
"llm": { "upsertProfile": { "profile": { "__nested__": {
|
|
70302
70699
|
"timeoutMs": 6e4,
|
|
70303
70700
|
"connectTimeoutMs": 1e4,
|
|
@@ -82301,147 +82698,6 @@ var NcDeviceMuteStore = class {
|
|
|
82301
82698
|
}
|
|
82302
82699
|
};
|
|
82303
82700
|
//#endregion
|
|
82304
|
-
//#region src/notification-center/record-kinds.ts
|
|
82305
|
-
/**
|
|
82306
|
-
* Record kinds owned by the pipeline-analytics addon (records plan phase 2,
|
|
82307
|
-
* steps 18-24): the notification-center config tables.
|
|
82308
|
-
*
|
|
82309
|
-
* The notification-center module is hosted inside the pipeline-analytics addon.
|
|
82310
|
-
* That addon declares no `execution.group`, so the UDS owner stamp is the addon
|
|
82311
|
-
* id: `pipeline-analytics`. Declared hub-only (agents have no `ctx.records`).
|
|
82312
|
-
* One deploy covers all 7 kinds.
|
|
82313
|
-
*/
|
|
82314
|
-
/**
|
|
82315
|
-
* The hub language and operator-authored per-key overrides.
|
|
82316
|
-
* One row, id `texts`. Losing it degrades to the shipped English catalog.
|
|
82317
|
-
*/
|
|
82318
|
-
var TextsBodySchema = object({
|
|
82319
|
-
language: NcLanguageSchema,
|
|
82320
|
-
overrides: partialRecord(NcLanguageSchema, record(string(), string()))
|
|
82321
|
-
});
|
|
82322
|
-
/**
|
|
82323
|
-
* A shared action sequence (without id, which is the record key).
|
|
82324
|
-
* Extends the wire shape with `createdAt` / `updatedAt` (stored by the legacy table).
|
|
82325
|
-
*/
|
|
82326
|
-
var SequenceBodySchema = NcSharedSequenceSchema.omit({ id: true }).extend({
|
|
82327
|
-
createdAt: number(),
|
|
82328
|
-
updatedAt: number()
|
|
82329
|
-
});
|
|
82330
|
-
/**
|
|
82331
|
-
* The AI section of one ordinary rule. Record id = the rule id.
|
|
82332
|
-
*/
|
|
82333
|
-
var RuleAiBodySchema = object({
|
|
82334
|
-
ai: NcRuleAiSchema,
|
|
82335
|
-
updatedAt: number()
|
|
82336
|
-
});
|
|
82337
|
-
/** A calendar-events rule (without `id`). */
|
|
82338
|
-
var CalendarEventsRuleBodySchema = NcCalendarEventsRuleSchema.omit({ id: true });
|
|
82339
|
-
/** A multi-camera digest rule (without `id`). */
|
|
82340
|
-
var SummaryRuleBodySchema = NcSummaryRuleSchema.omit({ id: true });
|
|
82341
|
-
/** A timelapse rule (without `id`). */
|
|
82342
|
-
var TimelapseRuleBodySchema = TimelapseRuleSchema.omit({ id: true });
|
|
82343
|
-
/** A notification rule (without `id`). */
|
|
82344
|
-
var RuleBodySchema = NcRuleSchema.omit({ id: true });
|
|
82345
|
-
var ncRecordKinds = defineRecordKinds({
|
|
82346
|
-
/**
|
|
82347
|
-
* The hub language + per-key text overrides. One row (id `texts`).
|
|
82348
|
-
*/
|
|
82349
|
-
texts: {
|
|
82350
|
-
schema: TextsBodySchema,
|
|
82351
|
-
class: "config",
|
|
82352
|
-
writeTrigger: "an operator changes the hub language (setLanguage) or replaces the per-key override set (setOverrides)",
|
|
82353
|
-
device: "none",
|
|
82354
|
-
at: "none",
|
|
82355
|
-
retention: { none: "one row (id `texts`); losing it costs the chosen language and household wording, never a notification — every read degrades to the shipped English catalog" }
|
|
82356
|
-
},
|
|
82357
|
-
/**
|
|
82358
|
-
* Shared action sequences — named, ordered runs of steps with their own throttle.
|
|
82359
|
-
* One row per sequence, id = sequence UUID.
|
|
82360
|
-
*/
|
|
82361
|
-
sequences: {
|
|
82362
|
-
schema: SequenceBodySchema,
|
|
82363
|
-
class: "config",
|
|
82364
|
-
writeTrigger: "an admin creates/edits/deletes a shared sequence via notificationRules.createSequence / updateSequence / deleteSequence, or the one-shot boot migration that materialises legacy inline sequences",
|
|
82365
|
-
device: "none",
|
|
82366
|
-
at: "none",
|
|
82367
|
-
retention: { none: "a row goes only when an admin deletes it; bounded by the sequence set a human is willing to author" }
|
|
82368
|
-
},
|
|
82369
|
-
/**
|
|
82370
|
-
* Per-rule AI section: whether and how a rule narrates itself.
|
|
82371
|
-
* Record id = the rule id it belongs to.
|
|
82372
|
-
*/
|
|
82373
|
-
"rule-ai": {
|
|
82374
|
-
schema: RuleAiBodySchema,
|
|
82375
|
-
class: "config",
|
|
82376
|
-
writeTrigger: "an operator switches the AI section of a notification rule on or off, or edits its prompt / word cap / language",
|
|
82377
|
-
device: "none",
|
|
82378
|
-
at: "none",
|
|
82379
|
-
retention: { none: "a row goes when the operator clears the section or deletes the rule; bounded by the rule set a human is willing to author" }
|
|
82380
|
-
},
|
|
82381
|
-
/**
|
|
82382
|
-
* Calendar-events rules. One row per rule, id = rule UUID.
|
|
82383
|
-
*/
|
|
82384
|
-
"calendar-events-rules": {
|
|
82385
|
-
schema: CalendarEventsRuleBodySchema,
|
|
82386
|
-
class: "config",
|
|
82387
|
-
writeTrigger: "an operator creates or edits a calendar-events rule, or the producer stamps a delivered window via markGenerated",
|
|
82388
|
-
device: "none",
|
|
82389
|
-
at: "none",
|
|
82390
|
-
indexes: [{
|
|
82391
|
-
name: "enabled",
|
|
82392
|
-
fields: ["enabled"]
|
|
82393
|
-
}],
|
|
82394
|
-
retention: { none: "a row goes only when the operator deletes the rule; bounded by the rule set a human is willing to author" }
|
|
82395
|
-
},
|
|
82396
|
-
/**
|
|
82397
|
-
* Multi-camera digest rules. One row per rule, id = rule UUID.
|
|
82398
|
-
*/
|
|
82399
|
-
"summary-rules": {
|
|
82400
|
-
schema: SummaryRuleBodySchema,
|
|
82401
|
-
class: "config",
|
|
82402
|
-
writeTrigger: "an operator creates or edits a digest rule, or the producer stamps a delivered window via markGenerated",
|
|
82403
|
-
device: "none",
|
|
82404
|
-
at: "none",
|
|
82405
|
-
indexes: [{
|
|
82406
|
-
name: "enabled",
|
|
82407
|
-
fields: ["enabled"]
|
|
82408
|
-
}],
|
|
82409
|
-
retention: { none: "a row goes only when the operator deletes the rule; bounded by the rule set a human is willing to author" }
|
|
82410
|
-
},
|
|
82411
|
-
/**
|
|
82412
|
-
* Timelapse rules. One row per rule, id = rule UUID.
|
|
82413
|
-
* Three rows on prod (2026-10-18).
|
|
82414
|
-
*/
|
|
82415
|
-
"timelapse-rules": {
|
|
82416
|
-
schema: TimelapseRuleBodySchema,
|
|
82417
|
-
class: "config",
|
|
82418
|
-
writeTrigger: "an operator creates or edits a timelapse rule, or the scheduler stamps a successful per-camera generation via markGenerated",
|
|
82419
|
-
device: "none",
|
|
82420
|
-
at: "none",
|
|
82421
|
-
indexes: [{
|
|
82422
|
-
name: "enabled",
|
|
82423
|
-
fields: ["enabled"]
|
|
82424
|
-
}],
|
|
82425
|
-
retention: { none: "a row goes only when the operator deletes the rule; bounded by the rule set a human is willing to author" }
|
|
82426
|
-
},
|
|
82427
|
-
/**
|
|
82428
|
-
* Notification rules — the main rule set. One row per rule, id = rule UUID.
|
|
82429
|
-
* 18 rows on prod (2026-10-18); most coupled kind in this owner.
|
|
82430
|
-
*/
|
|
82431
|
-
rules: {
|
|
82432
|
-
schema: RuleBodySchema,
|
|
82433
|
-
class: "config",
|
|
82434
|
-
writeTrigger: "an operator creates, edits, enables/disables a rule or opts a target out of it; nothing writes on the evaluation path",
|
|
82435
|
-
device: "none",
|
|
82436
|
-
at: "none",
|
|
82437
|
-
indexes: [{
|
|
82438
|
-
name: "delivery",
|
|
82439
|
-
fields: ["delivery"]
|
|
82440
|
-
}],
|
|
82441
|
-
retention: { none: "a row goes only when the operator deletes the rule; bounded by the rule set a human is willing to author" }
|
|
82442
|
-
}
|
|
82443
|
-
});
|
|
82444
|
-
//#endregion
|
|
82445
82701
|
//#region src/notification-center/sequence-store.ts
|
|
82446
82702
|
/**
|
|
82447
82703
|
* Shared action sequences for the notification centre.
|
|
@@ -87526,6 +87782,56 @@ var NcDispatcher = class {
|
|
|
87526
87782
|
renderText(input) {
|
|
87527
87783
|
return renderRowText(this.texts, input);
|
|
87528
87784
|
}
|
|
87785
|
+
/** Rules already warned about a deprecated variable in this process — once each. */
|
|
87786
|
+
deprecatedVarWarned = /* @__PURE__ */ new Set();
|
|
87787
|
+
/**
|
|
87788
|
+
* A rule template written by an older client may still say `{{camera}}`. It
|
|
87789
|
+
* renders (the alias), and the rule is named once so the operator can edit it.
|
|
87790
|
+
*/
|
|
87791
|
+
warnDeprecatedVars(entry) {
|
|
87792
|
+
if (this.deprecatedVarWarned.has(entry.ruleId)) return;
|
|
87793
|
+
const template = entry.payload.template;
|
|
87794
|
+
const used = [...new Set([...deprecatedPlaceholders(template?.title), ...deprecatedPlaceholders(template?.body)])];
|
|
87795
|
+
if (used.length === 0) return;
|
|
87796
|
+
this.deprecatedVarWarned.add(entry.ruleId);
|
|
87797
|
+
this.deps.logger.warn("rule template uses a renamed variable — it still renders, edit it to the new name", {
|
|
87798
|
+
tags: { ruleId: entry.ruleId },
|
|
87799
|
+
meta: {
|
|
87800
|
+
variables: used,
|
|
87801
|
+
replacement: "device"
|
|
87802
|
+
}
|
|
87803
|
+
});
|
|
87804
|
+
}
|
|
87805
|
+
/**
|
|
87806
|
+
* The facts of a finished appliance cycle; unknown on every other row and on
|
|
87807
|
+
* any failure (a part that cannot be read is omitted, never a blocked send).
|
|
87808
|
+
*/
|
|
87809
|
+
async applianceCycleFacts(entry) {
|
|
87810
|
+
const subject = entry.payload.subject;
|
|
87811
|
+
const resolve = this.deps.resolveApplianceCycleFacts;
|
|
87812
|
+
const deviceId = subject.applianceCycle?.deviceId;
|
|
87813
|
+
if (resolve === void 0 || deviceId === void 0) return NC_UNKNOWN_CYCLE_FACTS;
|
|
87814
|
+
try {
|
|
87815
|
+
const facts = await resolve({
|
|
87816
|
+
deviceId,
|
|
87817
|
+
finishedAtMs: subject.timestamp
|
|
87818
|
+
});
|
|
87819
|
+
if (facts.durationMs === null || facts.energyKwh === null) this.deps.logger.debug("appliance cycle part omitted — unknown", {
|
|
87820
|
+
tags: { deviceId },
|
|
87821
|
+
meta: {
|
|
87822
|
+
duration: facts.durationMs === null ? "unknown" : "known",
|
|
87823
|
+
energy: facts.energyKwh === null ? "unknown" : "known"
|
|
87824
|
+
}
|
|
87825
|
+
});
|
|
87826
|
+
return facts;
|
|
87827
|
+
} catch (err) {
|
|
87828
|
+
this.deps.logger.debug("appliance cycle facts failed — parts omitted", {
|
|
87829
|
+
tags: { deviceId },
|
|
87830
|
+
meta: { error: err instanceof Error ? err.message : String(err) }
|
|
87831
|
+
});
|
|
87832
|
+
return NC_UNKNOWN_CYCLE_FACTS;
|
|
87833
|
+
}
|
|
87834
|
+
}
|
|
87529
87835
|
/**
|
|
87530
87836
|
* Builds the notification AND returns the artefact ids its media resolve
|
|
87531
87837
|
* indexed — see {@link withArtifactUrls}. A tuple rather than a field on
|
|
@@ -87538,7 +87844,9 @@ var NcDispatcher = class {
|
|
|
87538
87844
|
const deviceName = await notificationDeviceName(entry, this.deps.getDeviceName);
|
|
87539
87845
|
const alarmSource = systemEvent?.alarmSource;
|
|
87540
87846
|
const zoneLabels = systemEvent === void 0 ? await resolveZoneLabels(this.deps.getZoneNames, subject.deviceId, subject.zones) : alarmSource?.zones !== void 0 && alarmSource.zones.length > 0 ? await resolveZoneLabels(this.deps.getZoneNames, alarmSource.deviceId, alarmSource.zones) : [];
|
|
87541
|
-
const
|
|
87847
|
+
const cycleFacts = await this.applianceCycleFacts(entry);
|
|
87848
|
+
const vars = buildTemplateVars(this.texts, entry, deviceName, zoneLabels, void 0, cycleFacts);
|
|
87849
|
+
this.warnDeprecatedVars(entry);
|
|
87542
87850
|
const systemCount = systemEvent?.textCount !== void 0 ? { count: systemEvent.textCount } : {};
|
|
87543
87851
|
const title = renderRowTitle(this.texts, entry, vars);
|
|
87544
87852
|
const authoredBody = entry.payload.template?.body;
|
|
@@ -88653,15 +88961,15 @@ async function resolveZoneLabels(getZoneNames, deviceId, zoneIds) {
|
|
|
88653
88961
|
function percentOf(confidence) {
|
|
88654
88962
|
return confidence !== void 0 ? `${Math.round(confidence * 100)}%` : "";
|
|
88655
88963
|
}
|
|
88656
|
-
/** What `{{
|
|
88964
|
+
/** What `{{device}}` renders on a system row that names no device. */
|
|
88657
88965
|
var NC_DEVICELESS_CAMERA_NAME = "system";
|
|
88658
88966
|
/**
|
|
88659
|
-
* The name `{{
|
|
88967
|
+
* The name `{{device}}` renders for a row — the ONE derivation, shared by the
|
|
88660
88968
|
* dispatcher and the template-variable parity spec.
|
|
88661
88969
|
*
|
|
88662
88970
|
* A system row that names no device (a node, a backup, an update) renders the
|
|
88663
88971
|
* filler {@link NC_DEVICELESS_CAMERA_NAME}: there is no camera to name, which
|
|
88664
|
-
* is why the catalog offers `{{
|
|
88972
|
+
* is why the catalog offers `{{device}}` on a system rule only for the kinds
|
|
88665
88973
|
* that carry a device (template-vars.ts). Everything else asks the directory,
|
|
88666
88974
|
* and falls back to `camera <id>` when it cannot answer.
|
|
88667
88975
|
*/
|
|
@@ -88704,7 +89012,7 @@ function systemEventParamsForTemplate(params) {
|
|
|
88704
89012
|
const { form: _form, attention: _attention, ...rest } = params;
|
|
88705
89013
|
return rest;
|
|
88706
89014
|
}
|
|
88707
|
-
function buildTemplateVars(texts, entry, deviceName, zoneLabels, timeZone) {
|
|
89015
|
+
function buildTemplateVars(texts, entry, deviceName, zoneLabels, timeZone, cycle) {
|
|
88708
89016
|
const subject = entry.payload.subject;
|
|
88709
89017
|
const occupancy = subject.occupancy;
|
|
88710
89018
|
const systemEvent = subject.systemEvent;
|
|
@@ -88714,7 +89022,7 @@ function buildTemplateVars(texts, entry, deviceName, zoneLabels, timeZone) {
|
|
|
88714
89022
|
const cameraName = deviceName.toLocaleLowerCase(locale);
|
|
88715
89023
|
const zonesLower = zoneLabels.map((z) => z.toLocaleLowerCase(locale));
|
|
88716
89024
|
return {
|
|
88717
|
-
|
|
89025
|
+
device: cameraName,
|
|
88718
89026
|
class: detection?.className ?? (systemEvent !== void 0 ? "" : subject.className),
|
|
88719
89027
|
classLabel: (() => {
|
|
88720
89028
|
const wire = detection?.className ?? (systemEvent !== void 0 ? "" : subject.className);
|
|
@@ -88740,6 +89048,7 @@ function buildTemplateVars(texts, entry, deviceName, zoneLabels, timeZone) {
|
|
|
88740
89048
|
hitPercent: subject.audio?.hitPercent !== void 0 ? `${Math.round(subject.audio.hitPercent)}` : "",
|
|
88741
89049
|
db: subject.audio?.peakDbfs !== void 0 ? `${Math.round(subject.audio.peakDbfs)}` : "",
|
|
88742
89050
|
eventType: subject.eventType ?? "",
|
|
89051
|
+
...cycle !== void 0 ? ncApplianceCycleVars(texts, cycle) : NC_EMPTY_CYCLE_VARS,
|
|
88743
89052
|
rule: entry.payload.ruleName,
|
|
88744
89053
|
count: occupancy !== void 0 ? `${occupancy.count}` : group !== void 0 && group.members.length > 1 ? `${group.members.length}` : "",
|
|
88745
89054
|
capacity: occupancy !== void 0 ? `${occupancy.capacity}` : "",
|
|
@@ -88766,6 +89075,7 @@ function bodyKeyFor(entry) {
|
|
|
88766
89075
|
const subject = entry.payload.subject;
|
|
88767
89076
|
if (subject.systemEvent !== void 0) return subject.systemEvent.bodyKey ?? "";
|
|
88768
89077
|
if (subject.occupancy !== void 0) return "occupancy.body";
|
|
89078
|
+
if (subject.applianceCycle !== void 0) return "appliance.finished.body";
|
|
88769
89079
|
if (subject.packagePhase === "delivered" && subject.packagePossible === true) return "package.delivered.possible.body";
|
|
88770
89080
|
if (subject.packagePhase !== void 0) return `package.${subject.packagePhase}.body`;
|
|
88771
89081
|
return entry.recordKind === "track-end" ? "detection.body.trackEnd" : "detection.body";
|
|
@@ -88803,7 +89113,7 @@ function renderRowTitle(texts, entry, vars) {
|
|
|
88803
89113
|
const systemEvent = entry.payload.subject.systemEvent;
|
|
88804
89114
|
const intrusion = entry.payload.alarmIntrusion;
|
|
88805
89115
|
const count = systemEvent?.textCount;
|
|
88806
|
-
|
|
89116
|
+
const rendered = renderRowText(texts, {
|
|
88807
89117
|
template: intrusion !== void 0 ? void 0 : entry.payload.template?.title,
|
|
88808
89118
|
key: titleKeyFor(entry),
|
|
88809
89119
|
vars: intrusion !== void 0 ? {
|
|
@@ -88813,11 +89123,13 @@ function renderRowTitle(texts, entry, vars) {
|
|
|
88813
89123
|
...count !== void 0 ? { count } : {},
|
|
88814
89124
|
frozen: systemEvent?.title ?? entry.payload.ruleName
|
|
88815
89125
|
});
|
|
89126
|
+
return titleKeyFor(entry) === "appliance.finished.title" && entry.payload.template?.title === void 0 ? ncSentenceCaseBody(rendered) : rendered;
|
|
88816
89127
|
}
|
|
88817
89128
|
/** The default TITLE key — same shape, same pre-catalog reasoning. */
|
|
88818
89129
|
function titleKeyFor(entry) {
|
|
88819
89130
|
const systemEvent = entry.payload.subject.systemEvent;
|
|
88820
89131
|
if (systemEvent !== void 0) return systemEvent.titleKey ?? "";
|
|
89132
|
+
if (entry.payload.subject.applianceCycle !== void 0) return "appliance.finished.title";
|
|
88821
89133
|
if (entry.payload.alarmIntrusion !== void 0) return "alarm.intrusion.title";
|
|
88822
89134
|
const packagePhase = entry.payload.subject.packagePhase;
|
|
88823
89135
|
if (packagePhase === "delivered" && entry.payload.subject.packagePossible === true) return "package.delivered.possible.title";
|
|
@@ -96578,7 +96890,7 @@ function clockOf(atMs) {
|
|
|
96578
96890
|
* catalog, the same way `buildTemplateVars` is asserted for rule rows. */
|
|
96579
96891
|
function timelapseTemplateVars(input) {
|
|
96580
96892
|
return {
|
|
96581
|
-
|
|
96893
|
+
device: input.deviceName ?? `camera ${input.deviceId}`,
|
|
96582
96894
|
rule: input.ruleName,
|
|
96583
96895
|
from: clockOf(input.window.startMs),
|
|
96584
96896
|
to: clockOf(input.window.endMs),
|
|
@@ -96644,7 +96956,7 @@ function paramsFor(target, clickUrl) {
|
|
|
96644
96956
|
*/
|
|
96645
96957
|
function timelapsePreviewText(input) {
|
|
96646
96958
|
const vars = {
|
|
96647
|
-
|
|
96959
|
+
device: input.deviceName ?? `camera ${input.deviceId}`,
|
|
96648
96960
|
...input.ruleName !== void 0 ? { rule: input.ruleName } : {},
|
|
96649
96961
|
...input.window !== void 0 ? {
|
|
96650
96962
|
from: clockOf(input.window.startMs),
|
|
@@ -101889,6 +102201,7 @@ function buildEntries(host, rule, subject, kind, matchedOn, userTargets = [], or
|
|
|
101889
102201
|
...subject.audioWindow.peakDbfs !== void 0 ? { peakDbfs: subject.audioWindow.peakDbfs } : {}
|
|
101890
102202
|
} } : {},
|
|
101891
102203
|
...subject.eventType !== void 0 ? { eventType: subject.eventType } : {},
|
|
102204
|
+
...applianceCycleOf(subject),
|
|
101892
102205
|
...subject.systemEvent !== void 0 ? { systemEvent: subject.systemEvent } : {}
|
|
101893
102206
|
}
|
|
101894
102207
|
};
|
|
@@ -104176,7 +104489,7 @@ function buildSnoozeDigest(texts, snooze, rows, deviceNames) {
|
|
|
104176
104489
|
key: "snooze.digest.line",
|
|
104177
104490
|
vars: {
|
|
104178
104491
|
rule: r.ruleName,
|
|
104179
|
-
|
|
104492
|
+
device: deviceNames.get(r.deviceId) ?? `camera ${r.deviceId}`,
|
|
104180
104493
|
count: `${r.count}`
|
|
104181
104494
|
}
|
|
104182
104495
|
}));
|
|
@@ -109626,6 +109939,7 @@ var BuildNotificationCenter = class extends BuildNotificationCenterBase {
|
|
|
109626
109939
|
}));
|
|
109627
109940
|
},
|
|
109628
109941
|
getDeviceName,
|
|
109942
|
+
resolveApplianceCycleFacts: this.deps.resolveApplianceCycleFacts,
|
|
109629
109943
|
getDeviceLocation,
|
|
109630
109944
|
buildActions: (input) => this.notificationCenter?.mintButtons(input) ?? Promise.resolve([])
|
|
109631
109945
|
},
|
|
@@ -122811,6 +123125,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
122811
123125
|
return out;
|
|
122812
123126
|
};
|
|
122813
123127
|
await step("declareCollections", () => this.declareCollections(api));
|
|
123128
|
+
if (this.localOwnNodeId() === "hub") await step("migrations", () => this.runTemplateMigrations());
|
|
122814
123129
|
this.armAlarmPanelDeclaration(api);
|
|
122815
123130
|
const logger = this.ctx.logger;
|
|
122816
123131
|
const storage = await step("resolveMediaStorage", () => this.resolveMediaStorage(logger));
|
|
@@ -123161,6 +123476,16 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
123161
123476
|
});
|
|
123162
123477
|
return this.collectionsBootInstance;
|
|
123163
123478
|
}
|
|
123479
|
+
/** The addon's migration catalogue (D987), bound to the notification kinds. */
|
|
123480
|
+
async runTemplateMigrations() {
|
|
123481
|
+
const records = this.requireRecords();
|
|
123482
|
+
const ports = {
|
|
123483
|
+
rules: records.kind(ncRecordKinds["rules"]),
|
|
123484
|
+
timelapseRules: records.kind(ncRecordKinds["timelapse-rules"]),
|
|
123485
|
+
texts: records.kind(ncRecordKinds.texts)
|
|
123486
|
+
};
|
|
123487
|
+
await this.runMigrations(defineAddonMigrations(ADDON_MIGRATIONS, ports));
|
|
123488
|
+
}
|
|
123164
123489
|
/** `declare-collections.ts` — declareCollections. */
|
|
123165
123490
|
async declareCollections(api) {
|
|
123166
123491
|
return this.collectionsBoot.declareCollections(api);
|
|
@@ -123486,7 +123811,16 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
123486
123811
|
buildTimelapsePorts: (api, stores) => this.buildTimelapsePorts(api, stores),
|
|
123487
123812
|
buildSummaryPorts: (api, stores) => this.buildSummaryPorts(api, stores),
|
|
123488
123813
|
wireAlarmPanel: (center) => this.wireAlarmPanel(center),
|
|
123489
|
-
serveNcActionPlane: (center) => this.serveNcActionPlane(center)
|
|
123814
|
+
serveNcActionPlane: (center) => this.serveNcActionPlane(center),
|
|
123815
|
+
resolveApplianceCycleFacts: applianceCycleFactsFromRuns({
|
|
123816
|
+
newestRun: async (deviceId) => {
|
|
123817
|
+
return (await this.ctx.api.deviceRuns.listRuns.query({
|
|
123818
|
+
deviceId,
|
|
123819
|
+
limit: 1
|
|
123820
|
+
})).runs[0] ?? null;
|
|
123821
|
+
},
|
|
123822
|
+
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms))
|
|
123823
|
+
})
|
|
123490
123824
|
});
|
|
123491
123825
|
return this.notificationCenterBootInstance;
|
|
123492
123826
|
}
|