@camstack/addon-post-analysis 1.2.298 → 1.2.299
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-D9WaswEs.mjs → clip-model-registry-DCztUu1G.mjs} +100 -1
- package/dist/{clip-model-registry-olxNKN7T.js → clip-model-registry-hTbsQ-z7.js} +111 -0
- 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-Bk7ACano.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-thT_ff8Z.mjs} +1 -1
- package/dist/pipeline-analytics/{_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D1CfMkm2.mjs → _virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-C3QGV7zb.mjs} +1 -1
- package/dist/pipeline-analytics/{hostInit-DtPqVNsM.mjs → hostInit-D9z3Da9D.mjs} +1 -1
- package/dist/pipeline-analytics/index.js +370 -20
- package/dist/pipeline-analytics/index.mjs +385 -36
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { $ as NcRuleSchema, $n as
|
|
1
|
+
import { $ as NcRuleSchema, $n as partialRecord, $t as isScheduleActive, A as LockStateSchema, At as audioMetricsCapability, B as NC_DEFAULT_SNOOZE_MINUTES, Bn as defineCustomActions, Bt as embeddingRefusalOf, C as EMBEDDING_REQUIREMENTS_UNAVAILABLE, Cn as systemEventFamilyProblems, Ct as TimelapseRuleInputSchema, D as FULL_IMAGE_BBOX, Dn as templateVarsFor, Dt as addonWidgetsSourceCapability, E as FIRST_LEVEL_MACRO_CLASSES, En as templateCarriesSummary, Et as TrackSourceSchema, F as MediaFileKindEnum, Fn as errMsg, Ft as deriveRecordingMode, G as NC_TAXONOMY, Gn as sleep$1, Gt as faceGalleryCapability, Hn as isDeviceScopedCap, I as MotionTriggeredBySchema, In as BaseAddon, It as describeSystemEventDeliveryProblem, J as NcAlarmSettingsPatchSchema, Jn as boolean, Jt as gifFromMp4Args, K as NC_TEMPLATE_VARS, Kn as _enum, Kt as failureContributionCapability, L as NC_ALARM_SYSTEM_EVENT_KINDS, Ln as CamProfileSchema, Lt as describeSystemEventFamilyProblem, M as MAX_BIRTH_DECISION_RECORDS, Mn as evaluateSensorEdge, Mt as buildEventKindDescriptor, Nn as isSourceCap, Nt as consumableLowPercentOf, O as FailureCounters, On as vectorDimFromBase64, Ot as alarmPanelCapability, P as MOTION_CLOSE_AFTER_MS, Pn as DeviceType, Pt as cosineSimilarity$1, Q as NcRulePatchSchema, Qn as object, Qt as isMediaOwnerType, R as NC_CONDITION_CATALOG, Rn as createEvent, S as EMBEDDING_REQUIREMENTS_FAILED, Sn as systemEventDeliveryProblems, St as TIMELAPSE_DENSE_FLOOR_SEC, T as EVENT_OWNER_TYPES, Tn as systemEventSummaryScheduleOf, Tt as TimelapseRuleSchema, U as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, Un as nodePin, Ut as encodeVectorBase64, V as NC_SENSOR_TRANSITION_KINDS, Vn as hydrateSchema, W as NC_TANK_SYSTEM_EVENT_KINDS, Wt as evictionPolicyOfLocation, X as NcConditionsSchema, Xn as literal, Xt as isEventOwnerType, Y as NcConditionDescriptorSchema, Yn as discriminatedUnion, Yt as isDetectionMacroClass, Z as NcRuleInputSchema, Zn as number, Zt as isKnownTemplateVar, _n as sceneMonitorCapability, a as CLIP_EMBEDDING_STEP_ID, an as notificationRulesCapability, at as NcSnoozeSuppressedSchema, b as DeclaredDevices, bn as storageOccupancyCapability, bt as SCENE_DIVERGED, c as resolveClusterModelPin, cn as pipelineAnalyticsCapability, ct as NcTemplatePreviewInputSchema, d as ArchivedDebugNoteSchema, dn as readMotionTriggeredBy, dt as OpsLogEntrySchema, en as isSystemDelivery, er as record, et as NcRuleTargetSchema, f as BaseDevice, fn as readTimelapseGeneratedAt, g as DEFAULT_EVENT_COLOR, gn as ruleBelongsToAlarm$1, gt as RetrainStatusSchema, h as CoverStateSchema, ht as RebuildObjectEmbeddingsRefusalSchema, in as mayWriteToLocation, it as NcSnoozeSchema, j as MAX_ARCHIVED_DEBUG_NOTES, jn as canonicalHash, jt as audioModeOf, k as LabelAttributionSchema, kn as zoneAnalyticsCapability, kt as assertTimelapseCadences, l as AUDIO_MACRO_LABELS, ln as plateGalleryCapability, lt as NcTemplatePreviewSchema, m as COCO_TO_MACRO, mn as resolveLocationMode, mt as RECORDING_SOURCE_CAMSTACK_ADDON, nn as isVectorIndexDimConflict, nr as unknown, nt as NcScheduleSchema, o as FACE_EMBEDDING_STEP_ID, on as occupancyScope, ot as NcSystemEventKindSchema, p as BirthDecisionRecordSchema, pn as resolveClipSearchMinScore, pt as RECORDING_EXPORT_MAX_READ_BYTES, q as NcAlarmConfigSchema, qn as array, qt as gifDeriveSpeed, rn as kebabToCamel, rr as EventCategory, rt as NcSnoozeInputSchema, s as readClusterModelPinStrict, st as NcTaxonomySchema, t as BUILTIN_CLIP_MODELS, tn as isSystemEventSummaryRule, tr as string, tt as NcRuleUpdateInputSchema, u as AlarmArmModeSchema, un as readDeviceStateFrom, ut as NcTemplateVarDescriptorSchema, v as DETECTION_MACRO_CLASSES, vn as sensorRaisedOf, vt as SCENE_DEFAULT_ANCHOR_THRESHOLD, w as EVENT_KIND_BY_CAP, wn as systemEventFilterApplies, wt as TimelapseRulePatchSchema, x as EMBEDDING_MODEL_FAILED, xn as subKindsOf, xt as SceneMonitorSchema, yn as servedTemplateVars, yt as SCENE_DEFAULT_UNCOVERED_POLICY, z as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, zn as customAction } from "../clip-model-registry-DCztUu1G.mjs";
|
|
2
2
|
import { t as __exportAll } from "../embedding-encoder/index.mjs";
|
|
3
|
-
import * as fs from "node:fs";
|
|
3
|
+
import * as fs$1 from "node:fs";
|
|
4
4
|
import { promises } from "node:fs";
|
|
5
5
|
import * as path$1 from "node:path";
|
|
6
6
|
import path from "node:path";
|
|
@@ -8,6 +8,7 @@ import { createHash, createHmac, randomBytes, randomUUID, timingSafeEqual } from
|
|
|
8
8
|
import { execFile } from "node:child_process";
|
|
9
9
|
import { startEventLoopStallMonitor } from "@camstack/system/addon-utils";
|
|
10
10
|
import { pipeline } from "node:stream/promises";
|
|
11
|
+
import fs from "node:fs/promises";
|
|
11
12
|
import sharp from "sharp";
|
|
12
13
|
import os from "node:os";
|
|
13
14
|
import { isDeepStrictEqual } from "node:util";
|
|
@@ -3152,16 +3153,16 @@ function errnoCode(err) {
|
|
|
3152
3153
|
async function writeFileAtomic(filePath, data) {
|
|
3153
3154
|
const tmp = path$1.join(path$1.dirname(filePath), `.${path$1.basename(filePath)}.${randomUUID()}.tmp`);
|
|
3154
3155
|
try {
|
|
3155
|
-
await fs.promises.writeFile(tmp, data);
|
|
3156
|
+
await fs$1.promises.writeFile(tmp, data);
|
|
3156
3157
|
await renameOver(tmp, filePath);
|
|
3157
3158
|
} catch (err) {
|
|
3158
|
-
await fs.promises.rm(tmp, { force: true }).catch(() => void 0);
|
|
3159
|
+
await fs$1.promises.rm(tmp, { force: true }).catch(() => void 0);
|
|
3159
3160
|
throw err;
|
|
3160
3161
|
}
|
|
3161
3162
|
}
|
|
3162
3163
|
async function renameOver(tmp, filePath) {
|
|
3163
3164
|
for (let attempt = 0;; attempt += 1) try {
|
|
3164
|
-
await fs.promises.rename(tmp, filePath);
|
|
3165
|
+
await fs$1.promises.rename(tmp, filePath);
|
|
3165
3166
|
return;
|
|
3166
3167
|
} catch (err) {
|
|
3167
3168
|
const code = errnoCode(err);
|
|
@@ -3170,8 +3171,8 @@ async function renameOver(tmp, filePath) {
|
|
|
3170
3171
|
await new Promise((resolve) => setTimeout(resolve, WINDOWS_RENAME_RETRY_MS));
|
|
3171
3172
|
continue;
|
|
3172
3173
|
}
|
|
3173
|
-
await fs.promises.copyFile(tmp, filePath);
|
|
3174
|
-
await fs.promises.rm(tmp, { force: true });
|
|
3174
|
+
await fs$1.promises.copyFile(tmp, filePath);
|
|
3175
|
+
await fs$1.promises.rm(tmp, { force: true });
|
|
3175
3176
|
return;
|
|
3176
3177
|
}
|
|
3177
3178
|
}
|
|
@@ -3246,28 +3247,28 @@ var FilesystemStorageProvider = class {
|
|
|
3246
3247
|
location,
|
|
3247
3248
|
relativePath
|
|
3248
3249
|
});
|
|
3249
|
-
await fs.promises.mkdir(path$1.dirname(filePath), { recursive: true });
|
|
3250
|
+
await fs$1.promises.mkdir(path$1.dirname(filePath), { recursive: true });
|
|
3250
3251
|
if (Buffer.isBuffer(data)) await writeFileAtomic(filePath, data);
|
|
3251
3252
|
else {
|
|
3252
3253
|
const tmp = path$1.join(path$1.dirname(filePath), `.${path$1.basename(filePath)}.${randomUUID()}.tmp`);
|
|
3253
3254
|
try {
|
|
3254
|
-
await pipeline(data, fs.createWriteStream(tmp));
|
|
3255
|
-
await fs.promises.rename(tmp, filePath);
|
|
3255
|
+
await pipeline(data, fs$1.createWriteStream(tmp));
|
|
3256
|
+
await fs$1.promises.rename(tmp, filePath);
|
|
3256
3257
|
} catch (err) {
|
|
3257
|
-
await fs.promises.rm(tmp, { force: true }).catch(() => void 0);
|
|
3258
|
+
await fs$1.promises.rm(tmp, { force: true }).catch(() => void 0);
|
|
3258
3259
|
throw err;
|
|
3259
3260
|
}
|
|
3260
3261
|
}
|
|
3261
3262
|
}
|
|
3262
3263
|
async read({ location, relativePath }) {
|
|
3263
|
-
return fs.promises.readFile(await this.resolve({
|
|
3264
|
+
return fs$1.promises.readFile(await this.resolve({
|
|
3264
3265
|
location,
|
|
3265
3266
|
relativePath
|
|
3266
3267
|
}));
|
|
3267
3268
|
}
|
|
3268
3269
|
async exists({ location, relativePath }) {
|
|
3269
3270
|
try {
|
|
3270
|
-
await fs.promises.access(await this.resolve({
|
|
3271
|
+
await fs$1.promises.access(await this.resolve({
|
|
3271
3272
|
location,
|
|
3272
3273
|
relativePath
|
|
3273
3274
|
}));
|
|
@@ -3281,7 +3282,7 @@ var FilesystemStorageProvider = class {
|
|
|
3281
3282
|
if (!base) return [];
|
|
3282
3283
|
const dir = prefix ? path$1.join(base, prefix) : base;
|
|
3283
3284
|
try {
|
|
3284
|
-
return (await fs.promises.readdir(dir, { withFileTypes: true })).map((e) => prefix ? `${prefix}/${e.name}` : e.name);
|
|
3285
|
+
return (await fs$1.promises.readdir(dir, { withFileTypes: true })).map((e) => prefix ? `${prefix}/${e.name}` : e.name);
|
|
3285
3286
|
} catch {
|
|
3286
3287
|
return [];
|
|
3287
3288
|
}
|
|
@@ -3291,19 +3292,19 @@ var FilesystemStorageProvider = class {
|
|
|
3291
3292
|
location,
|
|
3292
3293
|
relativePath
|
|
3293
3294
|
});
|
|
3294
|
-
await fs.promises.rm(filePath, { force: true });
|
|
3295
|
+
await fs$1.promises.rm(filePath, { force: true });
|
|
3295
3296
|
}
|
|
3296
3297
|
async getAvailableSpace({ location }) {
|
|
3297
3298
|
const base = this.locationPaths.get(location);
|
|
3298
3299
|
if (!base) return null;
|
|
3299
3300
|
try {
|
|
3300
3301
|
let target = base;
|
|
3301
|
-
while (!fs.existsSync(target)) {
|
|
3302
|
+
while (!fs$1.existsSync(target)) {
|
|
3302
3303
|
const parent = path$1.dirname(target);
|
|
3303
3304
|
if (!parent || parent === target) return null;
|
|
3304
3305
|
target = parent;
|
|
3305
3306
|
}
|
|
3306
|
-
const stats = await fs.promises.statfs(target);
|
|
3307
|
+
const stats = await fs$1.promises.statfs(target);
|
|
3307
3308
|
return stats.bavail * stats.bsize;
|
|
3308
3309
|
} catch {
|
|
3309
3310
|
return null;
|
|
@@ -9973,14 +9974,25 @@ function occupancySubjectFromEdge(edge) {
|
|
|
9973
9974
|
threshold: edge.threshold
|
|
9974
9975
|
};
|
|
9975
9976
|
}
|
|
9976
|
-
/**
|
|
9977
|
-
*
|
|
9977
|
+
/**
|
|
9978
|
+
* Build the subject for a `package-event` evaluation (a persisted `package`
|
|
9979
|
+
* object-event; `phase` derives from the event `state` at the call site).
|
|
9980
|
+
*
|
|
9981
|
+
* `observedAt` (D682, D684): a pick-up row's `timestamp` is when the departure
|
|
9982
|
+
* was CONCLUDED — five minutes of unseen observed time after the parcel went —
|
|
9983
|
+
* so the detector STORES the instant it happened on the row, and the footage is
|
|
9984
|
+
* cut around that (`media-anchor.ts`). Read from the row HERE, the one place
|
|
9985
|
+
* every path builds a package subject (live hook, boot reconcile, dry-run), so
|
|
9986
|
+
* none of them can anchor differently. `timestamp` keeps its meaning; a row
|
|
9987
|
+
* written before D684 has none, which the anchor reads as unknown, out loud.
|
|
9988
|
+
*/
|
|
9978
9989
|
function subjectFromPackageEvent(ev, phase) {
|
|
9979
9990
|
return {
|
|
9980
9991
|
kind: "package-event",
|
|
9981
9992
|
recordId: String(ev.id),
|
|
9982
9993
|
deviceId: ev.deviceId,
|
|
9983
9994
|
timestamp: ev.timestamp,
|
|
9995
|
+
...ev.observedAt !== void 0 ? { observedAt: ev.observedAt } : {},
|
|
9984
9996
|
classNames: [ev.className],
|
|
9985
9997
|
...displayLabel(ev) !== void 0 ? { label: displayLabel(ev) } : {},
|
|
9986
9998
|
...recognitionPatch(ev.subLabelMeta),
|
|
@@ -10911,7 +10923,11 @@ function incomingFromAudioEvent(event, stillOwnerId) {
|
|
|
10911
10923
|
})
|
|
10912
10924
|
};
|
|
10913
10925
|
}
|
|
10914
|
-
/**
|
|
10926
|
+
/**
|
|
10927
|
+
* Package object-event persist (delivered / picked-up) — the live hook and the
|
|
10928
|
+
* boot reconcile alike. A pick-up's instant is read from the row
|
|
10929
|
+
* (`event.observedAt`, D684) inside `subjectFromPackageEvent`.
|
|
10930
|
+
*/
|
|
10915
10931
|
function incomingFromPackageEvent(event, phase) {
|
|
10916
10932
|
return {
|
|
10917
10933
|
subject: subjectFromPackageEvent(event, phase),
|
|
@@ -10921,7 +10937,8 @@ function incomingFromPackageEvent(event, phase) {
|
|
|
10921
10937
|
tags: { deviceId: event.deviceId },
|
|
10922
10938
|
meta: {
|
|
10923
10939
|
eventId: event.id,
|
|
10924
|
-
phase
|
|
10940
|
+
phase,
|
|
10941
|
+
...event.observedAt !== void 0 ? { observedAt: event.observedAt } : {}
|
|
10925
10942
|
}
|
|
10926
10943
|
})
|
|
10927
10944
|
};
|
|
@@ -19314,9 +19331,14 @@ function mediaAnchor(subject) {
|
|
|
19314
19331
|
lagMs: subject.timestamp - observedAt
|
|
19315
19332
|
};
|
|
19316
19333
|
}
|
|
19334
|
+
function selfDatingKindOf(subject) {
|
|
19335
|
+
if (subject.occupancy !== void 0) return "occupancy";
|
|
19336
|
+
if (subject.packagePhase === "picked-up") return "package pick-up";
|
|
19337
|
+
return null;
|
|
19338
|
+
}
|
|
19317
19339
|
/**
|
|
19318
19340
|
* True when this anchor is the conclusion instant AND the subject was one that
|
|
19319
|
-
* should have been able to date itself —
|
|
19341
|
+
* should have been able to date itself — see {@link selfDatingKindOf}.
|
|
19320
19342
|
*
|
|
19321
19343
|
* Split from {@link mediaAnchor} because the anchor must stay pure of any
|
|
19322
19344
|
* notion of subject KIND, while the log line that matters is exactly the one
|
|
@@ -20420,7 +20442,8 @@ var NcDispatcher = class {
|
|
|
20420
20442
|
};
|
|
20421
20443
|
const preRollSec = entry.payload.mediaClipPreRollSec ?? 4;
|
|
20422
20444
|
const anchor = mediaAnchor(entry.payload.subject);
|
|
20423
|
-
|
|
20445
|
+
const selfDating = selfDatingKindOf(entry.payload.subject);
|
|
20446
|
+
if (anchorFellBack(anchor, selfDating !== null)) this.deps.logger.warn(`${selfDating ?? "occupancy"} footage anchored on the conclusion — moment unknown`, {
|
|
20424
20447
|
tags: { deviceId: entry.payload.subject.deviceId },
|
|
20425
20448
|
meta: {
|
|
20426
20449
|
ruleId: entry.ruleId,
|
|
@@ -20448,7 +20471,7 @@ var NcDispatcher = class {
|
|
|
20448
20471
|
preRollSec,
|
|
20449
20472
|
retentionSec: this.ringRetentionSec(entry.payload.subject.deviceId),
|
|
20450
20473
|
wanted: [...wantGif ? ["gif"] : [], ...wantMp4 ? ["video"] : []],
|
|
20451
|
-
next: this.
|
|
20474
|
+
next: this.recordedFollowUp(entry).kinds.length > 0 ? "recorded-clip-follow-up" : "no-clip"
|
|
20452
20475
|
}
|
|
20453
20476
|
});
|
|
20454
20477
|
return {
|
|
@@ -20502,6 +20525,13 @@ var NcDispatcher = class {
|
|
|
20502
20525
|
* alert for a complete one, which is precisely the wrong trade for the
|
|
20503
20526
|
* notification that tells an operator someone is at the door.
|
|
20504
20527
|
*
|
|
20528
|
+
* A GIF rule is served here too (D682): a package pick-up is concluded five
|
|
20529
|
+
* minutes after it happened, so a gif anchored on the pick-up is always
|
|
20530
|
+
* outside the ring. The gif is derived from THIS cut's bytes
|
|
20531
|
+
* (`deriveGifFromClip`) — one cut, never a second renderer — and a moment the
|
|
20532
|
+
* recordings cannot serve ships NO gif, by named reason, rather than a gif of
|
|
20533
|
+
* the wrong time.
|
|
20534
|
+
*
|
|
20505
20535
|
* So the alert's latency is UNCHANGED, and **the clip is attached later**, as
|
|
20506
20536
|
* a follow-up send to the same target carrying the same `tag` — a phone
|
|
20507
20537
|
* collapses the two, so what the operator sees is the notification gaining
|
|
@@ -20524,7 +20554,9 @@ var NcDispatcher = class {
|
|
|
20524
20554
|
*/
|
|
20525
20555
|
startRecordedFootage(entry, target, notification) {
|
|
20526
20556
|
const cut = this.deps.cutRecordedClip;
|
|
20527
|
-
|
|
20557
|
+
const plan = this.recordedFollowUp(entry);
|
|
20558
|
+
const wanted = plan.kinds;
|
|
20559
|
+
if (cut === void 0 || wanted.length === 0 && plan.gifRefused === void 0 && plan.videoRefused === void 0) return;
|
|
20528
20560
|
const preRollSec = entry.payload.mediaClipPreRollSec ?? 4;
|
|
20529
20561
|
const anchor = mediaAnchor(entry.payload.subject);
|
|
20530
20562
|
if (footageSourceFor({
|
|
@@ -20534,34 +20566,70 @@ var NcDispatcher = class {
|
|
|
20534
20566
|
ringRetentionSec: this.ringRetentionSec(entry.payload.subject.deviceId)
|
|
20535
20567
|
}) !== "recordings") return;
|
|
20536
20568
|
const deviceId = entry.payload.subject.deviceId;
|
|
20569
|
+
if (plan.gifRefused !== void 0) this.deps.logger.info("recorded gif follow-up: none — the gif is not cut from the recordings", {
|
|
20570
|
+
tags: { deviceId },
|
|
20571
|
+
meta: {
|
|
20572
|
+
ruleId: entry.ruleId,
|
|
20573
|
+
eventId: entry.recordId,
|
|
20574
|
+
targetId: target.id,
|
|
20575
|
+
reason: plan.gifRefused,
|
|
20576
|
+
anchoredOn: anchor.source,
|
|
20577
|
+
...anchor.fallback !== void 0 ? { anchorFallback: anchor.fallback } : {},
|
|
20578
|
+
next: wanted
|
|
20579
|
+
}
|
|
20580
|
+
});
|
|
20581
|
+
if (plan.videoRefused !== void 0) this.deps.logger.info("recorded video follow-up: none — the video is not cut from the recordings", {
|
|
20582
|
+
tags: { deviceId },
|
|
20583
|
+
meta: {
|
|
20584
|
+
ruleId: entry.ruleId,
|
|
20585
|
+
eventId: entry.recordId,
|
|
20586
|
+
targetId: target.id,
|
|
20587
|
+
reason: plan.videoRefused,
|
|
20588
|
+
anchoredOn: anchor.source,
|
|
20589
|
+
...anchor.fallback !== void 0 ? { anchorFallback: anchor.fallback } : {},
|
|
20590
|
+
next: wanted
|
|
20591
|
+
}
|
|
20592
|
+
});
|
|
20593
|
+
if (wanted.length === 0) return;
|
|
20594
|
+
const videoSpeed = entry.payload.mediaClipSpeed;
|
|
20537
20595
|
const pending = (async () => {
|
|
20538
20596
|
const result = await cut({
|
|
20539
20597
|
deviceId,
|
|
20540
20598
|
aroundMs: anchor.atMs,
|
|
20541
20599
|
preRollSec,
|
|
20542
20600
|
postRollSec: entry.payload.mediaClipPostRollSec ?? 6,
|
|
20543
|
-
...
|
|
20601
|
+
...videoSpeed !== void 0 ? { speed: videoSpeed } : {},
|
|
20544
20602
|
ruleId: entry.ruleId,
|
|
20545
20603
|
recordId: entry.recordId
|
|
20546
20604
|
});
|
|
20547
20605
|
if (!result.ok) {
|
|
20548
|
-
this.deps.logger.info("recorded
|
|
20606
|
+
this.deps.logger.info("recorded footage follow-up: none — the recorded cut failed", {
|
|
20549
20607
|
tags: { deviceId },
|
|
20550
20608
|
meta: {
|
|
20551
20609
|
ruleId: entry.ruleId,
|
|
20552
20610
|
eventId: entry.recordId,
|
|
20553
20611
|
targetId: target.id,
|
|
20554
|
-
reason: result.reason
|
|
20612
|
+
reason: result.reason,
|
|
20613
|
+
wanted
|
|
20555
20614
|
}
|
|
20556
20615
|
});
|
|
20557
20616
|
return;
|
|
20558
20617
|
}
|
|
20559
|
-
const
|
|
20560
|
-
|
|
20561
|
-
|
|
20562
|
-
|
|
20563
|
-
|
|
20564
|
-
|
|
20618
|
+
const attachments = await this.recordedAttachments(entry, wanted, result.mp4);
|
|
20619
|
+
if (attachments.length === 0) {
|
|
20620
|
+
this.deps.logger.info("recorded clip follow-up: none — the gif could not be derived", {
|
|
20621
|
+
tags: { deviceId },
|
|
20622
|
+
meta: {
|
|
20623
|
+
ruleId: entry.ruleId,
|
|
20624
|
+
eventId: entry.recordId,
|
|
20625
|
+
targetId: target.id,
|
|
20626
|
+
reason: "gif-derive-failed",
|
|
20627
|
+
wanted
|
|
20628
|
+
}
|
|
20629
|
+
});
|
|
20630
|
+
return;
|
|
20631
|
+
}
|
|
20632
|
+
const withUrls = await this.withArtifactUrls(entry, attachments);
|
|
20565
20633
|
const sent = await this.deps.send({
|
|
20566
20634
|
addonId: target.addonId,
|
|
20567
20635
|
targetId: target.id,
|
|
@@ -20590,6 +20658,8 @@ var NcDispatcher = class {
|
|
|
20590
20658
|
target: target.name,
|
|
20591
20659
|
profile: result.profile,
|
|
20592
20660
|
bytes: result.mp4.byteLength,
|
|
20661
|
+
attachments: attachments.map((a) => a.mediaType),
|
|
20662
|
+
anchoredOn: anchor.source,
|
|
20593
20663
|
lagMs: this.now() - entry.updatedAt
|
|
20594
20664
|
}
|
|
20595
20665
|
});
|
|
@@ -20609,6 +20679,84 @@ var NcDispatcher = class {
|
|
|
20609
20679
|
});
|
|
20610
20680
|
}
|
|
20611
20681
|
/**
|
|
20682
|
+
* What a recorded follow-up for this row would CARRY — the one answer both
|
|
20683
|
+
* the refusal line (`next`) and the follow-up read, so the log cannot promise
|
|
20684
|
+
* a follow-up the dispatcher will not send.
|
|
20685
|
+
*
|
|
20686
|
+
* A video when the rule asked for one. A gif only for a package PICK-UP
|
|
20687
|
+
* whose moment is KNOWN (D682): the gif is derived from the recorded cut's
|
|
20688
|
+
* own bytes, the same way the broker derives it from a ring cut — one cut,
|
|
20689
|
+
* two containers, never a second renderer.
|
|
20690
|
+
*
|
|
20691
|
+
* Narrow on purpose. A pick-up is the one kind whose moment is ALWAYS outside
|
|
20692
|
+
* the ring; every other kind keeps the gif behaviour it had (the ring's, or
|
|
20693
|
+
* none) rather than silently gaining a recorder export per notification. And
|
|
20694
|
+
* a pick-up that fell back to its conclusion gets no recorded footage at all,
|
|
20695
|
+
* gif OR video — cutting the recordings there is exactly the doormat D682
|
|
20696
|
+
* removed (see {@link NcRecordedGifRefusal}, {@link NcRecordedVideoRefusal}).
|
|
20697
|
+
*/
|
|
20698
|
+
recordedFollowUp(entry) {
|
|
20699
|
+
if (this.deps.cutRecordedClip === void 0) return { kinds: [] };
|
|
20700
|
+
const gifRefused = this.recordedGifRefusal(entry);
|
|
20701
|
+
const videoRefused = this.recordedVideoRefusal(entry);
|
|
20702
|
+
const kinds = [];
|
|
20703
|
+
if (entry.payload.mediaGif === true && gifRefused === void 0) kinds.push("gif");
|
|
20704
|
+
if (entry.payload.mediaClip === true && videoRefused === void 0) kinds.push("video");
|
|
20705
|
+
return {
|
|
20706
|
+
kinds,
|
|
20707
|
+
...gifRefused !== void 0 ? { gifRefused } : {},
|
|
20708
|
+
...videoRefused !== void 0 ? { videoRefused } : {}
|
|
20709
|
+
};
|
|
20710
|
+
}
|
|
20711
|
+
/** Why this row's video is not cut from the recordings, or `undefined` when
|
|
20712
|
+
* it is (or when the rule asked for no video). */
|
|
20713
|
+
recordedVideoRefusal(entry) {
|
|
20714
|
+
if (entry.payload.mediaClip !== true) return void 0;
|
|
20715
|
+
const subject = entry.payload.subject;
|
|
20716
|
+
if (selfDatingKindOf(subject) !== "package pick-up") return void 0;
|
|
20717
|
+
if (anchorFellBack(mediaAnchor(subject), true)) return "moment-unknown";
|
|
20718
|
+
}
|
|
20719
|
+
/** Why this row's gif is not cut from the recordings, or `undefined` when it
|
|
20720
|
+
* is (or when the rule asked for no gif). */
|
|
20721
|
+
recordedGifRefusal(entry) {
|
|
20722
|
+
if (entry.payload.mediaGif !== true) return void 0;
|
|
20723
|
+
if (this.deps.deriveGifFromClip === void 0) return "no-derive";
|
|
20724
|
+
const subject = entry.payload.subject;
|
|
20725
|
+
if (selfDatingKindOf(subject) !== "package pick-up") return "not-a-pick-up";
|
|
20726
|
+
if (anchorFellBack(mediaAnchor(subject), true)) return "moment-unknown";
|
|
20727
|
+
}
|
|
20728
|
+
/**
|
|
20729
|
+
* The follow-up's attachments, gif first and video second — the order the
|
|
20730
|
+
* ring path ships them in. A gif that could not be derived is left out (its
|
|
20731
|
+
* reason already logged); the video, when asked for, still ships.
|
|
20732
|
+
*/
|
|
20733
|
+
async recordedAttachments(entry, wanted, mp4) {
|
|
20734
|
+
const out = [];
|
|
20735
|
+
const derive = this.deps.deriveGifFromClip;
|
|
20736
|
+
if (wanted.includes("gif") && derive !== void 0) {
|
|
20737
|
+
const gif = await derive({
|
|
20738
|
+
deviceId: entry.payload.subject.deviceId,
|
|
20739
|
+
mp4,
|
|
20740
|
+
...entry.payload.mediaClipSpeed !== void 0 ? { videoSpeed: entry.payload.mediaClipSpeed } : {},
|
|
20741
|
+
ruleId: entry.ruleId,
|
|
20742
|
+
recordId: entry.recordId
|
|
20743
|
+
});
|
|
20744
|
+
if (gif.ok) out.push({
|
|
20745
|
+
mediaType: "gif",
|
|
20746
|
+
bytes: gif.gif,
|
|
20747
|
+
mime: "image/gif",
|
|
20748
|
+
name: "event.gif"
|
|
20749
|
+
});
|
|
20750
|
+
}
|
|
20751
|
+
if (wanted.includes("video")) out.push({
|
|
20752
|
+
mediaType: "video",
|
|
20753
|
+
bytes: mp4,
|
|
20754
|
+
mime: "video/mp4",
|
|
20755
|
+
name: "event.mp4"
|
|
20756
|
+
});
|
|
20757
|
+
return out;
|
|
20758
|
+
}
|
|
20759
|
+
/**
|
|
20612
20760
|
* Settle every recorded-clip follow-up this dispatcher has in flight.
|
|
20613
20761
|
*
|
|
20614
20762
|
* A TEST SEAM, and the honest kind: the follow-up is detached by design, so
|
|
@@ -32536,6 +32684,9 @@ var NotificationCenter = class NotificationCenter {
|
|
|
32536
32684
|
* delivered/picked-up), in the SAME moment as the durable insert. Feeds the
|
|
32537
32685
|
* `package-event` trigger. Package events ARE object-event rows, so the boot
|
|
32538
32686
|
* crash-gap reconcile re-covers them (routed by className in {@link reconcile}).
|
|
32687
|
+
*
|
|
32688
|
+
* When a pick-up HAPPENED is on the row (`event.observedAt`, D684), so this
|
|
32689
|
+
* hook and the reconcile read it from the same place.
|
|
32539
32690
|
*/
|
|
32540
32691
|
onPackageEventPersisted(event, phase) {
|
|
32541
32692
|
this.consumeEvent(incomingFromPackageEvent(event, phase));
|
|
@@ -53030,7 +53181,9 @@ var MOTION_EVENTS_COLLECTION = "pipeline-analytics:motion-events";
|
|
|
53030
53181
|
* @durable class=ledger owner=pipeline-analytics
|
|
53031
53182
|
* write="one row per detected object per processed frame — every tracked
|
|
53032
53183
|
* detection the frame processor emits, plus the appearance events and the
|
|
53033
|
-
* synthetic package-drop events. Every row carries the trackId it belongs to.
|
|
53184
|
+
* synthetic package-drop events. Every row carries the trackId it belongs to.
|
|
53185
|
+
* A package PICK-UP row also carries observedAt, when the parcel went,
|
|
53186
|
+
* beside its timestamp, when the departure was concluded (D684)."
|
|
53034
53187
|
* retention="TRACK-OWNED: it has no clock of its own. Rows go only when their
|
|
53035
53188
|
* track goes, through EventStore.deleteByTracks — which folds in the deletion
|
|
53036
53189
|
* of the event's child crops so a caller cannot take the events and leave the
|
|
@@ -53237,7 +53390,21 @@ var OBJECT_COLUMNS = [
|
|
|
53237
53390
|
{
|
|
53238
53391
|
name: "importance",
|
|
53239
53392
|
type: "REAL"
|
|
53240
|
-
}
|
|
53393
|
+
},
|
|
53394
|
+
(
|
|
53395
|
+
/**
|
|
53396
|
+
* When a package PICK-UP happened, beside `timestamp` (when it was
|
|
53397
|
+
* CONCLUDED, five minutes later) — see `ObjectEvent.observedAt` (D684).
|
|
53398
|
+
*
|
|
53399
|
+
* DECLARED, or the backend drops it on write (see `frameId`). Additive: the
|
|
53400
|
+
* collection gains the column in place (`ALTER TABLE … ADD COLUMN`), and every
|
|
53401
|
+
* row written before it reads SQL NULL → absent after `stripNulls`, which is
|
|
53402
|
+
* the truth about it: the moment is unknown. Only the package detector sets it.
|
|
53403
|
+
*/
|
|
53404
|
+
{
|
|
53405
|
+
name: "observedAt",
|
|
53406
|
+
type: "INTEGER"
|
|
53407
|
+
})
|
|
53241
53408
|
];
|
|
53242
53409
|
var AUDIO_COLUMNS = [
|
|
53243
53410
|
...COMMON_BASE_COLUMNS,
|
|
@@ -59025,6 +59192,180 @@ function decodeBase64(base64) {
|
|
|
59025
59192
|
}
|
|
59026
59193
|
}
|
|
59027
59194
|
//#endregion
|
|
59195
|
+
//#region src/notification-center/recorded-gif.ts
|
|
59196
|
+
/**
|
|
59197
|
+
* The notification GIF for a moment only the RECORDINGS still hold — derived
|
|
59198
|
+
* from the recorded clip's own bytes (D682).
|
|
59199
|
+
*
|
|
59200
|
+
* ## Why this exists
|
|
59201
|
+
*
|
|
59202
|
+
* A package pick-up is concluded five minutes after the parcel went
|
|
59203
|
+
* (`PACKAGE_STILLNESS_TTL_MS`). Once its footage is anchored on the pick-up
|
|
59204
|
+
* itself rather than on the conclusion (`media-anchor.ts`), the window is far
|
|
59205
|
+
* older than any clip ring (≤ 60 s, `NC_CLIP_RETENTION_MAX_SEC`), so the ring
|
|
59206
|
+
* refuses it. A gif-only rule then had NOTHING: the recorded follow-up served
|
|
59207
|
+
* only a rule that asked for a video. The honest fix for "the gif shows the
|
|
59208
|
+
* empty doormat" is not "no gif" — it is the gif of the pick-up, from the
|
|
59209
|
+
* recordings.
|
|
59210
|
+
*
|
|
59211
|
+
* ## One cut, and the gif is DERIVED from it
|
|
59212
|
+
*
|
|
59213
|
+
* The recorded clip (`recorded-clip.ts`, one `recordingExport` render) is the
|
|
59214
|
+
* only cut. The gif is derived from ITS bytes with the SAME filter chain the
|
|
59215
|
+
* broker uses on a ring cut (`gifFromMp4Args` in `@camstack/types`), so a gif
|
|
59216
|
+
* of an old moment and a gif of a live one look the same, and a rule that asks
|
|
59217
|
+
* for both a gif and a video gets two containers of ONE window — the guarantee
|
|
59218
|
+
* `NcEventMediaRequest` exists for.
|
|
59219
|
+
*
|
|
59220
|
+
* ## Never throws, every miss named
|
|
59221
|
+
*
|
|
59222
|
+
* `derive-failed` (ffmpeg could not produce it) and `stage-failed` (the clip
|
|
59223
|
+
* could not be written where ffmpeg can read it) are logged with
|
|
59224
|
+
* `tags: { deviceId }` (D400: a missing attachment names its reason).
|
|
59225
|
+
*/
|
|
59226
|
+
/** Bound on one derive: a ~10 s window encodes in well under a second; a
|
|
59227
|
+
* derive that has not finished in 20 s is wedged. Same bound as the broker's. */
|
|
59228
|
+
var NC_RECORDED_GIF_TIMEOUT_MS = 2e4;
|
|
59229
|
+
/** A notification gif is a few hundred KB; this is headroom, not a budget. */
|
|
59230
|
+
var RECORDED_GIF_MAX_BUFFER = 32 * 1024 * 1024;
|
|
59231
|
+
/**
|
|
59232
|
+
* Derive the gif. Never throws; every `ok: false` has logged its reason.
|
|
59233
|
+
*/
|
|
59234
|
+
async function deriveRecordedGif(ports, req) {
|
|
59235
|
+
const tags = { deviceId: req.deviceId };
|
|
59236
|
+
const common = {
|
|
59237
|
+
ruleId: req.ruleId,
|
|
59238
|
+
eventId: req.recordId,
|
|
59239
|
+
sourceBytes: req.mp4.byteLength
|
|
59240
|
+
};
|
|
59241
|
+
let file;
|
|
59242
|
+
try {
|
|
59243
|
+
file = await ports.writeTemp(req.mp4);
|
|
59244
|
+
} catch (err) {
|
|
59245
|
+
ports.logger.warn("recorded gif: could not stage the recorded clip — no gif", {
|
|
59246
|
+
tags,
|
|
59247
|
+
meta: {
|
|
59248
|
+
...common,
|
|
59249
|
+
reason: "stage-failed",
|
|
59250
|
+
error: String(err)
|
|
59251
|
+
}
|
|
59252
|
+
});
|
|
59253
|
+
return {
|
|
59254
|
+
ok: false,
|
|
59255
|
+
reason: "stage-failed"
|
|
59256
|
+
};
|
|
59257
|
+
}
|
|
59258
|
+
try {
|
|
59259
|
+
const speed = gifDeriveSpeed(4, req.videoSpeed ?? 1);
|
|
59260
|
+
const args = gifFromMp4Args({
|
|
59261
|
+
maxWidth: 640,
|
|
59262
|
+
fps: 12,
|
|
59263
|
+
speed,
|
|
59264
|
+
input: file
|
|
59265
|
+
});
|
|
59266
|
+
const startedAt = Date.now();
|
|
59267
|
+
let ran;
|
|
59268
|
+
try {
|
|
59269
|
+
ran = await ports.run(await ports.resolveFfmpeg(), args);
|
|
59270
|
+
} catch (err) {
|
|
59271
|
+
ran = {
|
|
59272
|
+
ok: false,
|
|
59273
|
+
error: String(err)
|
|
59274
|
+
};
|
|
59275
|
+
}
|
|
59276
|
+
const out = ran.ok ? ran.stdout : null;
|
|
59277
|
+
if (out === null || out.byteLength === 0) {
|
|
59278
|
+
ports.logger.warn("recorded gif: the derive failed — the follow-up carries no gif", {
|
|
59279
|
+
tags,
|
|
59280
|
+
meta: {
|
|
59281
|
+
...common,
|
|
59282
|
+
reason: "derive-failed",
|
|
59283
|
+
error: ran.ok ? "ffmpeg produced no bytes" : ran.error.slice(-400)
|
|
59284
|
+
}
|
|
59285
|
+
});
|
|
59286
|
+
return {
|
|
59287
|
+
ok: false,
|
|
59288
|
+
reason: "derive-failed"
|
|
59289
|
+
};
|
|
59290
|
+
}
|
|
59291
|
+
const gif = new Uint8Array(new ArrayBuffer(out.byteLength));
|
|
59292
|
+
gif.set(out);
|
|
59293
|
+
ports.logger.info("recorded gif: derived from the recorded clip", {
|
|
59294
|
+
tags,
|
|
59295
|
+
meta: {
|
|
59296
|
+
...common,
|
|
59297
|
+
gifBytes: gif.byteLength,
|
|
59298
|
+
width: 640,
|
|
59299
|
+
fps: 12,
|
|
59300
|
+
speed,
|
|
59301
|
+
encodeMs: Date.now() - startedAt
|
|
59302
|
+
}
|
|
59303
|
+
});
|
|
59304
|
+
return {
|
|
59305
|
+
ok: true,
|
|
59306
|
+
gif
|
|
59307
|
+
};
|
|
59308
|
+
} finally {
|
|
59309
|
+
await ports.removeTemp(file).catch((err) => {
|
|
59310
|
+
ports.logger.warn("recorded gif: could not remove the staged clip", {
|
|
59311
|
+
tags,
|
|
59312
|
+
meta: {
|
|
59313
|
+
...common,
|
|
59314
|
+
file,
|
|
59315
|
+
error: String(err)
|
|
59316
|
+
}
|
|
59317
|
+
});
|
|
59318
|
+
});
|
|
59319
|
+
}
|
|
59320
|
+
}
|
|
59321
|
+
/** The production ports: the pinned ffmpeg, a temp file, a bounded child. */
|
|
59322
|
+
function buildRecordedGifPorts(input) {
|
|
59323
|
+
return {
|
|
59324
|
+
logger: input.logger,
|
|
59325
|
+
resolveFfmpeg: input.resolveFfmpeg,
|
|
59326
|
+
run: (cmd, args) => new Promise((resolve) => {
|
|
59327
|
+
execFile(cmd, [...args], {
|
|
59328
|
+
encoding: "buffer",
|
|
59329
|
+
maxBuffer: RECORDED_GIF_MAX_BUFFER,
|
|
59330
|
+
timeout: NC_RECORDED_GIF_TIMEOUT_MS,
|
|
59331
|
+
killSignal: "SIGKILL"
|
|
59332
|
+
}, (err, stdout) => resolve(err !== null ? {
|
|
59333
|
+
ok: false,
|
|
59334
|
+
error: String(err)
|
|
59335
|
+
} : {
|
|
59336
|
+
ok: true,
|
|
59337
|
+
stdout
|
|
59338
|
+
}));
|
|
59339
|
+
}),
|
|
59340
|
+
writeTemp: (bytes) => stageTempClip(path.join(os.tmpdir(), `camstack-nc-gif-${randomUUID()}.mp4`), bytes, {
|
|
59341
|
+
write: (file, data) => fs.writeFile(file, data),
|
|
59342
|
+
remove: (file) => fs.rm(file, { force: true })
|
|
59343
|
+
}),
|
|
59344
|
+
removeTemp: (file) => fs.rm(file, { force: true })
|
|
59345
|
+
};
|
|
59346
|
+
}
|
|
59347
|
+
/**
|
|
59348
|
+
* Write the clip to `file`, and on a failed write remove whatever landed.
|
|
59349
|
+
*
|
|
59350
|
+
* The path is named BEFORE the write, because a write can create the file and
|
|
59351
|
+
* then fail (ENOSPC half-way): the caller's `finally` only knows a path the
|
|
59352
|
+
* write RETURNED, so a partial `camstack-nc-gif-*.mp4` used to stay in the temp
|
|
59353
|
+
* directory for good. The write's error is re-thrown — the caller names it
|
|
59354
|
+
* (`stage-failed`, tagged per camera). A removal that ALSO fails is a real leak
|
|
59355
|
+
* and rides in that same error's message, so it reaches that one line rather
|
|
59356
|
+
* than a second, untagged one.
|
|
59357
|
+
*/
|
|
59358
|
+
async function stageTempClip(file, bytes, io) {
|
|
59359
|
+
try {
|
|
59360
|
+
await io.write(file, bytes);
|
|
59361
|
+
return file;
|
|
59362
|
+
} catch (err) {
|
|
59363
|
+
const leaked = await io.remove(file).then(() => null, (removeErr) => String(removeErr));
|
|
59364
|
+
if (leaked === null) throw err;
|
|
59365
|
+
throw new Error(`${String(err)}; the partial file ${file} was NOT removed: ${leaked}`);
|
|
59366
|
+
}
|
|
59367
|
+
}
|
|
59368
|
+
//#endregion
|
|
59028
59369
|
//#region src/shared/frame/crop-extractor.ts
|
|
59029
59370
|
/**
|
|
59030
59371
|
* The ONE reading of a normalized box against a frame: round, then clamp so
|
|
@@ -70498,10 +70839,12 @@ var PackageDropDetector = class {
|
|
|
70498
70839
|
pickupAt: entry.lastConfirmedAt
|
|
70499
70840
|
}
|
|
70500
70841
|
});
|
|
70842
|
+
const observedAt = collector?.observedAt ?? pickupInstantOf(entry);
|
|
70501
70843
|
const draft = {
|
|
70502
70844
|
kind: "object",
|
|
70503
70845
|
deviceId: entry.deviceId,
|
|
70504
70846
|
timestamp,
|
|
70847
|
+
observedAt,
|
|
70505
70848
|
source: "pipeline",
|
|
70506
70849
|
idempotencyKey: pickedUpKey,
|
|
70507
70850
|
trackId: mediaTrackId,
|
|
@@ -70553,6 +70896,8 @@ var PackageDropDetector = class {
|
|
|
70553
70896
|
idempotencyKey: pickedUpKey,
|
|
70554
70897
|
deliveredEventId: delivered.id,
|
|
70555
70898
|
mediaTrackId,
|
|
70899
|
+
observedAt,
|
|
70900
|
+
concludedLagMs: timestamp - observedAt,
|
|
70556
70901
|
...collector !== void 0 ? {
|
|
70557
70902
|
collectorTrackId: collector.trackId,
|
|
70558
70903
|
collectorClassName: collector.className,
|
|
@@ -89067,6 +89412,10 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
89067
89412
|
readExportBytes: (input) => api.recordingExport.readExportBytes.query(input),
|
|
89068
89413
|
deleteExport: (input) => api.recordingExport.deleteExport.mutate(input)
|
|
89069
89414
|
}, req),
|
|
89415
|
+
deriveGifFromClip: (req) => deriveRecordedGif(buildRecordedGifPorts({
|
|
89416
|
+
logger: logger.child("RecordedGif"),
|
|
89417
|
+
resolveFfmpeg: () => this.ctx.deps.ensureFfmpeg()
|
|
89418
|
+
}), req),
|
|
89070
89419
|
publishArtifact: async (bytes, mime, deviceId) => await this.ncArtifactPlane?.publish(bytes, mime, deviceId) ?? null,
|
|
89071
89420
|
viewerUrlBase: async () => pickArtifactBaseUrl(await this.ncEndpoints()),
|
|
89072
89421
|
indexArtifact: async (bytes, mime, meta) => await this.ncArtifactPlane?.publishIndexed(bytes, mime, meta) ?? {
|
|
@@ -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-thT_ff8Z.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.299",
|
|
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",
|