@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.
- package/dist/{clip-model-registry-t2ey3w0B.js → clip-model-registry-C67UM_q_.js} +128 -6
- package/dist/{clip-model-registry-EA6x7Vd5.mjs → clip-model-registry-C9Aw4qkh.mjs} +117 -7
- package/dist/embedding-encoder/index.js +1 -1
- package/dist/embedding-encoder/index.mjs +1 -1
- package/dist/pipeline-analytics/_stub.js +1 -1
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-yOiRjNnR.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-QE0Juzwb.mjs} +1 -1
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-MwQBD526.mjs +26 -0
- package/dist/pipeline-analytics/{hostInit-6Km5THPt.mjs → hostInit-DzNrV8y8.mjs} +1 -1
- package/dist/pipeline-analytics/index.js +330 -22
- package/dist/pipeline-analytics/index.mjs +330 -22
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CieM-gpB.mjs +0 -26
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, $n as
|
|
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
|
-
*
|
|
10654
|
-
*
|
|
10655
|
-
*
|
|
10656
|
-
*
|
|
10657
|
-
*
|
|
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
|
-
|
|
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$
|
|
14391
|
+
if (err instanceof NcDevicesExcludeRefusal) warnRefusal$3(ctx.logger, err, ctx);
|
|
14328
14392
|
throw err;
|
|
14329
14393
|
}
|
|
14330
14394
|
}
|
|
14331
|
-
function warnRefusal$
|
|
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
|
|
17899
|
-
function wantsFootage(
|
|
17900
|
-
return
|
|
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
|
-
|
|
17910
|
-
|
|
17911
|
-
const
|
|
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
|
-
...
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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-
|
|
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.
|
|
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",
|