@camstack/addon-post-analysis 1.2.305 → 1.2.306

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { $ as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, $n as sceneMonitorCapability, $t as TimelapseRuleInputSchema, A as EMBEDDING_REQUIREMENTS_FAILED, An as isDetectionMacroClass, Ar as array, At as NcTemplateVarDescriptorSchema, B as ListTrackRelationsInputSchema, Bn as memoizePinnedFfmpeg, Br as string, Bt as SCENE_DEFAULT_ANCHOR_THRESHOLD, C as DEFAULT_EVENT_COLOR, Cn as encodeVectorBase64, Cr as hydrateSchema, Ct as NcSnoozeInputSchema, D as DeclaredDevices, Dn as gifDeriveSpeed, Dr as sleep$1, Dt as NcTaxonomySchema, E as DETECTION_PIPELINE_CAP_NAME, En as failureContributionCapability, Et as NcSystemEventKindSchema, F as EXPORT_DENSE_MAX_RANGES, Fn as isSystemDelivery, Fr as number, Ft as RECORDING_SOURCE_CAMSTACK_ADDON, G as MAX_BIRTH_LATENCY_PROXY_MS, Gn as plateGalleryCapability, Gt as SCENE_DIVERGED, H as LockStateSchema, Hn as occupancyScope, Hr as union, Ht as SCENE_DEFAULT_OBSERVATION_SPACING_SEC, I as FIRST_LEVEL_MACRO_CLASSES, In as isSystemEventSummaryRule, Ir as object, It as RebuildObjectEmbeddingsRefusalSchema, J as MOTION_CLOSE_AFTER_MS, Jn as readTimelapseGeneratedAt, Jt as SetTrackPurityInputSchema, K as MAX_TRACK_PURITIES, Kn as readDeviceStateFrom, Kt as SCENE_RESET_RECAPTURES, L as FULL_IMAGE_BBOX, Ln as isVectorIndexDimConflict, Lr as partialRecord, Lt as RetrainStatusSchema, M as EVENT_DENSITY_BATCH_MAX, Mn as isKnownTemplateVar, Mr as discriminatedUnion, Mt as OpsLogEntrySchema, N as EVENT_KIND_BY_CAP, Nn as isMediaOwnerType, Nr as literal, O as DetectionSourceSchema, On as gifFromMp4Args, Or as ZodObject, Ot as NcTemplatePreviewInputSchema, P as EVENT_OWNER_TYPES, Pn as isScheduleActive, Pr as looseObject, Pt as RECORDING_EXPORT_MAX_READ_BYTES, Q as NC_AUDIO_CONFIRM_HITS_DEFAULT, Qn as ruleBelongsToAlarm$1, Qt as TRACK_RELATIONS_DEFAULT_LIMIT, R as FailureCounters, Rn as kebabToCamel, Rr as record, Rt as SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX, S as CoverStateSchema, Sr as defineCustomActions, St as NcScheduleSchema, T as DETECTION_MACRO_CLASSES, Tn as faceGalleryCapability, Tr as nodePin, Tt as NcSnoozeSuppressedSchema, U as MAX_ARCHIVED_DEBUG_NOTES, Ur as unknown, Ut as SCENE_DEFAULT_QUIET_SECONDS, V as ListTrackRelationsResultSchema, Vn as notificationRulesCapability, Vr as tuple, Vt as SCENE_DEFAULT_CHECK_INTERVAL_SEC, W as MAX_BIRTH_DECISION_RECORDS, Wn as pipelineAnalyticsCapability, Wr as EventCategory, Wt as SCENE_DEFAULT_UNCOVERED_POLICY, X as MotionTriggeredBySchema, Xn as resolveLocationMode, Xt as SetTrackRelationInputSchema, Y as MediaFileKindEnum, Yn as resolveClipSearchMinScore, Yt as SetTrackPurityResultSchema, Z as NC_ALARM_SYSTEM_EVENT_KINDS, Zt as TIMELAPSE_DENSE_FLOOR_SEC, _ as BaseDevice, _n as describeSystemEventFamilyProblem, _r as errMsg, _t as NcRuleInputSchema, a as CLIP_EMBEDDING_STEP_ID, an as TrackSideSchema, ar as systemEventFamilyProblems, at as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, b as ClearTrackRelationInputSchema, bn as embeddingRefusalOf, br as createEvent, bt as NcRuleTargetSchema, c as resolveClusterModelPin, cn as alarmPanelCapability, cr as templateCarriesSummary, ct as NC_SNOOZE_MAX_MINUTES, d as APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT, dn as audioModeOf, dr as zoneAnalyticsCapability, dt as NC_TAXONOMY, en as TimelapseRulePatchSchema, er as sensorRaisedOf, et as NC_CLIP_POST_ROLL_DEFAULT_SEC, f as ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT, fn as buildEventKindDescriptor, fr as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, ft as NC_TEMPLATE_VARS, g as BIRTH_DECISION_DEFAULT_LIMIT, gn as describeSystemEventDeliveryProblem, gr as DeviceType, gt as NcConditionsSchema, h as ArchivedDebugNoteSchema, hn as deriveRecordingMode, hr as isSourceCap, ht as NcConditionDescriptorSchema, in as TrackRelationSchema, ir as systemEventDeliveryProblems, it as NC_CONSUMABLE_LOW_PERCENT_DEFAULT, j as EMBEDDING_REQUIREMENTS_UNAVAILABLE, jn as isEventOwnerType, jr as boolean, jt as OPS_LOG_DEFAULT_LIMIT, k as EMBEDDING_MODEL_FAILED, kn as isAudioClassName, kr as _enum, kt as NcTemplatePreviewSchema, l as APPEARANCE_BIN_COUNT, ln as assertTimelapseCadences, lr as templateVarsFor, lt as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, m as AlarmArmModeSchema, mn as cosineSimilarity$1, mr as evaluateSensorEdge, mt as NcAlarmSettingsPatchSchema, nn as TrackPuritySchema, nr as storageOccupancyCapability, nt as NC_CLIP_RETENTION_MAX_SEC, o as FACE_EMBEDDING_STEP_ID, on as TrackSourceSchema, or as systemEventFilterApplies, ot as NC_DEFAULT_SNOOZE_MINUTES, p as AUDIO_MACRO_LABELS, pn as consumableLowPercentOf, pr as canonicalHash, pt as NcAlarmConfigSchema, q as MAX_TRACK_RELATIONS, qn as readMotionTriggeredBy, qt as SceneMonitorSchema, rn as TrackRelationKindSchema, rr as subKindsOf, rt as NC_CONDITION_CATALOG, s as readClusterModelPinStrict, sn as addonWidgetsSourceCapability, sr as systemEventSummaryScheduleOf, st as NC_SENSOR_TRANSITION_KINDS, t as BUILTIN_CLIP_MODELS, tn as TimelapseRuleSchema, tr as servedTemplateVars, tt as NC_CLIP_PRE_ROLL_DEFAULT_SEC, u as APPEARANCE_BLOCKS, un as audioMetricsCapability, ur as vectorDimFromBase64, ut as NC_TANK_SYSTEM_EVENT_KINDS, v as BirthDecisionRecordSchema, vr as BaseAddon, vt as NcRulePatchSchema, w as DEFAULT_TIMELAPSE_PREVIEW_TEXT, wn as evictionPolicyOfLocation, wr as isDeviceScopedCap, wt as NcSnoozeSchema, x as ClearTrackRelationResultSchema, xr as customAction, xt as NcRuleUpdateInputSchema, y as COCO_TO_MACRO, yr as CamProfileSchema, yt as NcRuleSchema, z as LabelAttributionSchema, zn as mayWriteToLocation, zr as strictObject, zt as SCENE_CONFIRM_DEFAULT_TIMEOUT_MS } from "../clip-model-registry-EA6x7Vd5.mjs";
1
+ import { $ as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, $n as ruleDeviceCompatCapQueries, $t as TimelapseRuleInputSchema, A as EMBEDDING_REQUIREMENTS_FAILED, An as isDetectionMacroClass, Ar as ZodObject, At as NcTemplateVarDescriptorSchema, B as ListTrackRelationsInputSchema, Bn as memoizePinnedFfmpeg, Br as record, Bt as SCENE_DEFAULT_ANCHOR_THRESHOLD, C as DEFAULT_EVENT_COLOR, Cn as encodeVectorBase64, Cr as customAction, Ct as NcSnoozeInputSchema, D as DeclaredDevices, Dn as gifDeriveSpeed, Dr as nodePin, Dt as NcTaxonomySchema, E as DETECTION_PIPELINE_CAP_NAME, En as failureContributionCapability, Er as isDeviceScopedCap, Et as NcSystemEventKindSchema, F as EXPORT_DENSE_MAX_RANGES, Fn as isSystemDelivery, Fr as literal, Ft as RECORDING_SOURCE_CAMSTACK_ADDON, G as MAX_BIRTH_LATENCY_PROXY_MS, Gn as plateGalleryCapability, Gr as unknown, Gt as SCENE_DIVERGED, H as LockStateSchema, Hn as occupancyScope, Hr as string, Ht as SCENE_DEFAULT_OBSERVATION_SPACING_SEC, I as FIRST_LEVEL_MACRO_CLASSES, In as isSystemEventSummaryRule, Ir as looseObject, It as RebuildObjectEmbeddingsRefusalSchema, J as MOTION_CLOSE_AFTER_MS, Jn as readTimelapseGeneratedAt, Jt as SetTrackPurityInputSchema, K as MAX_TRACK_PURITIES, Kn as readDeviceStateFrom, Kr as EventCategory, Kt as SCENE_RESET_RECAPTURES, L as FULL_IMAGE_BBOX, Ln as isVectorIndexDimConflict, Lr as number, Lt as RetrainStatusSchema, M as EVENT_DENSITY_BATCH_MAX, Mn as isKnownTemplateVar, Mr as array, Mt as OpsLogEntrySchema, N as EVENT_KIND_BY_CAP, Nn as isMediaOwnerType, Nr as boolean, O as DetectionSourceSchema, On as gifFromMp4Args, Ot as NcTemplatePreviewInputSchema, P as EVENT_OWNER_TYPES, Pn as isScheduleActive, Pr as discriminatedUnion, Pt as RECORDING_EXPORT_MAX_READ_BYTES, Q as NC_AUDIO_CONFIRM_HITS_DEFAULT, Qn as ruleBelongsToAlarm$1, Qt as TRACK_RELATIONS_DEFAULT_LIMIT, R as FailureCounters, Rn as kebabToCamel, Rr as object, Rt as SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX, S as CoverStateSchema, Sr as createEvent, St as NcScheduleSchema, T as DETECTION_MACRO_CLASSES, Tn as faceGalleryCapability, Tr as hydrateSchema, Tt as NcSnoozeSuppressedSchema, U as MAX_ARCHIVED_DEBUG_NOTES, Ur as tuple, Ut as SCENE_DEFAULT_QUIET_SECONDS, V as ListTrackRelationsResultSchema, Vn as notificationRulesCapability, Vr as strictObject, Vt as SCENE_DEFAULT_CHECK_INTERVAL_SEC, W as MAX_BIRTH_DECISION_RECORDS, Wn as pipelineAnalyticsCapability, Wr as union, Wt as SCENE_DEFAULT_UNCOVERED_POLICY, X as MotionTriggeredBySchema, Xn as resolveLocationMode, Xt as SetTrackRelationInputSchema, Y as MediaFileKindEnum, Yn as resolveClipSearchMinScore, Yt as SetTrackPurityResultSchema, Z as NC_ALARM_SYSTEM_EVENT_KINDS, Zt as TIMELAPSE_DENSE_FLOOR_SEC, _ as BaseDevice, _n as describeSystemEventFamilyProblem, _r as isSourceCap, _t as NcRuleInputSchema, a as CLIP_EMBEDDING_STEP_ID, an as TrackSideSchema, ar as subKindsOf, at as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, b as ClearTrackRelationInputSchema, bn as embeddingRefusalOf, br as BaseAddon, bt as NcRuleTargetSchema, c as resolveClusterModelPin, cn as alarmPanelCapability, cr as systemEventFilterApplies, ct as NC_SNOOZE_MAX_MINUTES, d as APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT, dn as audioModeOf, dr as templateVarsFor, dt as NC_TAXONOMY, en as TimelapseRulePatchSchema, er as ruleKindOf, et as NC_CLIP_POST_ROLL_DEFAULT_SEC, f as ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT, fn as buildEventKindDescriptor, fr as vectorDimFromBase64, ft as NC_TEMPLATE_VARS, g as BIRTH_DECISION_DEFAULT_LIMIT, gn as describeSystemEventDeliveryProblem, gr as evaluateSensorEdge, gt as NcConditionsSchema, h as ArchivedDebugNoteSchema, hn as deriveRecordingMode, hr as canonicalHash, ht as NcConditionDescriptorSchema, in as TrackRelationSchema, ir as storageOccupancyCapability, it as NC_CONSUMABLE_LOW_PERCENT_DEFAULT, j as EMBEDDING_REQUIREMENTS_UNAVAILABLE, jn as isEventOwnerType, jr as _enum, jt as OPS_LOG_DEFAULT_LIMIT, k as EMBEDDING_MODEL_FAILED, kn as isAudioClassName, kr as sleep$1, kt as NcTemplatePreviewSchema, l as APPEARANCE_BIN_COUNT, ln as assertTimelapseCadences, lr as systemEventSummaryScheduleOf, lt as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, m as AlarmArmModeSchema, mn as cosineSimilarity$1, mr as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, mt as NcAlarmSettingsPatchSchema, nn as TrackPuritySchema, nr as sensorRaisedOf, nt as NC_CLIP_RETENTION_MAX_SEC, o as FACE_EMBEDDING_STEP_ID, on as TrackSourceSchema, or as systemEventDeliveryProblems, ot as NC_DEFAULT_SNOOZE_MINUTES, p as AUDIO_MACRO_LABELS, pn as consumableLowPercentOf, pr as zoneAnalyticsCapability, pt as NcAlarmConfigSchema, q as MAX_TRACK_RELATIONS, qn as readMotionTriggeredBy, qt as SceneMonitorSchema, rn as TrackRelationKindSchema, rr as servedTemplateVars, rt as NC_CONDITION_CATALOG, s as readClusterModelPinStrict, sn as addonWidgetsSourceCapability, sr as systemEventFamilyProblems, st as NC_SENSOR_TRANSITION_KINDS, t as BUILTIN_CLIP_MODELS, tn as TimelapseRuleSchema, tr as sceneMonitorCapability, tt as NC_CLIP_PRE_ROLL_DEFAULT_SEC, u as APPEARANCE_BLOCKS, un as audioMetricsCapability, ur as templateCarriesSummary, ut as NC_TANK_SYSTEM_EVENT_KINDS, v as BirthDecisionRecordSchema, vr as DeviceType, vt as NcRulePatchSchema, w as DEFAULT_TIMELAPSE_PREVIEW_TEXT, wn as evictionPolicyOfLocation, wr as defineCustomActions, wt as NcSnoozeSchema, x as ClearTrackRelationResultSchema, xr as CamProfileSchema, xt as NcRuleUpdateInputSchema, y as COCO_TO_MACRO, yr as errMsg, yt as NcRuleSchema, z as LabelAttributionSchema, zn as mayWriteToLocation, zr as partialRecord, zt as SCENE_CONFIRM_DEFAULT_TIMEOUT_MS } from "../clip-model-registry-C9Aw4qkh.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";
@@ -10644,21 +10644,49 @@ function matchesPlate(label, values, maxDistance) {
10644
10644
  return false;
10645
10645
  }
10646
10646
  /**
10647
+ * Subject kinds whose `classNames` is a real, operator-meaningful detection
10648
+ * class — the ones the `classes` condition can actually scope a rule to.
10649
+ * `device-event` and `system-event` carry NO class live (`classNames: []`,
10650
+ * always — see `subjectFromSensorEvent`); their OUTBOX `className` is a
10651
+ * display placeholder instead (the sensor kind, or the literal `'event'`,
10652
+ * `className: subject.classNames[0] ?? subject.sensorKind ?? 'event'`), which
10653
+ * `cooldownSubjectFromOutbox` would otherwise reconstruct as if it were a real
10654
+ * class. Gating here, not on the reconstructed value, keeps the live path and
10655
+ * the boot reseed addressing the SAME key regardless of what a display label
10656
+ * happens to say (2026-10-01, caught by `system-event-cooldown-direction.spec.ts`
10657
+ * when the default below flipped).
10658
+ */
10659
+ var CLASS_BEARING_SUBJECT_KINDS = new Set([
10660
+ "object-event",
10661
+ "track-end",
10662
+ "package-event",
10663
+ "occupancy-event",
10664
+ "audio-event",
10665
+ "audio-window"
10666
+ ]);
10667
+ /**
10647
10668
  * Should this subject's class be part of the cooldown key?
10648
10669
  *
10649
10670
  * AUDIO is unconditional and predates the setting: a rule opted into several
10650
10671
  * audio classes (dog + scream) must not have a safety-relevant scream
10651
10672
  * swallowed by an unrelated bark's 60 s window.
10652
10673
  *
10653
- * Every other subject gets the same treatment only when the rule ASKS for it
10654
- * (`granularity: 'per-class'`) — cat→dog fires at once, cat→cat still waits.
10655
- * Absent / `shared` reproduces the class-agnostic key byte for byte, because
10656
- * changing how often an operator's existing rules fire is not a side effect
10657
- * anyone asked for.
10674
+ * A `device-event` or `system-event` subject never reads a class — see
10675
+ * {@link CLASS_BEARING_SUBJECT_KINDS} — so the setting has nothing to key on
10676
+ * regardless of `granularity`.
10677
+ *
10678
+ * Every class-bearing subject gets the same treatment unless the rule
10679
+ * explicitly asks for `shared` — cat→dog fires at once, cat→cat still waits.
10680
+ * That is the operator's default since 2026-10-01 (D36's dated note): an
10681
+ * UNSET rule now reads exactly like an explicit `per-class` one, new rules and
10682
+ * existing rules alike. Only a `granularity: 'shared'` actually stored
10683
+ * reproduces the old class-agnostic key byte for byte — the one case where an
10684
+ * operator asked for one window across every class on purpose.
10658
10685
  */
10659
10686
  function keysPerClass(rule, subject) {
10660
10687
  if (subject.kind === "audio-event" || subject.kind === "audio-window") return true;
10661
- return rule.throttle.granularity === "per-class";
10688
+ if (!CLASS_BEARING_SUBJECT_KINDS.has(subject.kind)) return false;
10689
+ return rule.throttle.granularity !== "shared";
10662
10690
  }
10663
10691
  /**
10664
10692
  * The cooldown scope of ONE system event — subject AND direction.
@@ -10743,6 +10771,42 @@ function isCoolingDown(rule, lastFiredAt, now) {
10743
10771
  return now - lastFiredAt < rule.throttle.cooldownSec * 1e3;
10744
10772
  }
10745
10773
  /**
10774
+ * The media policy EVERY sensor rule attaches: one whole-scene photograph,
10775
+ * never a selector. `attach: 'keyFrame'` is the existing "clean full scene
10776
+ * frame" ladder (`attachmentKindPreference`) — the closest existing concept
10777
+ * to a plain snapshot, as opposed to `'best'`/`'best-matching'`, which chase a
10778
+ * SUBJECT crop a sensor subject (a doorbell press, a contact change) has
10779
+ * none of to chase. No zone crop, no gif, no clip, no profile — a sensor
10780
+ * subject has no zone condition to crop to and no reason to animate.
10781
+ */
10782
+ var NC_SENSOR_MEDIA_POLICY = { attach: "keyFrame" };
10783
+ /**
10784
+ * The media policy actually used to build a delivery, for a rule of this
10785
+ * KIND. A sensor rule's STORED `media` is never read at evaluation — the
10786
+ * editor offers no media control for one any more, and `media.attach` /
10787
+ * `.gif` / `.clip` / `.profile` on an existing sensor rule (authored before
10788
+ * this ruling, from the viewer or the API) are IGNORED here, never refused at
10789
+ * load. See {@link mediaPolicyMatchesSensorDefault} for the sampled-log gate.
10790
+ */
10791
+ function effectiveMediaPolicy(rule, kind) {
10792
+ return kind === "sensor" ? NC_SENSOR_MEDIA_POLICY : rule.media;
10793
+ }
10794
+ /**
10795
+ * True when a stored media policy already reads as the sensor default — the
10796
+ * gate the boot/evaluation path uses to decide whether an existing sensor
10797
+ * rule's stored choice is being silently overridden (and so is worth a
10798
+ * sampled log line) or already matches and there is nothing to say.
10799
+ */
10800
+ function mediaPolicyMatchesSensorDefault(media) {
10801
+ return media.attach === NC_SENSOR_MEDIA_POLICY.attach && media.frame === void 0 && media.zoneCrop !== true && media.gif !== true && media.clip !== true && media.profile === void 0;
10802
+ }
10803
+ /** `effectiveMediaPolicy`, resolving the kind itself — the call-site shortcut
10804
+ * every production caller uses; `effectiveMediaPolicy` stays the unit under
10805
+ * test because `ruleKindOf` needs no fixture of its own there. */
10806
+ function effectiveMediaPolicyForRule(rule) {
10807
+ return effectiveMediaPolicy(rule, ruleKindOf(rule));
10808
+ }
10809
+ /**
10746
10810
  * Ordered media-kind preference for one attachment, per policy and owner.
10747
10811
  * `best` favours the tight subject crop; `keyFrame` the clean scene frame
10748
10812
  * (small variant first — the degrade engine enforces per-backend byte
@@ -14324,11 +14388,11 @@ function logRefusal$3(check, ctx) {
14324
14388
  try {
14325
14389
  check();
14326
14390
  } catch (err) {
14327
- if (err instanceof NcDevicesExcludeRefusal) warnRefusal$2(ctx.logger, err, ctx);
14391
+ if (err instanceof NcDevicesExcludeRefusal) warnRefusal$3(ctx.logger, err, ctx);
14328
14392
  throw err;
14329
14393
  }
14330
14394
  }
14331
- function warnRefusal$2(logger, err, ctx) {
14395
+ function warnRefusal$3(logger, err, ctx) {
14332
14396
  logger.warn("nc rule refused: devicesExclude on a system rule", { meta: {
14333
14397
  ...ctx.ruleId !== void 0 ? { ruleId: ctx.ruleId } : {},
14334
14398
  by: ctx.by,
@@ -14351,6 +14415,184 @@ function guardPatchDevicesExclude(existing, patch, ctx) {
14351
14415
  logRefusal$3(() => assertDevicesExcludeDelivery(merged), ctx);
14352
14416
  }
14353
14417
  //#endregion
14418
+ //#region src/notification-center/device-compat-guard.ts
14419
+ /**
14420
+ * A NEW or UPDATED rule's `conditions.devices` (the "Only these" INCLUDE list)
14421
+ * names only devices that can actually produce this rule's KIND of subject —
14422
+ * operator ruling, 2026-10-01: "the DEVICE picker of a rule must offer only
14423
+ * devices compatible with the rule type … the server should also refuse a
14424
+ * save whose deviceIds include an incompatible device".
14425
+ *
14426
+ * THE authority, same arrangement as `device-scope-guard.ts` beside it: the
14427
+ * cap-provider route (`notificationRules.createRule/updateRule`, index.ts)
14428
+ * and the rule bridge (`nc.createRule/updateRule`, nc-actions.ts) both call
14429
+ * `guardRuleDeviceCompat` / `guardPatchDeviceCompat`. Which devices a kind
14430
+ * may scope is `ruleDeviceCompatCapQueries` (`@camstack/types`) — the SAME
14431
+ * table the admin's Devices tab narrows by, so a save can never refuse a
14432
+ * device its own picker just offered. A `sensor` rule's set includes every
14433
+ * camera: a camera-scoped sensor rule is legitimate (D630 §6).
14434
+ *
14435
+ * ASYNC, unlike its sibling guards: it has to ask `deviceManager` which
14436
+ * devices carry the caps. `listDeviceIdsByCaps` is therefore OPTIONAL on the
14437
+ * context — absent on an older wiring, if the cross-addon call throws, or if
14438
+ * it answers EMPTY (the registry not yet warm at boot: `getAllBindings`
14439
+ * answers `[]` with only a warning, which is not a measurement — D315/D393),
14440
+ * the guard FAILS OPEN (never refuses) rather than blocking every save on a
14441
+ * read it cannot make (D49). It is never SILENT about it: an unjudged scoped
14442
+ * save logs a sampled WARN naming the rule and the reason, so a dropped wiring
14443
+ * is visible in production rather than a guard that quietly stopped existing.
14444
+ *
14445
+ * ON UPDATE only the ids the patch ADDS are judged. A device already stored on
14446
+ * the rule is never re-judged: the answer is not stable (switching detection
14447
+ * off on a camera removes its `detection-pipeline` binding, D62; an agent
14448
+ * camera's native caps are missing during the handshake), and re-judging
14449
+ * would make every rule naming that camera un-editable until the operator
14450
+ * removed it — losing a scope a later switch-on would not give back.
14451
+ *
14452
+ * NEVER called at LOAD. `NcRuleSchema.parse` and the store's own read path are
14453
+ * untouched — a rule saved before this ruling, or saved while the capability
14454
+ * read was unavailable, keeps loading and keeps firing exactly as it does
14455
+ * today; only a NEW save attempt is judged.
14456
+ *
14457
+ * `devicesExclude` is NOT checked: this guard judges what the rule actually
14458
+ * MATCHES ON (the include scope), not what it widens away from, and an
14459
+ * operator excluding an incompatible device from an "all except" rule is not
14460
+ * the mistake this exists to catch.
14461
+ */
14462
+ /** How long one rule's "accepted unchecked" WARN stays quiet after it fired. */
14463
+ var UNCHECKED_WARN_WINDOW_MS = 10 * 6e4;
14464
+ /** Bound on remembered rule keys — cleared whole when exceeded. */
14465
+ var UNCHECKED_WARN_MEMO_MAX = 256;
14466
+ /**
14467
+ * Samples the "accepted unchecked" WARN per rule: an editor that autosaves, or
14468
+ * a script, must not turn one unreachable read into a log flood, but the first
14469
+ * save of every rule in a window is always reported.
14470
+ */
14471
+ var NcDeviceCompatWarnSampler = class {
14472
+ lastWarnedAt = /* @__PURE__ */ new Map();
14473
+ shouldWarn(key, now) {
14474
+ const last = this.lastWarnedAt.get(key);
14475
+ if (last !== void 0 && now - last < UNCHECKED_WARN_WINDOW_MS) return false;
14476
+ if (this.lastWarnedAt.size >= UNCHECKED_WARN_MEMO_MAX) this.lastWarnedAt.clear();
14477
+ this.lastWarnedAt.set(key, now);
14478
+ return true;
14479
+ }
14480
+ };
14481
+ var NcDeviceCompatRefusal = class extends Error {
14482
+ kind;
14483
+ incompatibleIds;
14484
+ constructor(kind, incompatibleIds) {
14485
+ super(`rule refused: device(s) ${incompatibleIds.join(", ")} cannot produce a '${kind}' rule's subject`);
14486
+ this.name = "NcDeviceCompatRefusal";
14487
+ this.kind = kind;
14488
+ this.incompatibleIds = incompatibleIds;
14489
+ }
14490
+ };
14491
+ /** The union of every compat query's answer, or why there is none. */
14492
+ async function readCompatibleIds(queries, listDeviceIdsByCaps) {
14493
+ try {
14494
+ const answers = await Promise.all(queries.map((capNames) => listDeviceIdsByCaps(capNames)));
14495
+ return {
14496
+ ok: true,
14497
+ ids: new Set(answers.flat())
14498
+ };
14499
+ } catch (err) {
14500
+ return {
14501
+ ok: false,
14502
+ error: String(err)
14503
+ };
14504
+ }
14505
+ }
14506
+ /**
14507
+ * The check. `judged` is the ids to judge — the whole include list on a
14508
+ * create, only the ADDED ids on an update (see the file header).
14509
+ *
14510
+ * Resolves `not-judged` when the kind has no capability filter
14511
+ * (`ruleDeviceCompatCapQueries` is `null`) or there is nothing to judge —
14512
+ * "every device" is never refused here. Resolves `unchecked` (fail open) when
14513
+ * the read is not wired, throws, or answers nothing at all. Throws
14514
+ * {@link NcDeviceCompatRefusal} naming every incompatible id, never only the
14515
+ * first — an operator fixing the list needs the whole picture in one pass.
14516
+ */
14517
+ async function assertRuleDeviceCompat(rule, listDeviceIdsByCaps, judged = rule.conditions.devices ?? []) {
14518
+ const kind = ruleKindOf(rule);
14519
+ const queries = ruleDeviceCompatCapQueries(kind);
14520
+ if (queries === null || judged.length === 0) return { outcome: "not-judged" };
14521
+ if (listDeviceIdsByCaps === void 0) return {
14522
+ outcome: "unchecked",
14523
+ reason: "unwired",
14524
+ ids: judged
14525
+ };
14526
+ const read = await readCompatibleIds(queries, listDeviceIdsByCaps);
14527
+ if (!read.ok) return {
14528
+ outcome: "unchecked",
14529
+ reason: "read-failed",
14530
+ ids: judged,
14531
+ error: read.error
14532
+ };
14533
+ if (read.ids.size === 0) return {
14534
+ outcome: "unchecked",
14535
+ reason: "answered-empty",
14536
+ ids: judged
14537
+ };
14538
+ const incompatible = judged.filter((id) => !read.ids.has(id));
14539
+ if (incompatible.length > 0) throw new NcDeviceCompatRefusal(kind, incompatible);
14540
+ return { outcome: "compatible" };
14541
+ }
14542
+ /**
14543
+ * Run the check and report what it could not do: a refusal is dropped work, so
14544
+ * it is logged before it is rethrown; an unchecked acceptance is a guard that
14545
+ * did not run, so it is logged (sampled) too.
14546
+ */
14547
+ async function runAndReport(rule, judged, ctx) {
14548
+ let verdict;
14549
+ try {
14550
+ verdict = await assertRuleDeviceCompat(rule, ctx.listDeviceIdsByCaps, judged);
14551
+ } catch (err) {
14552
+ if (err instanceof NcDeviceCompatRefusal) warnRefusal$2(ctx.logger, err, ctx);
14553
+ throw err;
14554
+ }
14555
+ if (verdict.outcome === "unchecked") warnUnchecked(ruleKindOf(rule), verdict, ctx);
14556
+ }
14557
+ function warnRefusal$2(logger, err, ctx) {
14558
+ logger.warn("nc rule refused: device(s) incompatible with the rule kind", { meta: {
14559
+ ...ctx.ruleId !== void 0 ? { ruleId: ctx.ruleId } : {},
14560
+ by: ctx.by,
14561
+ kind: err.kind,
14562
+ incompatibleIds: [...err.incompatibleIds]
14563
+ } });
14564
+ }
14565
+ function warnUnchecked(kind, verdict, ctx) {
14566
+ const now = (ctx.now ?? Date.now)();
14567
+ const key = `${ctx.ruleId ?? `new:${ctx.by}`}:${verdict.reason}`;
14568
+ if (ctx.sampler !== void 0 && !ctx.sampler.shouldWarn(key, now)) return;
14569
+ ctx.logger.warn("nc rule saved WITHOUT the device-compatibility check — accepted unchecked", { meta: {
14570
+ ...ctx.ruleId !== void 0 ? { ruleId: ctx.ruleId } : {},
14571
+ by: ctx.by,
14572
+ kind,
14573
+ reason: verdict.reason,
14574
+ uncheckedIds: [...verdict.ids],
14575
+ ...verdict.error !== void 0 ? { error: verdict.error } : {}
14576
+ } });
14577
+ }
14578
+ /** The create path: the whole include list is judged. */
14579
+ async function guardRuleDeviceCompat(rule, ctx) {
14580
+ await runAndReport(rule, rule.conditions.devices ?? [], ctx);
14581
+ }
14582
+ /**
14583
+ * The update path: the MERGED rule decides the kind, but only the ids the
14584
+ * patch ADDS to `conditions.devices` are judged — a stored id is never
14585
+ * re-judged (see the file header). A patch that adds nothing never pays for a
14586
+ * capability read.
14587
+ */
14588
+ async function guardPatchDeviceCompat(existing, patch, ctx) {
14589
+ if (existing === null) return;
14590
+ const merged = mergedFamilySubject(existing, patch);
14591
+ if (merged === null) return;
14592
+ const stored = new Set(existing.conditions.devices ?? []);
14593
+ await runAndReport(merged, (merged.conditions.devices ?? []).filter((id) => !stored.has(id)), ctx);
14594
+ }
14595
+ //#endregion
14354
14596
  //#region src/notification-center/rule-summary-guard.ts
14355
14597
  /**
14356
14598
  * The hub's half of D647: `systemEventDelivery: { mode: 'summary' }` belongs to
@@ -17195,6 +17437,8 @@ function requireAdmin(caller) {
17195
17437
  return c;
17196
17438
  }
17197
17439
  function makeNcActionHandlers(deps) {
17440
+ /** One sampler per handler set: an unchecked save warns once per rule per window. */
17441
+ const deviceCompatWarnSampler = new NcDeviceCompatWarnSampler();
17198
17442
  /** The alarm half, or a refusal by name — never a made-up "disarmed". */
17199
17443
  const requireAlarm = (action) => {
17200
17444
  if (deps.alarm === void 0) throw new Error(`${action}: the alarm is not wired on this node`);
@@ -17352,6 +17596,12 @@ function makeNcActionHandlers(deps) {
17352
17596
  logger: deps.logger,
17353
17597
  by: c.userId
17354
17598
  });
17599
+ await guardRuleDeviceCompat(parsed, {
17600
+ logger: deps.logger,
17601
+ by: c.userId,
17602
+ listDeviceIdsByCaps: deps.listDeviceIdsByCaps,
17603
+ sampler: deviceCompatWarnSampler
17604
+ });
17355
17605
  guardRuleSystemEventDelivery(parsed, {
17356
17606
  logger: deps.logger,
17357
17607
  by: c.userId
@@ -17394,6 +17644,13 @@ function makeNcActionHandlers(deps) {
17394
17644
  by: c.userId,
17395
17645
  ruleId: input.ruleId
17396
17646
  });
17647
+ await guardPatchDeviceCompat(existing, patch, {
17648
+ logger: deps.logger,
17649
+ by: c.userId,
17650
+ ruleId: input.ruleId,
17651
+ listDeviceIdsByCaps: deps.listDeviceIdsByCaps,
17652
+ sampler: deviceCompatWarnSampler
17653
+ });
17397
17654
  guardPatchSystemEventDelivery(existing, patch, clear, {
17398
17655
  logger: deps.logger,
17399
17656
  by: c.userId,
@@ -17895,9 +18152,9 @@ function makeNcActionHandlers(deps) {
17895
18152
  * reproduce.
17896
18153
  */
17897
18154
  var NC_CLIP_DISPATCH_MARGIN_SEC = 10;
17898
- /** Does this rule ever cut footage from the broker's clip ring? */
17899
- function wantsFootage(rule) {
17900
- return rule.media.gif === true || rule.media.clip === true;
18155
+ /** Does this media policy ever cut footage from the broker's clip ring? */
18156
+ function wantsFootage(media) {
18157
+ return media.gif === true || media.clip === true;
17901
18158
  }
17902
18159
  /** The ask ONE rule makes, or `null` when it needs no retained footage. */
17903
18160
  function askSecondsFor(rule) {
@@ -17906,9 +18163,10 @@ function askSecondsFor(rule) {
17906
18163
  seconds: NC_CLIP_RETENTION_MAX_SEC,
17907
18164
  reason: "occupancy"
17908
18165
  };
17909
- if (!wantsFootage(rule)) return null;
17910
- const pre = rule.media.clipPreRollSec ?? NC_CLIP_PRE_ROLL_DEFAULT_SEC;
17911
- const post = rule.media.clipPostRollSec ?? NC_CLIP_POST_ROLL_DEFAULT_SEC;
18166
+ const media = effectiveMediaPolicyForRule(rule);
18167
+ if (!wantsFootage(media)) return null;
18168
+ const pre = media.clipPreRollSec ?? NC_CLIP_PRE_ROLL_DEFAULT_SEC;
18169
+ const post = media.clipPostRollSec ?? NC_CLIP_POST_ROLL_DEFAULT_SEC;
17912
18170
  return {
17913
18171
  seconds: Math.min(pre + post + NC_CLIP_DISPATCH_MARGIN_SEC, NC_CLIP_RETENTION_MAX_SEC),
17914
18172
  reason: "window"
@@ -17927,12 +18185,13 @@ function deriveClipRetentionAsks(rules) {
17927
18185
  for (const rule of rules) {
17928
18186
  const ask = askSecondsFor(rule);
17929
18187
  if (ask === null) continue;
18188
+ const profile = effectiveMediaPolicyForRule(rule).profile;
17930
18189
  const base = {
17931
18190
  seconds: ask.seconds,
17932
18191
  reason: ask.reason,
17933
18192
  ruleId: rule.id,
17934
18193
  ruleName: rule.name,
17935
- ...rule.media.profile !== void 0 ? { profile: rule.media.profile } : {}
18194
+ ...profile !== void 0 ? { profile } : {}
17936
18195
  };
17937
18196
  const devices = rule.conditions.devices;
17938
18197
  if (devices === void 0 || devices.length === 0) {
@@ -31546,9 +31805,15 @@ var NC_ALARM_ANNOUNCE_RULE_ID = "nc-alarm-announce";
31546
31805
  * A rule's media policy, as the fields a row freezes — ONE derivation, used by
31547
31806
  * every row a rule addresses AND by the alarm's own announcement row when it is
31548
31807
  * the COMBINED siren (the triggering rule's pictures on the alarm's words).
31808
+ *
31809
+ * `effectiveMediaPolicyForRule` is what actually resolves it: a SENSOR rule's
31810
+ * stored `media` is ignored here, in favour of the one-snapshot default
31811
+ * (operator ruling, 2026-10-01) — the rule still LOADS with whatever it has
31812
+ * stored, and `buildEntries` is where the sampled log fires when that stored
31813
+ * choice is about to be overridden.
31549
31814
  */
31550
31815
  function mediaPolicyFields(mediaRule, cropZoneIds) {
31551
- const media = mediaRule.media;
31816
+ const media = effectiveMediaPolicyForRule(mediaRule);
31552
31817
  return {
31553
31818
  media: media.attach,
31554
31819
  ...media.zoneCrop === true && cropZoneIds !== void 0 ? { mediaZoneIds: [...cropZoneIds] } : {},
@@ -31842,13 +32107,14 @@ function cooldownSubjectKind(kind) {
31842
32107
  * the same builder the live path does, so the two can never address different
31843
32108
  * windows. Only the four fields the key is a function of are reconstructed —
31844
32109
  * the class (for `per-class` and audio), the subject kind (which decides
31845
- * whether audio is keyed per class at all), the system event (subject +
32110
+ * whether the class is keyed at all — audio always, occupancy and detections
32111
+ * unless `shared`), the system event (subject +
31846
32112
  * direction) and the device.
31847
32113
  */
31848
32114
  function cooldownSubjectFromOutbox(entry) {
31849
32115
  const subject = entry.payload.subject;
31850
32116
  return {
31851
- kind: cooldownSubjectKind(entry.recordKind),
32117
+ kind: entry.recordKind === "device-event" && subject.occupancy !== void 0 ? "occupancy-event" : cooldownSubjectKind(entry.recordKind),
31852
32118
  recordId: entry.recordId,
31853
32119
  deviceId: entry.deviceId,
31854
32120
  timestamp: subject.timestamp,
@@ -31927,6 +32193,9 @@ function renderAudioScope(devices, excluded) {
31927
32193
  if (devices.length === 0) return excluded.length === 0 ? "@all" : `@all-except:${excluded.join("+")}`;
31928
32194
  return devices.filter((id) => !excluded.includes(id)).join("+");
31929
32195
  }
32196
+ /** {@link NotificationCenter.reportedSensorMediaIgnored} cap, same shape as
32197
+ * the dispatcher's own annotated-fallback memo. */
32198
+ var NC_SENSOR_MEDIA_IGNORED_MEMO_MAX = 5e3;
31930
32199
  var NotificationCenter = class NotificationCenter {
31931
32200
  logger;
31932
32201
  rules;
@@ -31934,6 +32203,11 @@ var NotificationCenter = class NotificationCenter {
31934
32203
  dispatcher;
31935
32204
  deps;
31936
32205
  now;
32206
+ /** Rule ids whose stored (non-default) media policy has already been
32207
+ * reported as ignored at evaluation — ONE line per rule, not per fire. */
32208
+ reportedSensorMediaIgnored = /* @__PURE__ */ new Set();
32209
+ /** Samples the device-compat guard's "accepted unchecked" WARN per rule. */
32210
+ deviceCompatWarnSampler = new NcDeviceCompatWarnSampler();
31937
32211
  /**
31938
32212
  * Every word this centre can print, in the hub's language.
31939
32213
  *
@@ -33714,7 +33988,7 @@ var NotificationCenter = class NotificationCenter {
33714
33988
  const shown = this.unmutedCameras(cameraIds);
33715
33989
  const involved = [sensorId, ...rowShown];
33716
33990
  if (!this.rules.listEnabled("device-event").some((rule) => {
33717
- if (rule.media.attach === "none") return false;
33991
+ if (effectiveMediaPolicyForRule(rule).attach === "none") return false;
33718
33992
  if (!deviceEventRuleMayFireOnKind(rule, sensorKind, sensorRaised)) return false;
33719
33993
  const excluded = rule.conditions.devicesExclude;
33720
33994
  if (excluded !== void 0 && deviceScopeExcludes(excluded, {
@@ -34011,7 +34285,7 @@ var NotificationCenter = class NotificationCenter {
34011
34285
  ruleWantsOccupancyStill(edge) {
34012
34286
  const subject = occupancySubjectFromEdge(edge);
34013
34287
  for (const rule of this.rules.listEnabled("device-event")) {
34014
- if (rule.media.attach === "none") continue;
34288
+ if (effectiveMediaPolicyForRule(rule).attach === "none") continue;
34015
34289
  const occ = rule.conditions.occupancy;
34016
34290
  if (occ === void 0 || !matchesOccupancy(occ, subject)) continue;
34017
34291
  const devices = rule.conditions.devices;
@@ -34278,6 +34552,12 @@ var NotificationCenter = class NotificationCenter {
34278
34552
  logger: this.logger,
34279
34553
  by: caller.userId
34280
34554
  });
34555
+ await guardRuleDeviceCompat(rule, {
34556
+ logger: this.logger,
34557
+ by: caller.userId,
34558
+ listDeviceIdsByCaps: this.deps.listDeviceIdsByCaps,
34559
+ sampler: this.deviceCompatWarnSampler
34560
+ });
34281
34561
  guardRuleSystemEventDelivery(rule, {
34282
34562
  logger: this.logger,
34283
34563
  by: caller.userId
@@ -34315,6 +34595,13 @@ var NotificationCenter = class NotificationCenter {
34315
34595
  by: caller.userId,
34316
34596
  ruleId
34317
34597
  });
34598
+ await guardPatchDeviceCompat(existing, patch, {
34599
+ logger: this.logger,
34600
+ by: caller.userId,
34601
+ ruleId,
34602
+ listDeviceIdsByCaps: this.deps.listDeviceIdsByCaps,
34603
+ sampler: this.deviceCompatWarnSampler
34604
+ });
34318
34605
  guardPatchSystemEventDelivery(existing, patch, clear ?? [], {
34319
34606
  logger: this.logger,
34320
34607
  by: caller.userId,
@@ -35362,7 +35649,7 @@ var NotificationCenter = class NotificationCenter {
35362
35649
  buttons: unresolvable.join(", ")
35363
35650
  }
35364
35651
  });
35365
- if (!noOwnerReported && kind === "device-event" && subject.trackId === void 0 && subject.linkedStills === void 0 && rule.media.attach !== "none") {
35652
+ if (!noOwnerReported && kind === "device-event" && subject.trackId === void 0 && subject.linkedStills === void 0 && effectiveMediaPolicyForRule(rule).attach !== "none") {
35366
35653
  noOwnerReported = true;
35367
35654
  const linked = subject.linkedCameraIds;
35368
35655
  const meta = {
@@ -35740,6 +36027,24 @@ var NotificationCenter = class NotificationCenter {
35740
36027
  }
35741
36028
  });
35742
36029
  }
36030
+ /**
36031
+ * ONE line per rule id, the first time a SENSOR rule's stored media policy
36032
+ * is about to be overridden by {@link effectiveMediaPolicyForRule}'s
36033
+ * one-snapshot default (operator ruling, 2026-10-01). Never refuses the
36034
+ * rule — it still loads and still fires — this only says the stored choice
36035
+ * is not the one being used.
36036
+ */
36037
+ warnSensorMediaIgnoredOnce(rule) {
36038
+ if (mediaPolicyMatchesSensorDefault(rule.media)) return;
36039
+ if (this.reportedSensorMediaIgnored.has(rule.id)) return;
36040
+ if (this.reportedSensorMediaIgnored.size >= NC_SENSOR_MEDIA_IGNORED_MEMO_MAX) this.reportedSensorMediaIgnored.clear();
36041
+ this.reportedSensorMediaIgnored.add(rule.id);
36042
+ this.logger.info("sensor rule carries a media choice — ignored at evaluation, one snapshot is always attached", { meta: {
36043
+ ruleId: rule.id,
36044
+ rule: rule.name,
36045
+ storedMedia: rule.media
36046
+ } });
36047
+ }
35743
36048
  buildEntries(rule, subject, kind, matchedOn, userTargets = [], origin = "pipeline", cooldown, upgrade, group) {
35744
36049
  const hasEventMedia = kind === "object-event" || kind === "package-event";
35745
36050
  const isTrackScoped = kind === "object-event" || kind === "track-end";
@@ -35747,6 +36052,7 @@ var NotificationCenter = class NotificationCenter {
35747
36052
  const alarmSource = subject.systemEvent?.alarmSource;
35748
36053
  const mediaRule = alarmSource !== void 0 ? this.rules.get(alarmSource.ruleId) ?? rule : rule;
35749
36054
  const noMedia = isSystemEvent && alarmSource === void 0;
36055
+ if (ruleKindOf(mediaRule) === "sensor") this.warnSensorMediaIgnoredOnce(mediaRule);
35750
36056
  const direct = new Set(rule.targets.map((t) => t.targetId));
35751
36057
  const renderedZones = notificationZones(rule, subject);
35752
36058
  const confirm = frozenConfirmPolicy(rule, isSystemEvent);
@@ -98899,6 +99205,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
98899
99205
  listCallerTargetIds: async (userId) => {
98900
99206
  return (await api.notificationOutput.listTargets.query({})).filter((t) => t.config["ownerUserId"] === userId).map((t) => t.id);
98901
99207
  },
99208
+ listDeviceIdsByCaps: (capNames) => api.deviceManager.listDeviceIdsByCaps.query({ capNames: [...capNames] }),
98902
99209
  dropRuleMosaics: async (ruleId) => {
98903
99210
  const mediaStore = this.mediaStore;
98904
99211
  if (mediaStore === null) return;
@@ -99815,6 +100122,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
99815
100122
  addonId: device.addonId
99816
100123
  };
99817
100124
  },
100125
+ listDeviceIdsByCaps: (capNames) => api.deviceManager.listDeviceIdsByCaps.query({ capNames: [...capNames] }),
99818
100126
  isDeviceDeleted: async (deviceId) => await api.deviceManager.getDevice.query({ deviceId }) === null,
99819
100127
  readNodeDirectory: () => api.nodes.directory.query(),
99820
100128
  getSnapshot: (deviceId) => api.snapshot.getSnapshot.query({ deviceId }),
@@ -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-yOiRjNnR.mjs")).catch((e) => {
33
+ return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-QE0Juzwb.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.305",
3
+ "version": "1.2.306",
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",