@camstack/addon-post-analysis 1.2.669 → 1.2.671
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 +13 -0
- package/dist/{clip-model-registry-CbzBwacH.js → clip-model-registry-BhKHkBsg.js} +573 -547
- package/dist/{clip-model-registry-BPvijtCz.mjs → clip-model-registry-CDLYwWsU.mjs} +568 -548
- 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-C4QK9e1e.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-CRWJsnQv.mjs} +2 -2
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D0SgNf77.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-DFMFx1IF.mjs +26 -0
- package/dist/pipeline-analytics/{hostInit-CPLvPO3K.mjs → hostInit-D503xVER.mjs} +2 -2
- package/dist/pipeline-analytics/index.js +252 -41
- package/dist/pipeline-analytics/index.mjs +252 -41
- 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-9HsFj_VL.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-anSYIl3S.mjs +0 -26
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as MAX_TRACK_RELATIONS, $i as
|
|
1
|
+
import { $ as MAX_TRACK_RELATIONS, $i as withSystemEventClasses, $n as buildViewerLink, $r as ncMediaPolicyError, $t as NcTemplatePreviewSchema, A as DETECTION_MACRO_CLASSES, Aa as partialRecord, Ai as ruleGroupingApplies, An as TrackPlacementSchema, Ar as isAlarmControllableCap, At as NcAlarmConfigSchema, B as EXPORT_DENSE_MAX_RANGES, Ba as EventCategory, Bi as subjectPathSvgPoints, Bn as alertEpisodeId, Br as isKnownTemplateVar, Bt as NcRuleSchema, C as COCO_TO_MACRO, Ca as array, Ci as resolveNcMediaImage, Cn as SetTrackPurityResultSchema, Cr as ensureAlarmProfiles, Ct as NC_GROUPING_MIN_SEC, D as DEFAULT_DETAIL_CROP_CONVENTION, Da as looseObject, Di as ruleAutoTriggersAlarm, Dn as TimelapseRuleInputSchema, Dr as failureContributionCapability, Dt as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, E as CoverStateSchema, Ea as literal, Ei as rootSupplyServes, En as TRACK_RELATIONS_DEFAULT_LIMIT, Er as faceGalleryCapability, Et as NC_STATE_SUMMARY_SECTION_IDS, F as EMBEDDING_REQUIREMENTS_FAILED, Fa as tuple, Fi as servedTemplateVars, Fn as TrackSourceSchema, Fr as isDefaultAlarmProfileId, Ft as NcConditionDescriptorSchema, G as LabelAttributionSchema, Gi as systemEventFamilyProblems, Gn as applyNonBlockingEdit, Gr as isScheduleActive, Gt as NcSnoozeInputSchema, H as FULL_IMAGE_BBOX, Hi as sunTimes, Hn as alertEpisodePayload, Hr as isMediaOwnerType, Ht as NcRuleUpdateInputSchema, I as EMBEDDING_REQUIREMENTS_UNAVAILABLE, Ia as union, Ii as startMoverUnderClearance, In as activateAlarmProfile, Ir as isDetectionMacroClass, It as NcConditionsSchema, J as LockStateSchema, Ji as systemEventSummarySplitOf, Jn as assertTimelapseCadences, Jr as isVectorIndexDimConflict, Jt as NcStateSummarySectionIdSchema, K as ListTrackRelationsInputSchema, Ki as systemEventFilterApplies, Kn as applySecureOnArmEdit, Kr as isSystemDelivery, Kt as NcSnoozeSchema, L as EVENT_DENSITY_BATCH_MAX, La as unknown, Li as storageOccupancyCapability, Ln as addonWidgetsSourceCapability, Lr as isDrawableSubjectPath, Lt as NcRuleActionSchema, M as DeclaredDevices, Ma as strictObject, Mi as sceneMonitorCapability, Mn as TrackRelationKindSchema, Mr as isAlertEpisodeSeverity, Mt as NcAlarmSensorsInputSchema, N as DetectionSourceSchema, Na as string, Ni as secureActuationFor, Nn as TrackRelationSchema, Nr as isAppLinkBase, Nt as NcAlarmSensorsSchema, O as DEFAULT_EVENT_COLOR, Oa as number, Oi as ruleBelongsToAlarm$1, On as TimelapseRulePatchSchema, Or as gifDeriveSpeed, Ot as NC_TAXONOMY, P as EMBEDDING_MODEL_FAILED, Pa as templateLiteral, Pi as sensorRaisedOf, Pn as TrackSideSchema, Pr as isAudioClassName, Pt as NcAlarmSettingsPatchSchema, Q as MAX_TRACK_PURITIES, Qi as viewerLinkBaseOf, Qn as buildSubjectPath, Qr as memoizePinnedFfmpeg, Qt as NcTemplatePreviewInputSchema, R as EVENT_KIND_BY_CAP, Ra as DeviceType, Ri as subKindsOf, Rn as alarmDeviceSecureOnArm, Rr as isEventKindLabelKey, Rt as NcRuleInputSchema, S as BucketAccumulator, Sa as _enum, Si as resolveModeNotifyPolicy, Sn as SetTrackPurityInputSchema, Sr as encodeVectorBase64, St as NC_GROUPING_MAX_SEC, T as ClearTrackRelationResultSchema, Ta as discriminatedUnion, Ti as retrainRevisionConflictMessage, Tn as TIMELAPSE_DENSE_FLOOR_SEC, Tr as evictionPolicyOfLocation, Tt as NC_SNOOZE_MAX_MINUTES, U as FailureCounters, Ui as syncActiveAlarmProfileSettings, Un as applyBlockingEdit, Ur as isRetiredClearKey, Ut as NcScheduleSchema, V as FIRST_LEVEL_MACRO_CLASSES, Vi as summarizeReview, Vn as alertEpisodeKind, Vr as isLabelSupplyStepId, Vt as NcRuleTargetSchema, W as LABEL_SUPPLY_MACRO, Wi as systemEventDeliveryProblems, Wn as applyModeDelaysEdits, Wr as isRootSuppliableStepId, Wt as NcSharedSequenceSchema, X as MAX_BIRTH_DECISION_RECORDS, Xi as templateVarsFor, Xn as audioModeOf, Xr as linkedStepOf, Xt as NcTaxonomySchema, Y as MAX_ARCHIVED_DEBUG_NOTES, Yi as templateCarriesSummary, Yn as audioMetricsCapability, Yr as kebabToCamel, Yt as NcSystemEventKindSchema, Z as MAX_BIRTH_LATENCY_PROXY_MS, Zi as vectorDimFromBase64, Zn as buildEventKindDescriptor, Zr as mayWriteToLocation, Zt as NcTemplateDefaultSchema, _ as AlarmArmModeSchema, _a as isDeviceScopedCap, _i as renameAlarmProfile, _n as SCENE_DEFAULT_QUIET_SECONDS, _t as NC_CONFIRM_DEFAULT_TIMEOUT_MS, a as CLIP_EMBEDDING_STEP_ID, aa as BaseAddon, ai as paintHex, an as RECORDING_EXPORT_MAX_READ_BYTES, ar as consumableLowPercentOf, at as NC_ALARM_DELAY_FIELDS, b as BaseDevice, ba as sleep$1, bi as resolveLocationMode, bn as SCENE_RESET_RECAPTURES, bt as NC_DEFAULT_SNOOZE_MINUTES, c as readClusterModelPinStrict, ca as InvalidRecordError, cn as RetrainDismissedSchema, cr as createAlarmProfile, ct as NC_ALARM_SYSTEM_EVENT_KINDS, d as APPEARANCE_BIN_COUNT, da as createEvent, di as plateGalleryCapability, dn as RetrainVerdictSubjectSchema, dr as derivePostTriggeredAction, dt as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, ea as zoneAnalyticsCapability, ei as normalizeNcAction, en as NcTemplateVarDescriptorSchema, er as bundledCamstack, et as MOTION_CLOSE_AFTER_MS, f as APPEARANCE_BLOCKS, fa as customAction, fi as preconditionOf, fn as SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX, fr as deriveRecordingMode, ft as NC_CLIP_POST_ROLL_DEFAULT_SEC, g as ActionTargetResolver, ga as hydrateSchema, gi as readTimelapseGeneratedAt, gn as SCENE_DEFAULT_OBSERVATION_SPACING_SEC, gr as deviceRemovalHookCapability, gt as NC_CONFIRM_DEFAULT_MAX_IMAGE_PX, h as AUDIO_MACRO_LABELS, ha as defineRecordKinds, hi as readMotionTriggeredBy, hn as SCENE_DEFAULT_CHECK_INTERVAL_SEC, hr as deviceAttentionKind, ht as NC_CONDITION_CATALOG, ia as isSourceCap, ii as occupancyScope, ir as consumableFormOf, it as NC_ALARM_DEFAULT_TRIGGERED_DURATION_SEC, j as DETECTION_PIPELINE_CAP_NAME, ja as record, ji as ruleKindOf, jn as TrackPuritySchema, jr as isAlertEpisodeOpen, jt as NcAlarmPostTriggeredActionSchema, k as DEFAULT_TIMELAPSE_PREVIEW_TEXT, ka as object, ki as ruleDeviceCompatCapQueries, kn as TimelapseRuleSchema, kr as gifFromMp4Args, kt as NC_TEMPLATE_VARS, l as resolveClusterModelPin, la as RECORD_MAX_DATA_BYTES, li as pickFaceRescoreIntervalMinutes, ln as RetrainOriginSchema, lr as deleteAlarmProfile, lt as NC_ALARM_TRIGGERED_MAX_SEC, m as ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT, ma as defineCustomActions, mi as readDeviceStateFrom, mn as SCENE_DEFAULT_ANCHOR_THRESHOLD, mr as describeSystemEventFamilyProblem, mt as NC_CLIP_RETENTION_MAX_SEC, na as canonicalHash, ni as normalizeNcMediaPolicy, nn as OpsLogEntrySchema, nr as classifyRetrainReview, nt as MotionTriggeredBySchema, o as CLUSTER_MODEL_OWNER_ADDON_ID, oa as CAP_ADVANCE_FIELDS, oi as paletteResultSchema, on as RECORDING_SOURCE_CAMSTACK_ADDON, or as coreBlockIdFromAddonId, ot as NC_ALARM_DELAY_MAX_SEC, p as APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT, pa as defineAddonMigrations, pi as projectSubjectPath, pn as SCENE_CONFIRM_DEFAULT_TIMEOUT_MS, pr as describeSystemEventDeliveryProblem, pt as NC_CLIP_PRE_ROLL_DEFAULT_SEC, q as ListTrackRelationsResultSchema, qi as systemEventSummaryScheduleOf, qn as armRemovalReconcile, qr as isSystemEventSummaryRule, qt as NcSnoozeSuppressedSchema, ra as evaluateSensorEdge, ri as notificationRulesCapability, rn as PackageLlmVerdictSchema, rr as cloneAlarmSettings, rt as NC_ALARM_DEFAULT_PROFILE_ID, s as FACE_EMBEDDING_STEP_ID, sa as CamProfileSchema, si as parseAlertEpisodePayload, sn as RebuildObjectEmbeddingsRefusalSchema, sr as cosineSimilarity$1, st as NC_ALARM_NOTIFY_FIELDS, t as BUILTIN_CLIP_MODELS, ta as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, ti as normalizeNcCapTarget, tn as OPS_LOG_DEFAULT_LIMIT, tr as calendarEventLocalSpan, tt as MediaFileKindEnum, u as ACTION_TARGET_INVALIDATION_EVENTS, ua as RECORD_QUERY_MAX, ui as pipelineAnalyticsCapability, un as RetrainStatusSchema, ur as deriveDetailCropRect, ut as NC_AUDIO_CONFIRM_HITS_DEFAULT, v as ArchivedDebugNoteSchema, va as nodePin, vi as resolveClipSearchMinScore, vn as SCENE_DEFAULT_UNCOVERED_POLICY, vt as NC_CONSUMABLE_LOW_PERCENT_DEFAULT, w as ClearTrackRelationInputSchema, wa as boolean, wn as SetTrackRelationInputSchema, wr as eventKindLabel, wt as NC_SENSOR_TRANSITION_KINDS, x as BirthDecisionRecordSchema, xa as ZodObject, xi as resolveModeDelays, xn as SceneMonitorSchema, xt as NC_GROUPING_DEFAULT_SEC, y as BIRTH_DECISION_DEFAULT_LIMIT, yi as resolveDeliveryParams, yn as SCENE_DIVERGED, yr as embeddingRefusalOf, yt as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, z as EVENT_OWNER_TYPES, za as errMsg, zi as subjectPathSampleFromBox, zn as alarmPanelCapability, zr as isEventOwnerType, zt as NcRulePatchSchema } from "../clip-model-registry-CDLYwWsU.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";
|
|
@@ -16750,6 +16750,68 @@ var MediaStore = class MediaStore {
|
|
|
16750
16750
|
};
|
|
16751
16751
|
}
|
|
16752
16752
|
/**
|
|
16753
|
+
* Rows and bytes per asked storage location, the unstamped (NULL) rows, the
|
|
16754
|
+
* rows naming a location that was NOT asked about, and the total.
|
|
16755
|
+
*
|
|
16756
|
+
* Same statements as {@link footprintByLocation} (one aggregate over
|
|
16757
|
+
* `idx_media_location_size` per location, one for NULL) plus one unfiltered
|
|
16758
|
+
* aggregate for the total (a covering-index scan, O(rows)); the unlisted
|
|
16759
|
+
* remainder is the difference, relative to the ids ASKED, so a row stamped with
|
|
16760
|
+
* a deleted location is counted without a distinct walk only when the caller
|
|
16761
|
+
* asked for every live location. A read that fails THROWS — never a zero.
|
|
16762
|
+
*/
|
|
16763
|
+
async censusByLocation(locationIds) {
|
|
16764
|
+
const fields = [{
|
|
16765
|
+
as: "bytes",
|
|
16766
|
+
field: "sizeBytes",
|
|
16767
|
+
op: "sum"
|
|
16768
|
+
}];
|
|
16769
|
+
const locations = [];
|
|
16770
|
+
let knownRows = 0;
|
|
16771
|
+
let knownBytes = 0;
|
|
16772
|
+
for (const locationId of locationIds) {
|
|
16773
|
+
const agg = await this.store.aggregate.query({
|
|
16774
|
+
collection: MEDIA_COLLECTION,
|
|
16775
|
+
fields: [...fields],
|
|
16776
|
+
filter: { where: { locationId } }
|
|
16777
|
+
});
|
|
16778
|
+
const bytes = agg.values["bytes"] ?? 0;
|
|
16779
|
+
locations.push({
|
|
16780
|
+
locationId,
|
|
16781
|
+
rows: agg.count,
|
|
16782
|
+
bytes
|
|
16783
|
+
});
|
|
16784
|
+
knownRows += agg.count;
|
|
16785
|
+
knownBytes += bytes;
|
|
16786
|
+
}
|
|
16787
|
+
const nullAgg = await this.store.aggregate.query({
|
|
16788
|
+
collection: MEDIA_COLLECTION,
|
|
16789
|
+
fields: [...fields],
|
|
16790
|
+
filter: { where: { locationId: null } }
|
|
16791
|
+
});
|
|
16792
|
+
const totalAgg = await this.store.aggregate.query({
|
|
16793
|
+
collection: MEDIA_COLLECTION,
|
|
16794
|
+
fields: [...fields]
|
|
16795
|
+
});
|
|
16796
|
+
const nullBytes = nullAgg.values["bytes"] ?? 0;
|
|
16797
|
+
const totalBytes = totalAgg.values["bytes"] ?? 0;
|
|
16798
|
+
return {
|
|
16799
|
+
locations,
|
|
16800
|
+
unstamped: {
|
|
16801
|
+
rows: nullAgg.count,
|
|
16802
|
+
bytes: nullBytes
|
|
16803
|
+
},
|
|
16804
|
+
unlisted: {
|
|
16805
|
+
rows: Math.max(0, totalAgg.count - knownRows - nullAgg.count),
|
|
16806
|
+
bytes: Math.max(0, totalBytes - knownBytes - nullBytes)
|
|
16807
|
+
},
|
|
16808
|
+
total: {
|
|
16809
|
+
rows: totalAgg.count,
|
|
16810
|
+
bytes: totalBytes
|
|
16811
|
+
}
|
|
16812
|
+
};
|
|
16813
|
+
}
|
|
16814
|
+
/**
|
|
16753
16815
|
* The media footprint broken down by KIND — fleet-wide, or for one camera.
|
|
16754
16816
|
*
|
|
16755
16817
|
* `footprintByDevice` answers "how much is where"; this answers "how much is
|
|
@@ -52446,7 +52508,7 @@ var FaceSettingsSchema = object({
|
|
|
52446
52508
|
* `resolveGlobalFaceEnabled` / `getDeviceSettingsContribution` (the field is
|
|
52447
52509
|
* stripped from the per-device schema).
|
|
52448
52510
|
*/
|
|
52449
|
-
|
|
52511
|
+
faceRecognitionEnabled: boolean().default(true),
|
|
52450
52512
|
/**
|
|
52451
52513
|
* Cosine similarity (on L2-normalized embeddings) required to match. A
|
|
52452
52514
|
* property of ONE model's cosine space: it moves with the default model.
|
|
@@ -52548,7 +52610,7 @@ function resolveFaceSettings(raw) {
|
|
|
52548
52610
|
return parsed.success ? parsed.data : FACE_DEFAULTS[key];
|
|
52549
52611
|
};
|
|
52550
52612
|
return {
|
|
52551
|
-
|
|
52613
|
+
faceRecognitionEnabled: pick("faceRecognitionEnabled"),
|
|
52552
52614
|
similarityThreshold: pick("similarityThreshold"),
|
|
52553
52615
|
margin: pick("margin"),
|
|
52554
52616
|
minFacePx: pick("minFacePx"),
|
|
@@ -56567,7 +56629,117 @@ async function migrateDeviceTemplateVariable(ports) {
|
|
|
56567
56629
|
};
|
|
56568
56630
|
}
|
|
56569
56631
|
//#endregion
|
|
56570
|
-
//#region src/migrations/
|
|
56632
|
+
//#region src/migrations/split-enabled-key.ts
|
|
56633
|
+
/**
|
|
56634
|
+
* The shared settings key `enabled` becomes two (D987, D986 §2).
|
|
56635
|
+
*
|
|
56636
|
+
* One key meant two things: "Face recognition on" and "Suppress parked objects". Toggling one
|
|
56637
|
+
* flipped the other. Each switch now has its own key. So today's behaviour does not change, the
|
|
56638
|
+
* value an install has stored under `enabled` is copied into BOTH new keys, and `enabled` is
|
|
56639
|
+
* deleted. That covers the cluster row (`addon-settings`) and every camera's own row
|
|
56640
|
+
* (`addon-device-settings`).
|
|
56641
|
+
*
|
|
56642
|
+
* A new key that already has a row is never overwritten (a seed never overwrites): it was written
|
|
56643
|
+
* by the build that reads it. The plan has nothing left to do once `enabled` is gone, so a rerun is
|
|
56644
|
+
* a no-op. A read that fails throws and nothing is written.
|
|
56645
|
+
*/
|
|
56646
|
+
var PIPELINE_ANALYTICS_ID = "pipeline-analytics";
|
|
56647
|
+
var RETIRED_ENABLED_KEY = "enabled";
|
|
56648
|
+
var NEW_KEYS = ["faceRecognitionEnabled", "stationarySuppressionEnabled"];
|
|
56649
|
+
/** The canonical settings table: one row per key, id `<addonId>.<key>`. */
|
|
56650
|
+
var SETTINGS_TABLE = "addon-settings";
|
|
56651
|
+
/** The per-device settings table: one row per field, id `<addonId>:<deviceId>.<field>`. */
|
|
56652
|
+
var DEVICE_SETTINGS_TABLE = "addon-device-settings";
|
|
56653
|
+
function clusterEdits(stored) {
|
|
56654
|
+
if (!(RETIRED_ENABLED_KEY in stored)) return [];
|
|
56655
|
+
const value = stored[RETIRED_ENABLED_KEY];
|
|
56656
|
+
const rowId = (key) => `${PIPELINE_ANALYTICS_ID}.${key}`;
|
|
56657
|
+
const missing = NEW_KEYS.filter((key) => !(key in stored));
|
|
56658
|
+
const edits = [];
|
|
56659
|
+
if (missing.length > 0) edits.push({
|
|
56660
|
+
op: "setKeys",
|
|
56661
|
+
scope: SETTINGS_TABLE,
|
|
56662
|
+
values: Object.fromEntries(missing.map((key) => [rowId(key), {
|
|
56663
|
+
addonId: PIPELINE_ANALYTICS_ID,
|
|
56664
|
+
key,
|
|
56665
|
+
value
|
|
56666
|
+
}])),
|
|
56667
|
+
precondition: preconditionOf(Object.fromEntries(missing.map((key) => [rowId(key), null])))
|
|
56668
|
+
});
|
|
56669
|
+
edits.push({
|
|
56670
|
+
op: "deleteKeys",
|
|
56671
|
+
scope: SETTINGS_TABLE,
|
|
56672
|
+
keys: [rowId(RETIRED_ENABLED_KEY)],
|
|
56673
|
+
precondition: preconditionOf({ [rowId(RETIRED_ENABLED_KEY)]: {
|
|
56674
|
+
addonId: PIPELINE_ANALYTICS_ID,
|
|
56675
|
+
key: RETIRED_ENABLED_KEY,
|
|
56676
|
+
value
|
|
56677
|
+
} })
|
|
56678
|
+
});
|
|
56679
|
+
return edits;
|
|
56680
|
+
}
|
|
56681
|
+
async function deviceEdits(ports) {
|
|
56682
|
+
const ids = await ports.listDeviceIds();
|
|
56683
|
+
if (ids.length === 0) return [];
|
|
56684
|
+
const retired = await ports.readDeviceField(ids, RETIRED_ENABLED_KEY);
|
|
56685
|
+
if (retired.size === 0) return [];
|
|
56686
|
+
const carriers = [...retired.keys()];
|
|
56687
|
+
const existing = /* @__PURE__ */ new Map();
|
|
56688
|
+
for (const key of NEW_KEYS) existing.set(key, await ports.readDeviceField(carriers, key));
|
|
56689
|
+
const rowId = (deviceId, field) => `${PIPELINE_ANALYTICS_ID}:${deviceId}.${field}`;
|
|
56690
|
+
const created = {};
|
|
56691
|
+
const retiredRows = {};
|
|
56692
|
+
for (const [deviceId, value] of retired) {
|
|
56693
|
+
for (const key of NEW_KEYS) {
|
|
56694
|
+
if (existing.get(key)?.has(deviceId) === true) continue;
|
|
56695
|
+
created[rowId(deviceId, key)] = {
|
|
56696
|
+
addonId: PIPELINE_ANALYTICS_ID,
|
|
56697
|
+
deviceId: String(deviceId),
|
|
56698
|
+
key,
|
|
56699
|
+
value
|
|
56700
|
+
};
|
|
56701
|
+
}
|
|
56702
|
+
retiredRows[rowId(deviceId, RETIRED_ENABLED_KEY)] = {
|
|
56703
|
+
addonId: PIPELINE_ANALYTICS_ID,
|
|
56704
|
+
deviceId: String(deviceId),
|
|
56705
|
+
key: RETIRED_ENABLED_KEY,
|
|
56706
|
+
value
|
|
56707
|
+
};
|
|
56708
|
+
}
|
|
56709
|
+
const edits = [];
|
|
56710
|
+
const createdIds = Object.keys(created);
|
|
56711
|
+
if (createdIds.length > 0) edits.push({
|
|
56712
|
+
op: "setKeys",
|
|
56713
|
+
scope: DEVICE_SETTINGS_TABLE,
|
|
56714
|
+
values: created,
|
|
56715
|
+
precondition: preconditionOf(Object.fromEntries(createdIds.map((id) => [id, null])))
|
|
56716
|
+
});
|
|
56717
|
+
edits.push({
|
|
56718
|
+
op: "deleteKeys",
|
|
56719
|
+
scope: DEVICE_SETTINGS_TABLE,
|
|
56720
|
+
keys: Object.keys(retiredRows),
|
|
56721
|
+
precondition: preconditionOf(retiredRows)
|
|
56722
|
+
});
|
|
56723
|
+
return edits;
|
|
56724
|
+
}
|
|
56725
|
+
/** Copy `enabled` into both new keys (cluster row and every camera's row) and delete it. */
|
|
56726
|
+
async function planSplitEnabledKey(ports) {
|
|
56727
|
+
return { edits: [...clusterEdits(await ports.readStored([RETIRED_ENABLED_KEY, ...NEW_KEYS])), ...await deviceEdits(ports)] };
|
|
56728
|
+
}
|
|
56729
|
+
/**
|
|
56730
|
+
* The port's read over an addon's three-way key read: each of `keys` that has a row, raw. A key
|
|
56731
|
+
* the store could not answer for throws, so the migration fails instead of treating a failed read
|
|
56732
|
+
* as "nothing to move".
|
|
56733
|
+
*/
|
|
56734
|
+
async function readRawKeys(read, keys) {
|
|
56735
|
+
const found = {};
|
|
56736
|
+
for (const key of keys) {
|
|
56737
|
+
const answer = await read(key);
|
|
56738
|
+
if (answer.kind === "unreadable") throw new Error(`${PIPELINE_ANALYTICS_ID}: the setting ${key} cannot be read (${answer.reason})`);
|
|
56739
|
+
if (answer.kind === "present") found[key] = answer.value;
|
|
56740
|
+
}
|
|
56741
|
+
return found;
|
|
56742
|
+
}
|
|
56571
56743
|
/** The `pipeline-analytics` catalogue (D987): offered to the engine at the hub's boot. */
|
|
56572
56744
|
var ADDON_MIGRATIONS = [{
|
|
56573
56745
|
meta: {
|
|
@@ -56584,6 +56756,21 @@ var ADDON_MIGRATIONS = [{
|
|
|
56584
56756
|
fixtureMark: "the rule name and the trigger conditions the migration does not know"
|
|
56585
56757
|
},
|
|
56586
56758
|
procedure: migrateDeviceTemplateVariable
|
|
56759
|
+
}, {
|
|
56760
|
+
meta: {
|
|
56761
|
+
id: "pipeline-analytics/2026-11-05-split-enabled-key",
|
|
56762
|
+
owner: PIPELINE_ANALYTICS_ID,
|
|
56763
|
+
level: "addon-state",
|
|
56764
|
+
seq: 2,
|
|
56765
|
+
dependsOn: [],
|
|
56766
|
+
store: "settings",
|
|
56767
|
+
scope: "cluster",
|
|
56768
|
+
onFailure: "block-owner",
|
|
56769
|
+
bodyKind: "plan",
|
|
56770
|
+
description: "Split the shared `enabled` setting into faceRecognitionEnabled and stationarySuppressionEnabled, copying the stored value into both, for the cluster and for every camera",
|
|
56771
|
+
fixtureMark: "a setting the migration does not know"
|
|
56772
|
+
},
|
|
56773
|
+
plan: planSplitEnabledKey
|
|
56587
56774
|
}];
|
|
56588
56775
|
//#endregion
|
|
56589
56776
|
//#region src/pipeline-analytics/clip-space-plan.ts
|
|
@@ -71450,7 +71637,6 @@ Object.freeze({
|
|
|
71450
71637
|
"addon-routes": ["getRoutes"],
|
|
71451
71638
|
"addon-widgets-source": ["listWidgets"],
|
|
71452
71639
|
"board-key-source": ["listSources"],
|
|
71453
|
-
"broker": ["list", "listProviders"],
|
|
71454
71640
|
"calendar-source": ["listCalendars", "listEvents"],
|
|
71455
71641
|
"custom-model-registry": ["listModels"],
|
|
71456
71642
|
"data-store-provider": ["histogram", "query"],
|
|
@@ -71997,7 +72183,7 @@ var SensorTransitionGate = class {
|
|
|
71997
72183
|
var StationarySettingsSchema = object({
|
|
71998
72184
|
/** Master switch. Off ⇒ this camera gathers no evidence and suppresses
|
|
71999
72185
|
* nothing (every parked object keeps spawning normal tracks). */
|
|
72000
|
-
|
|
72186
|
+
stationarySuppressionEnabled: boolean().default(true),
|
|
72001
72187
|
/** IoU at/above which a detection is the same parked object, unmoved →
|
|
72002
72188
|
* suppress its spawn. `SUPPRESS_IOU`. */
|
|
72003
72189
|
suppressIou: number().min(.3).max(.9).default(SUPPRESS_IOU),
|
|
@@ -72024,7 +72210,7 @@ function resolveStationarySettings(raw) {
|
|
|
72024
72210
|
return parsed.success ? parsed.data : STATIONARY_DEFAULTS[key];
|
|
72025
72211
|
};
|
|
72026
72212
|
return {
|
|
72027
|
-
|
|
72213
|
+
stationarySuppressionEnabled: pick("stationarySuppressionEnabled"),
|
|
72028
72214
|
suppressIou: pick("suppressIou"),
|
|
72029
72215
|
wakeAssocIou: pick("wakeAssocIou"),
|
|
72030
72216
|
sessionStillnessWindowMs: pick("sessionStillnessWindowMs"),
|
|
@@ -72435,10 +72621,10 @@ function buildDetectionSettingsSections() {
|
|
|
72435
72621
|
fields: [
|
|
72436
72622
|
{
|
|
72437
72623
|
type: "boolean",
|
|
72438
|
-
key: "
|
|
72624
|
+
key: "stationarySuppressionEnabled",
|
|
72439
72625
|
label: "Suppress parked objects",
|
|
72440
72626
|
description: "Promote a stopped object to a lightweight registry entry and suppress its detections from re-spawning tracks. Off = every parked object keeps spawning normal tracks on this camera.",
|
|
72441
|
-
default: STATIONARY_DEFAULTS.
|
|
72627
|
+
default: STATIONARY_DEFAULTS.stationarySuppressionEnabled
|
|
72442
72628
|
},
|
|
72443
72629
|
{
|
|
72444
72630
|
type: "slider",
|
|
@@ -72648,8 +72834,6 @@ function retagRetentionSection(sections) {
|
|
|
72648
72834
|
* model-substitution readout.
|
|
72649
72835
|
*/
|
|
72650
72836
|
var SUGGESTION_THRESHOLD_READOUT_KEY = "suggestionThresholdReadout";
|
|
72651
|
-
/** `getGlobalSettings({ cap })` scope for the face matching form. */
|
|
72652
|
-
var FACE_GALLERY_SETTINGS_CAP = "face-gallery";
|
|
72653
72837
|
var FACE_RECOGNITION_SECTION_ID = "face-recognition";
|
|
72654
72838
|
/** Percent, at most one decimal, without a trailing `.0`. Cosines here are
|
|
72655
72839
|
* two-decimal operator values; `36.0%` reads like false precision. */
|
|
@@ -72671,7 +72855,7 @@ function formatSuggestionThresholdReadout(similarityThreshold) {
|
|
|
72671
72855
|
* by each device's detection-pipeline steps, so a per-device toggle would be
|
|
72672
72856
|
* misleading. Keyed by section id → set of field keys to drop.
|
|
72673
72857
|
*/
|
|
72674
|
-
var GLOBAL_ONLY_FIELDS = { "face-recognition": new Set(["
|
|
72858
|
+
var GLOBAL_ONLY_FIELDS = { "face-recognition": new Set(["faceRecognitionEnabled", SUGGESTION_THRESHOLD_READOUT_KEY]) };
|
|
72675
72859
|
/**
|
|
72676
72860
|
* Whole sections that are cluster-wide (global page only) and must NOT appear
|
|
72677
72861
|
* in a per-device contribution (D62: a per-camera field whose reader only ever
|
|
@@ -72730,8 +72914,8 @@ function stripDeviceOnlyFields(sections) {
|
|
|
72730
72914
|
* in `BaseAddon.schema()`; the general sections below are followed by the
|
|
72731
72915
|
* detection-knob sections in the original order.
|
|
72732
72916
|
*/
|
|
72733
|
-
function buildGlobalSettingsSchema(
|
|
72734
|
-
return
|
|
72917
|
+
function buildGlobalSettingsSchema() {
|
|
72918
|
+
return { sections: [...[
|
|
72735
72919
|
{
|
|
72736
72920
|
id: "cluster-post-processing",
|
|
72737
72921
|
title: "Cluster post-processing",
|
|
@@ -73310,10 +73494,10 @@ function buildGlobalSettingsSchema(cap) {
|
|
|
73310
73494
|
fields: [
|
|
73311
73495
|
{
|
|
73312
73496
|
type: "boolean",
|
|
73313
|
-
key: "
|
|
73497
|
+
key: "faceRecognitionEnabled",
|
|
73314
73498
|
label: "Face recognition on",
|
|
73315
73499
|
description: "Off stops face matching for every camera. On by default.",
|
|
73316
|
-
default: FACE_DEFAULTS.
|
|
73500
|
+
default: FACE_DEFAULTS.faceRecognitionEnabled
|
|
73317
73501
|
},
|
|
73318
73502
|
{
|
|
73319
73503
|
type: "number",
|
|
@@ -73408,25 +73592,22 @@ function buildGlobalSettingsSchema(cap) {
|
|
|
73408
73592
|
}
|
|
73409
73593
|
]
|
|
73410
73594
|
}
|
|
73411
|
-
], ...buildDetectionSettingsSections()] }
|
|
73595
|
+
], ...buildDetectionSettingsSections()] };
|
|
73596
|
+
}
|
|
73597
|
+
/** The face matching form: the cluster form of `face-gallery`. */
|
|
73598
|
+
function buildFaceClusterSchema() {
|
|
73599
|
+
return { sections: buildGlobalSettingsSchema().sections.filter((section) => section.id === FACE_RECOGNITION_SECTION_ID) };
|
|
73600
|
+
}
|
|
73601
|
+
/** The cluster-wide knobs of `pipeline-analytics`: the sections a camera never overrides. */
|
|
73602
|
+
function buildAnalyticsClusterSchema() {
|
|
73603
|
+
return { sections: buildGlobalSettingsSchema().sections.filter((section) => GLOBAL_ONLY_SECTIONS.has(section.id)) };
|
|
73412
73604
|
}
|
|
73413
73605
|
/**
|
|
73414
|
-
* The
|
|
73415
|
-
*
|
|
73416
|
-
* → Settings asks for `face-gallery`; System → Settings omits `cap` and
|
|
73417
|
-
* still gets every section. An unknown cap is empty so this addon cannot
|
|
73418
|
-
* appear on a page that meant someone else.
|
|
73606
|
+
* The fleet defaults of `pipeline-analytics`: every knob a camera can override on its own form,
|
|
73607
|
+
* the face section excluded (it is the cluster form of `face-gallery`).
|
|
73419
73608
|
*/
|
|
73420
|
-
function
|
|
73421
|
-
|
|
73422
|
-
if (cap === FACE_GALLERY_SETTINGS_CAP) return {
|
|
73423
|
-
...schema,
|
|
73424
|
-
sections: schema.sections.filter((s) => s.id === FACE_RECOGNITION_SECTION_ID)
|
|
73425
|
-
};
|
|
73426
|
-
return {
|
|
73427
|
-
...schema,
|
|
73428
|
-
sections: []
|
|
73429
|
-
};
|
|
73609
|
+
function buildAnalyticsDeviceDefaultsSchema() {
|
|
73610
|
+
return { sections: buildGlobalSettingsSchema().sections.filter((section) => section.id !== FACE_RECOGNITION_SECTION_ID && !GLOBAL_ONLY_SECTIONS.has(section.id)) };
|
|
73430
73611
|
}
|
|
73431
73612
|
//#endregion
|
|
73432
73613
|
//#region src/pipeline-analytics/store/embedding-json-conversion.ts
|
|
@@ -123991,7 +124172,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
123991
124172
|
}
|
|
123992
124173
|
_faceGlobalEnabledState = null;
|
|
123993
124174
|
get faceGlobalEnabledState() {
|
|
123994
|
-
if (!this._faceGlobalEnabledState) this._faceGlobalEnabledState = this.state("
|
|
124175
|
+
if (!this._faceGlobalEnabledState) this._faceGlobalEnabledState = this.state("faceRecognitionEnabled", FaceSettingsSchema.shape.faceRecognitionEnabled, FACE_DEFAULTS.faceRecognitionEnabled);
|
|
123995
124176
|
return this._faceGlobalEnabledState;
|
|
123996
124177
|
}
|
|
123997
124178
|
constructor() {
|
|
@@ -124368,10 +124549,19 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
124368
124549
|
/** The addon's migration catalogue (D987), bound to the notification kinds. */
|
|
124369
124550
|
async runTemplateMigrations() {
|
|
124370
124551
|
const records = this.requireRecords();
|
|
124552
|
+
const settings = this.ctx.settings;
|
|
124553
|
+
if (settings === void 0) throw new Error("the per-device settings store is unavailable");
|
|
124371
124554
|
const ports = {
|
|
124372
124555
|
rules: records.kind(ncRecordKinds["rules"]),
|
|
124373
124556
|
timelapseRules: records.kind(ncRecordKinds["timelapse-rules"]),
|
|
124374
|
-
texts: records.kind(ncRecordKinds.texts)
|
|
124557
|
+
texts: records.kind(ncRecordKinds.texts),
|
|
124558
|
+
readStored: (keys) => readRawKeys((key) => this.readStoredGlobalKey(key), keys),
|
|
124559
|
+
listDeviceIds: () => settings.listDeviceStoreIds(),
|
|
124560
|
+
readDeviceField: async (deviceIds, field) => {
|
|
124561
|
+
const found = /* @__PURE__ */ new Map();
|
|
124562
|
+
for (const [deviceId, blob] of await settings.readDeviceStoreBatch(deviceIds)) if (field in blob) found.set(deviceId, blob[field]);
|
|
124563
|
+
return found;
|
|
124564
|
+
}
|
|
124375
124565
|
};
|
|
124376
124566
|
await this.runMigrations(defineAddonMigrations(ADDON_MIGRATIONS, ports));
|
|
124377
124567
|
}
|
|
@@ -126938,7 +127128,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
126938
127128
|
const stationarySettings = this.stationarySettingsFromCache(deviceId);
|
|
126939
127129
|
const packageSettings = this.packageDropSettingsFromCache(deviceId);
|
|
126940
127130
|
const packageClasses = new Set(packageSettings.packageDropClassFilter);
|
|
126941
|
-
if (planeRunsStationary(source) && this.stationaryRegistry && this.stationaryEvidence && stationarySettings.
|
|
127131
|
+
if (planeRunsStationary(source) && this.stationaryRegistry && this.stationaryEvidence && stationarySettings.stationarySuppressionEnabled) {
|
|
126942
127132
|
const evidence = this.stationaryEvidence;
|
|
126943
127133
|
for (const t of result.tracked) {
|
|
126944
127134
|
if (packageClasses.has(t.className)) continue;
|
|
@@ -129282,7 +129472,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
129282
129472
|
const registry = this.stationaryRegistry;
|
|
129283
129473
|
p.setStationaryGate({ filter: (input) => {
|
|
129284
129474
|
const s = this.stationarySettingsFromCache(deviceId);
|
|
129285
|
-
if (!s.
|
|
129475
|
+
if (!s.stationarySuppressionEnabled) return {
|
|
129286
129476
|
suppressedIndices: /* @__PURE__ */ new Set(),
|
|
129287
129477
|
continuableIndices: /* @__PURE__ */ new Set(),
|
|
129288
129478
|
confirmed: [],
|
|
@@ -132639,6 +132829,10 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
132639
132829
|
} });
|
|
132640
132830
|
return { jobId };
|
|
132641
132831
|
}
|
|
132832
|
+
/** Stored media per storage location (see the cap): indexed aggregates, no walk. */
|
|
132833
|
+
async getMediaLocationCensus(input) {
|
|
132834
|
+
return this.requireMediaStore().censusByLocation(input.locationIds);
|
|
132835
|
+
}
|
|
132642
132836
|
/**
|
|
132643
132837
|
* How many media / retrain rows still carry no `locationId`.
|
|
132644
132838
|
*
|
|
@@ -132842,8 +133036,25 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
132842
133036
|
});
|
|
132843
133037
|
return await readWinningBlob(candidates, pick, readBlob);
|
|
132844
133038
|
}
|
|
132845
|
-
|
|
132846
|
-
return
|
|
133039
|
+
scopedSettingsCapabilities() {
|
|
133040
|
+
return ["pipeline-analytics", "face-gallery"];
|
|
133041
|
+
}
|
|
133042
|
+
/**
|
|
133043
|
+
* D986 M4. The face matching form is the cluster form of `face-gallery`; the cluster-wide knobs
|
|
133044
|
+
* (post-processing node, index maintenance, device alerts, prune windows) are the cluster form
|
|
133045
|
+
* of `pipeline-analytics`. A page asks for ONE capability's form, and System → Settings asks for
|
|
133046
|
+
* all of them. The schemas are static; the only live value (the derived suggestion floor) is
|
|
133047
|
+
* injected into the hydrate blob by `getGlobalSettings`.
|
|
133048
|
+
*/
|
|
133049
|
+
async clusterSettingsSchema(cap) {
|
|
133050
|
+
if (cap === "face-gallery") return this.schema(buildFaceClusterSchema());
|
|
133051
|
+
if (cap === "pipeline-analytics") return this.schema(buildAnalyticsClusterSchema());
|
|
133052
|
+
return null;
|
|
133053
|
+
}
|
|
133054
|
+
/** The knobs a camera can override: stored as the fleet default, resolved per camera. */
|
|
133055
|
+
async deviceDefaultsSchema(cap) {
|
|
133056
|
+
if (cap === "pipeline-analytics") return this.schema(buildAnalyticsDeviceDefaultsSchema());
|
|
133057
|
+
return null;
|
|
132847
133058
|
}
|
|
132848
133059
|
/**
|
|
132849
133060
|
* The only reason this is overridden: the face suggestion floor is DERIVED
|
|
@@ -132857,11 +133068,11 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
132857
133068
|
* implies and has nothing to contradict it with. Everything else about this
|
|
132858
133069
|
* call is `BaseAddon`'s.
|
|
132859
133070
|
*
|
|
132860
|
-
* (Fix round, L3.) `
|
|
133071
|
+
* (Fix round, L3.) `buildGlobalSettingsSchema()` is reused, untouched, by
|
|
132861
133072
|
* `getDeviceSettingsContribution` below to build the PER-DEVICE form —
|
|
132862
133073
|
* `trackingTape` must stay there. So the strip happens here, on the result
|
|
132863
133074
|
* THIS method actually hands to the global settings page, never inside
|
|
132864
|
-
* `
|
|
133075
|
+
* `buildGlobalSettingsSchema()` itself, which would also remove it from the
|
|
132865
133076
|
* per-device form that shares the same base sections.
|
|
132866
133077
|
*/
|
|
132867
133078
|
async getGlobalSettings(overlay, cap, nodeId) {
|
|
@@ -132883,7 +133094,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
132883
133094
|
}
|
|
132884
133095
|
async getDeviceSettingsContribution(input) {
|
|
132885
133096
|
if (!await this.isCameraDevice(input.deviceId)) return null;
|
|
132886
|
-
const schema =
|
|
133097
|
+
const schema = buildGlobalSettingsSchema();
|
|
132887
133098
|
const raw = await this.readDeviceBlob(input.deviceId);
|
|
132888
133099
|
const globalRaw = await this.rawGlobalStoreMirror.resolve();
|
|
132889
133100
|
const baseSections = schema ? hydrateWithInheritedGlobals({
|
|
@@ -30,7 +30,7 @@ async function d(e) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
async function f() {
|
|
33
|
-
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-
|
|
33
|
+
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-CRWJsnQv.mjs")).catch((e) => {
|
|
34
34
|
throw l = void 0, e;
|
|
35
35
|
}), l;
|
|
36
36
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-post-analysis",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.671",
|
|
4
4
|
"description": "Post-Analysis bundle — enrichment, embedding-encoder, pipeline-analytics. Multi-entry npm package shipping addons that consume pipeline output.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
}
|
|
139
139
|
],
|
|
140
140
|
"requires": {
|
|
141
|
-
"server": ">=1.2.
|
|
141
|
+
"server": ">=1.2.780"
|
|
142
142
|
}
|
|
143
143
|
},
|
|
144
144
|
"scripts": {
|