@camstack/addon-post-analysis 1.2.173 → 1.2.175
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/{dist-BXc3lu5t.mjs → dist-B1cFmGC0.mjs} +20 -1
- package/dist/{dist-LIFo4F1P.js → dist-BfdKgU7-.js} +20 -1
- package/dist/embedding-encoder/index.js +1 -1
- package/dist/embedding-encoder/index.mjs +1 -1
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-C2HBf1pQ.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-CSd331cv.mjs} +3 -3
- package/dist/pipeline-analytics/{hostInit-ByKDRuKE.mjs → hostInit-ChNi37CS.mjs} +3 -3
- package/dist/pipeline-analytics/index.js +83 -1
- package/dist/pipeline-analytics/index.mjs +83 -1
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +1 -1
|
@@ -13146,7 +13146,26 @@ var DiscoveryCandidateSchema = object({
|
|
|
13146
13146
|
* identity ahead of adoption. Rendering metadata (unit, precision)
|
|
13147
13147
|
* flows live through the cap STATUS SLICE after adoption.
|
|
13148
13148
|
*/
|
|
13149
|
-
sourceInfo: SourceInfoSchema.optional()
|
|
13149
|
+
sourceInfo: SourceInfoSchema.optional(),
|
|
13150
|
+
/**
|
|
13151
|
+
* Set when this candidate is a device the provider ALREADY owns.
|
|
13152
|
+
*
|
|
13153
|
+
* A scan cannot generally produce the identity a device was onboarded under
|
|
13154
|
+
* (Reolink keys on `mac-<mac>`, learned at adopt time), so a stableId
|
|
13155
|
+
* comparison never matches and an owned device looks addable. Re-adopting one
|
|
13156
|
+
* overwrites its config with scan-derived values — that is how a Home Hub's
|
|
13157
|
+
* Baichuan port was overwritten with its ONVIF port, taking the hub and its
|
|
13158
|
+
* three child cameras offline for four hours.
|
|
13159
|
+
*
|
|
13160
|
+
* A provider that can recognise its own devices says so here. Absent means
|
|
13161
|
+
* "not recognised", which is not the same as "known to be new" — a provider
|
|
13162
|
+
* that cannot tell simply never sets it.
|
|
13163
|
+
*/
|
|
13164
|
+
alreadyOnboarded: boolean().optional(),
|
|
13165
|
+
/** Numeric id of the device this candidate was matched to. Set with `alreadyOnboarded`. */
|
|
13166
|
+
onboardedDeviceId: number().optional(),
|
|
13167
|
+
/** Operator-facing name of the matched device, so the UI can say WHICH one it is. */
|
|
13168
|
+
onboardedName: string().optional()
|
|
13150
13169
|
});
|
|
13151
13170
|
/**
|
|
13152
13171
|
* Flat device summary returned by `createDevice` / `adoptDiscoveredDevice`.
|
|
@@ -13177,7 +13177,26 @@ var DiscoveryCandidateSchema = object({
|
|
|
13177
13177
|
* identity ahead of adoption. Rendering metadata (unit, precision)
|
|
13178
13178
|
* flows live through the cap STATUS SLICE after adoption.
|
|
13179
13179
|
*/
|
|
13180
|
-
sourceInfo: SourceInfoSchema.optional()
|
|
13180
|
+
sourceInfo: SourceInfoSchema.optional(),
|
|
13181
|
+
/**
|
|
13182
|
+
* Set when this candidate is a device the provider ALREADY owns.
|
|
13183
|
+
*
|
|
13184
|
+
* A scan cannot generally produce the identity a device was onboarded under
|
|
13185
|
+
* (Reolink keys on `mac-<mac>`, learned at adopt time), so a stableId
|
|
13186
|
+
* comparison never matches and an owned device looks addable. Re-adopting one
|
|
13187
|
+
* overwrites its config with scan-derived values — that is how a Home Hub's
|
|
13188
|
+
* Baichuan port was overwritten with its ONVIF port, taking the hub and its
|
|
13189
|
+
* three child cameras offline for four hours.
|
|
13190
|
+
*
|
|
13191
|
+
* A provider that can recognise its own devices says so here. Absent means
|
|
13192
|
+
* "not recognised", which is not the same as "known to be new" — a provider
|
|
13193
|
+
* that cannot tell simply never sets it.
|
|
13194
|
+
*/
|
|
13195
|
+
alreadyOnboarded: boolean().optional(),
|
|
13196
|
+
/** Numeric id of the device this candidate was matched to. Set with `alreadyOnboarded`. */
|
|
13197
|
+
onboardedDeviceId: number().optional(),
|
|
13198
|
+
/** Operator-facing name of the matched device, so the UI can say WHICH one it is. */
|
|
13199
|
+
onboardedName: string().optional()
|
|
13181
13200
|
});
|
|
13182
13201
|
/**
|
|
13183
13202
|
* Flat device summary returned by `createDevice` / `adoptDiscoveredDevice`.
|
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
5
|
+
const require_dist = require("../dist-BfdKgU7-.js");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
7
|
node_fs = require_dist.__toESM(node_fs);
|
|
8
8
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { At as BaseAddon, F as PoolMemoryWatchdog, St as resolvePoolMemoryPolicy, at as embeddingEncoderCapability, gt as parseProcStatus, ut as hfModelUrl } from "../dist-
|
|
1
|
+
import { At as BaseAddon, F as PoolMemoryWatchdog, St as resolvePoolMemoryPolicy, at as embeddingEncoderCapability, gt as parseProcStatus, ut as hfModelUrl } from "../dist-B1cFmGC0.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -3,7 +3,7 @@ import "./dist-CYZr2fwk.mjs";
|
|
|
3
3
|
var e = {
|
|
4
4
|
"@camstack/sdk": {
|
|
5
5
|
name: "@camstack/sdk",
|
|
6
|
-
version: "1.2.
|
|
6
|
+
version: "1.2.64",
|
|
7
7
|
scope: ["default"],
|
|
8
8
|
loaded: !1,
|
|
9
9
|
from: "addon_pipeline_analytics_widgets",
|
|
@@ -18,7 +18,7 @@ var e = {
|
|
|
18
18
|
},
|
|
19
19
|
"@camstack/types": {
|
|
20
20
|
name: "@camstack/types",
|
|
21
|
-
version: "1.2.
|
|
21
|
+
version: "1.2.144",
|
|
22
22
|
scope: ["default"],
|
|
23
23
|
loaded: !1,
|
|
24
24
|
from: "addon_pipeline_analytics_widgets",
|
|
@@ -33,7 +33,7 @@ var e = {
|
|
|
33
33
|
},
|
|
34
34
|
"@camstack/ui-library": {
|
|
35
35
|
name: "@camstack/ui-library",
|
|
36
|
-
version: "1.2.
|
|
36
|
+
version: "1.2.110",
|
|
37
37
|
scope: ["default"],
|
|
38
38
|
loaded: !1,
|
|
39
39
|
from: "addon_pipeline_analytics_widgets",
|
|
@@ -36,7 +36,7 @@ async function r() {
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
"@camstack/types": {
|
|
39
|
-
version: "1.2.
|
|
39
|
+
version: "1.2.144",
|
|
40
40
|
scope: "default",
|
|
41
41
|
shareConfig: {
|
|
42
42
|
singleton: !0,
|
|
@@ -45,7 +45,7 @@ async function r() {
|
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
47
|
"@camstack/sdk": {
|
|
48
|
-
version: "1.2.
|
|
48
|
+
version: "1.2.64",
|
|
49
49
|
scope: "default",
|
|
50
50
|
shareConfig: {
|
|
51
51
|
singleton: !0,
|
|
@@ -81,7 +81,7 @@ async function r() {
|
|
|
81
81
|
}
|
|
82
82
|
},
|
|
83
83
|
"@camstack/ui-library": {
|
|
84
|
-
version: "1.2.
|
|
84
|
+
version: "1.2.110",
|
|
85
85
|
scope: "default",
|
|
86
86
|
shareConfig: {
|
|
87
87
|
singleton: !0,
|
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
5
|
+
const require_dist = require("../dist-BfdKgU7-.js");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
7
|
node_fs = require_dist.__toESM(node_fs, 1);
|
|
8
8
|
let node_path = require("node:path");
|
|
@@ -45339,6 +45339,48 @@ async function copyFaceCropIfTrackHasNoThumbnail(store, input) {
|
|
|
45339
45339
|
return true;
|
|
45340
45340
|
}
|
|
45341
45341
|
//#endregion
|
|
45342
|
+
//#region src/pipeline-analytics/detail-refusal.ts
|
|
45343
|
+
/**
|
|
45344
|
+
* Recognises the runner's TYPED `not-attached` refusal from a
|
|
45345
|
+
* `pipelineRunner.runDetailSubtree` call.
|
|
45346
|
+
*
|
|
45347
|
+
* The refusal crosses the wire as an ERROR whose message carries a marker,
|
|
45348
|
+
* not as a result field: the cap output schema
|
|
45349
|
+
* (`@camstack/types` `pipeline-runner.cap.ts` → `z.object({ details
|
|
45350
|
+
* }).nullable()`) is parsed on the hub route and Zod strips unknown keys, so a
|
|
45351
|
+
* refusal field cannot survive without a types + codegen + server-train
|
|
45352
|
+
* change. Error messages DO survive the route (tRPC carries `error.message`;
|
|
45353
|
+
* see `cap-route-error-formatter.ts`).
|
|
45354
|
+
*
|
|
45355
|
+
* The marker constant is a TWIN of
|
|
45356
|
+
* `addon-pipeline/src/pipeline-runner/detail-park.ts`
|
|
45357
|
+
* `DETAIL_NOT_ATTACHED_MARKER` — addons never import each other (`ctx.api` is
|
|
45358
|
+
* the only cross-addon layer), so the value is duplicated here the same way
|
|
45359
|
+
* `composeDetailSteps` mirrors the pipeline catalog's chain. Keep the two
|
|
45360
|
+
* identical.
|
|
45361
|
+
*
|
|
45362
|
+
* Why the dispatcher cares: this refusal is about the camera's SESSION state
|
|
45363
|
+
* (the on-motion session closed and the runner's detail park grace has
|
|
45364
|
+
* lapsed), not about one frame — so the full-frame and crop fallback rungs are
|
|
45365
|
+
* structurally doomed and must be skipped, feeding the scheduler's bounded
|
|
45366
|
+
* give-up directly.
|
|
45367
|
+
*/
|
|
45368
|
+
var DETAIL_NOT_ATTACHED_MARKER = "runDetailSubtree-refused:not-attached";
|
|
45369
|
+
/** Best-effort message extraction across transport error shapes. */
|
|
45370
|
+
function messageOf(err) {
|
|
45371
|
+
if (err instanceof Error) return err.message;
|
|
45372
|
+
if (typeof err === "string") return err;
|
|
45373
|
+
if (typeof err === "object" && err !== null) {
|
|
45374
|
+
const message = Reflect.get(err, "message");
|
|
45375
|
+
if (typeof message === "string") return message;
|
|
45376
|
+
}
|
|
45377
|
+
return "";
|
|
45378
|
+
}
|
|
45379
|
+
/** Did this `runDetailSubtree` error carry the runner's not-attached marker? */
|
|
45380
|
+
function isDetailNotAttachedRefusal(err) {
|
|
45381
|
+
return messageOf(err).includes(DETAIL_NOT_ATTACHED_MARKER);
|
|
45382
|
+
}
|
|
45383
|
+
//#endregion
|
|
45342
45384
|
//#region src/pipeline-analytics/detail-scheduler.ts
|
|
45343
45385
|
/** Default backoff/period when a step's cadence omits `minIntervalMs`. */
|
|
45344
45386
|
var DEFAULT_MIN_INTERVAL_MS = 1e3;
|
|
@@ -45719,6 +45761,14 @@ var TrackDetailDispatcher = class {
|
|
|
45719
45761
|
* On D9/D18: the payload that crosses in rung 2 is a COMPRESSED JPEG fetched on
|
|
45720
45762
|
* demand, per TRACK per dispatch (≤2 in flight per device, ~1 Hz) and only after
|
|
45721
45763
|
* rung 1 missed — never a frame-rate stream, and never raw pixels.
|
|
45764
|
+
*
|
|
45765
|
+
* ONE outcome stops the ladder cold: the runner's typed `not-attached`
|
|
45766
|
+
* refusal (`detail-refusal.ts`). It names the camera's SESSION state, not
|
|
45767
|
+
* this frame — the session closed and the runner's detail park grace has
|
|
45768
|
+
* lapsed — so the two remaining rungs are structurally doomed (the retained
|
|
45769
|
+
* store is purged with the session; `captureCrop` is native-strict against
|
|
45770
|
+
* the same missing lease). Walking them anyway is what burned two extra
|
|
45771
|
+
* cross-node RPCs per refusal, ~600–900 times an hour fleet-wide.
|
|
45722
45772
|
*/
|
|
45723
45773
|
async runOnce(deviceId, dev, req, frame) {
|
|
45724
45774
|
const parent = {
|
|
@@ -45735,6 +45785,10 @@ var TrackDetailDispatcher = class {
|
|
|
45735
45785
|
}, frame.nodeId);
|
|
45736
45786
|
if (primary !== null) return primary.details;
|
|
45737
45787
|
} catch (err) {
|
|
45788
|
+
if (isDetailNotAttachedRefusal(err)) {
|
|
45789
|
+
this.warnNotAttachedThrottled(deviceId, dev, req);
|
|
45790
|
+
return null;
|
|
45791
|
+
}
|
|
45738
45792
|
this.deps.logger.debug("detail primary call failed — trying frame fallback", {
|
|
45739
45793
|
tags: { deviceId },
|
|
45740
45794
|
meta: {
|
|
@@ -45767,6 +45821,10 @@ var TrackDetailDispatcher = class {
|
|
|
45767
45821
|
if (derived !== null) return derived.details;
|
|
45768
45822
|
}
|
|
45769
45823
|
} catch (err) {
|
|
45824
|
+
if (isDetailNotAttachedRefusal(err)) {
|
|
45825
|
+
this.warnNotAttachedThrottled(deviceId, dev, req);
|
|
45826
|
+
return null;
|
|
45827
|
+
}
|
|
45770
45828
|
this.deps.logger.debug("detail full-frame fallback call failed", {
|
|
45771
45829
|
tags: { deviceId },
|
|
45772
45830
|
meta: {
|
|
@@ -45788,6 +45846,10 @@ var TrackDetailDispatcher = class {
|
|
|
45788
45846
|
if (retry !== null) return retry.details;
|
|
45789
45847
|
}
|
|
45790
45848
|
} catch (err) {
|
|
45849
|
+
if (isDetailNotAttachedRefusal(err)) {
|
|
45850
|
+
this.warnNotAttachedThrottled(deviceId, dev, req);
|
|
45851
|
+
return null;
|
|
45852
|
+
}
|
|
45791
45853
|
this.deps.logger.debug("detail crop-fallback call failed", {
|
|
45792
45854
|
tags: { deviceId },
|
|
45793
45855
|
meta: {
|
|
@@ -45800,6 +45862,26 @@ var TrackDetailDispatcher = class {
|
|
|
45800
45862
|
this.warnFailThrottled(deviceId, dev, req);
|
|
45801
45863
|
return null;
|
|
45802
45864
|
}
|
|
45865
|
+
/**
|
|
45866
|
+
* The typed refusal is EXPECTED for a track that outlives the runner's
|
|
45867
|
+
* detail park grace (a closing track's last dispatches), so it logs its own
|
|
45868
|
+
* line — the reason is knowable, unlike the every-rung-missed warn — and
|
|
45869
|
+
* shares the per-device throttle. Never silent: this branch drops the
|
|
45870
|
+
* track's enrichment for good once the give-up bound is reached.
|
|
45871
|
+
*/
|
|
45872
|
+
warnNotAttachedThrottled(deviceId, dev, req) {
|
|
45873
|
+
const now = Date.now();
|
|
45874
|
+
if (now - dev.lastFailWarnAt < FAIL_WARN_THROTTLE_MS) return;
|
|
45875
|
+
dev.lastFailWarnAt = now;
|
|
45876
|
+
this.deps.logger.warn("detail dispatch refused: camera not attached (park grace lapsed) — skipping fallback rungs", {
|
|
45877
|
+
tags: { deviceId },
|
|
45878
|
+
meta: {
|
|
45879
|
+
trackId: req.trackId,
|
|
45880
|
+
stepId: req.stepId,
|
|
45881
|
+
reason: req.reason
|
|
45882
|
+
}
|
|
45883
|
+
});
|
|
45884
|
+
}
|
|
45803
45885
|
warnFailThrottled(deviceId, dev, req) {
|
|
45804
45886
|
const now = Date.now();
|
|
45805
45887
|
if (now - dev.lastFailWarnAt < FAIL_WARN_THROTTLE_MS) return;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as audioModeOf, A as NcSnoozeSchema, At as BaseAddon, B as SCENE_DEFAULT_UNCOVERED_POLICY, Bt as boolean, C as NcConditionDescriptorSchema, Ct as sceneMonitorCapability, D as NcRuleTargetSchema, Dt as videoclipsCapability, E as NcRuleSchema, Et as vectorDimFromBase64, Ft as isDeviceScopedCap, G as TimelapseRulePatchSchema, Gt as partialRecord, H as SceneMonitorSchema, Ht as literal, I as RECORDING_EXPORT_MAX_READ_BYTES, It as nodePin, J as VISIT_MERGE_GAP_MS, Jt as unknown, K as TimelapseRuleSchema, Kt as record, L as RetrainStatusSchema, Lt as sleep$1, M as NcSystemEventKindSchema, Mt as DeviceType, N as NcTaxonomySchema, Nt as createEvent, O as NcScheduleSchema, Ot as zoneAnalyticsCapability, P as OpsLogEntrySchema, Pt as hydrateSchema, Q as audioMetricsCapability, Rt as _enum, S as NC_TAXONOMY, T as NcRulePatchSchema, Tt as systemEventFilterApplies, U as TIMELAPSE_DENSE_FLOOR_SEC, Ut as number, V as SCENE_DIVERGED, Vt as discriminatedUnion, W as TimelapseRuleInputSchema, Wt as object, X as alarmPanelCapability, Y as addonWidgetsSourceCapability, Yt as EventCategory, Z as assertTimelapseCadences, _ as MediaFileKindEnum, _t as pickClusterStepModels, a as DEFAULT_EVENT_COLOR, b as NC_DEFAULT_SNOOZE_MINUTES, bt as readDeviceStateFrom, c as DETECTION_MACRO_CLASSES, ct as faceGalleryCapability, d as EVENT_KIND_BY_CAP, dt as isDetectionMacroClass, et as buildEventKindDescriptor, f as EVENT_PAD_MS, ft as isScheduleActive, g as MACRO_LABELS, h as LabelAttributionSchema, ht as notificationRulesCapability, i as COCO_TO_MACRO, it as deriveRecordingMode, j as NcSnoozeSuppressedSchema, jt as CamProfileSchema, k as NcSnoozeInputSchema, kt as errMsg, lt as failureContributionCapability, m as FailureCounters, mt as kebabToCamel, n as BaseDevice, nt as customAction, ot as encodeVectorBase64, p as FULL_IMAGE_BBOX, pt as isSourceCap, q as TrackSourceSchema, qt as string, r as CLUSTER_MODEL_SCOPED_STEPS, rt as defineCustomActions, st as evaluateSensorEdge, t as AUDIO_MACRO_LABELS, tt as cosineSimilarity$1, u as DeclaredDevices, v as NC_ALARM_SYSTEM_EVENT_KINDS, vt as pipelineAnalyticsCapability, w as NcRuleInputSchema, wt as subKindsOf, xt as readTimelapseGeneratedAt, y as NC_CONDITION_CATALOG, yt as plateGalleryCapability, z as SCENE_DEFAULT_ANCHOR_THRESHOLD, zt as array } from "../dist-
|
|
1
|
+
import { $ as audioModeOf, A as NcSnoozeSchema, At as BaseAddon, B as SCENE_DEFAULT_UNCOVERED_POLICY, Bt as boolean, C as NcConditionDescriptorSchema, Ct as sceneMonitorCapability, D as NcRuleTargetSchema, Dt as videoclipsCapability, E as NcRuleSchema, Et as vectorDimFromBase64, Ft as isDeviceScopedCap, G as TimelapseRulePatchSchema, Gt as partialRecord, H as SceneMonitorSchema, Ht as literal, I as RECORDING_EXPORT_MAX_READ_BYTES, It as nodePin, J as VISIT_MERGE_GAP_MS, Jt as unknown, K as TimelapseRuleSchema, Kt as record, L as RetrainStatusSchema, Lt as sleep$1, M as NcSystemEventKindSchema, Mt as DeviceType, N as NcTaxonomySchema, Nt as createEvent, O as NcScheduleSchema, Ot as zoneAnalyticsCapability, P as OpsLogEntrySchema, Pt as hydrateSchema, Q as audioMetricsCapability, Rt as _enum, S as NC_TAXONOMY, T as NcRulePatchSchema, Tt as systemEventFilterApplies, U as TIMELAPSE_DENSE_FLOOR_SEC, Ut as number, V as SCENE_DIVERGED, Vt as discriminatedUnion, W as TimelapseRuleInputSchema, Wt as object, X as alarmPanelCapability, Y as addonWidgetsSourceCapability, Yt as EventCategory, Z as assertTimelapseCadences, _ as MediaFileKindEnum, _t as pickClusterStepModels, a as DEFAULT_EVENT_COLOR, b as NC_DEFAULT_SNOOZE_MINUTES, bt as readDeviceStateFrom, c as DETECTION_MACRO_CLASSES, ct as faceGalleryCapability, d as EVENT_KIND_BY_CAP, dt as isDetectionMacroClass, et as buildEventKindDescriptor, f as EVENT_PAD_MS, ft as isScheduleActive, g as MACRO_LABELS, h as LabelAttributionSchema, ht as notificationRulesCapability, i as COCO_TO_MACRO, it as deriveRecordingMode, j as NcSnoozeSuppressedSchema, jt as CamProfileSchema, k as NcSnoozeInputSchema, kt as errMsg, lt as failureContributionCapability, m as FailureCounters, mt as kebabToCamel, n as BaseDevice, nt as customAction, ot as encodeVectorBase64, p as FULL_IMAGE_BBOX, pt as isSourceCap, q as TrackSourceSchema, qt as string, r as CLUSTER_MODEL_SCOPED_STEPS, rt as defineCustomActions, st as evaluateSensorEdge, t as AUDIO_MACRO_LABELS, tt as cosineSimilarity$1, u as DeclaredDevices, v as NC_ALARM_SYSTEM_EVENT_KINDS, vt as pipelineAnalyticsCapability, w as NcRuleInputSchema, wt as subKindsOf, xt as readTimelapseGeneratedAt, y as NC_CONDITION_CATALOG, yt as plateGalleryCapability, z as SCENE_DEFAULT_ANCHOR_THRESHOLD, zt as array } from "../dist-B1cFmGC0.mjs";
|
|
2
2
|
import { t as __exportAll } from "../embedding-encoder/index.mjs";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import { promises } from "node:fs";
|
|
@@ -45265,6 +45265,48 @@ async function copyFaceCropIfTrackHasNoThumbnail(store, input) {
|
|
|
45265
45265
|
return true;
|
|
45266
45266
|
}
|
|
45267
45267
|
//#endregion
|
|
45268
|
+
//#region src/pipeline-analytics/detail-refusal.ts
|
|
45269
|
+
/**
|
|
45270
|
+
* Recognises the runner's TYPED `not-attached` refusal from a
|
|
45271
|
+
* `pipelineRunner.runDetailSubtree` call.
|
|
45272
|
+
*
|
|
45273
|
+
* The refusal crosses the wire as an ERROR whose message carries a marker,
|
|
45274
|
+
* not as a result field: the cap output schema
|
|
45275
|
+
* (`@camstack/types` `pipeline-runner.cap.ts` → `z.object({ details
|
|
45276
|
+
* }).nullable()`) is parsed on the hub route and Zod strips unknown keys, so a
|
|
45277
|
+
* refusal field cannot survive without a types + codegen + server-train
|
|
45278
|
+
* change. Error messages DO survive the route (tRPC carries `error.message`;
|
|
45279
|
+
* see `cap-route-error-formatter.ts`).
|
|
45280
|
+
*
|
|
45281
|
+
* The marker constant is a TWIN of
|
|
45282
|
+
* `addon-pipeline/src/pipeline-runner/detail-park.ts`
|
|
45283
|
+
* `DETAIL_NOT_ATTACHED_MARKER` — addons never import each other (`ctx.api` is
|
|
45284
|
+
* the only cross-addon layer), so the value is duplicated here the same way
|
|
45285
|
+
* `composeDetailSteps` mirrors the pipeline catalog's chain. Keep the two
|
|
45286
|
+
* identical.
|
|
45287
|
+
*
|
|
45288
|
+
* Why the dispatcher cares: this refusal is about the camera's SESSION state
|
|
45289
|
+
* (the on-motion session closed and the runner's detail park grace has
|
|
45290
|
+
* lapsed), not about one frame — so the full-frame and crop fallback rungs are
|
|
45291
|
+
* structurally doomed and must be skipped, feeding the scheduler's bounded
|
|
45292
|
+
* give-up directly.
|
|
45293
|
+
*/
|
|
45294
|
+
var DETAIL_NOT_ATTACHED_MARKER = "runDetailSubtree-refused:not-attached";
|
|
45295
|
+
/** Best-effort message extraction across transport error shapes. */
|
|
45296
|
+
function messageOf(err) {
|
|
45297
|
+
if (err instanceof Error) return err.message;
|
|
45298
|
+
if (typeof err === "string") return err;
|
|
45299
|
+
if (typeof err === "object" && err !== null) {
|
|
45300
|
+
const message = Reflect.get(err, "message");
|
|
45301
|
+
if (typeof message === "string") return message;
|
|
45302
|
+
}
|
|
45303
|
+
return "";
|
|
45304
|
+
}
|
|
45305
|
+
/** Did this `runDetailSubtree` error carry the runner's not-attached marker? */
|
|
45306
|
+
function isDetailNotAttachedRefusal(err) {
|
|
45307
|
+
return messageOf(err).includes(DETAIL_NOT_ATTACHED_MARKER);
|
|
45308
|
+
}
|
|
45309
|
+
//#endregion
|
|
45268
45310
|
//#region src/pipeline-analytics/detail-scheduler.ts
|
|
45269
45311
|
/** Default backoff/period when a step's cadence omits `minIntervalMs`. */
|
|
45270
45312
|
var DEFAULT_MIN_INTERVAL_MS = 1e3;
|
|
@@ -45645,6 +45687,14 @@ var TrackDetailDispatcher = class {
|
|
|
45645
45687
|
* On D9/D18: the payload that crosses in rung 2 is a COMPRESSED JPEG fetched on
|
|
45646
45688
|
* demand, per TRACK per dispatch (≤2 in flight per device, ~1 Hz) and only after
|
|
45647
45689
|
* rung 1 missed — never a frame-rate stream, and never raw pixels.
|
|
45690
|
+
*
|
|
45691
|
+
* ONE outcome stops the ladder cold: the runner's typed `not-attached`
|
|
45692
|
+
* refusal (`detail-refusal.ts`). It names the camera's SESSION state, not
|
|
45693
|
+
* this frame — the session closed and the runner's detail park grace has
|
|
45694
|
+
* lapsed — so the two remaining rungs are structurally doomed (the retained
|
|
45695
|
+
* store is purged with the session; `captureCrop` is native-strict against
|
|
45696
|
+
* the same missing lease). Walking them anyway is what burned two extra
|
|
45697
|
+
* cross-node RPCs per refusal, ~600–900 times an hour fleet-wide.
|
|
45648
45698
|
*/
|
|
45649
45699
|
async runOnce(deviceId, dev, req, frame) {
|
|
45650
45700
|
const parent = {
|
|
@@ -45661,6 +45711,10 @@ var TrackDetailDispatcher = class {
|
|
|
45661
45711
|
}, frame.nodeId);
|
|
45662
45712
|
if (primary !== null) return primary.details;
|
|
45663
45713
|
} catch (err) {
|
|
45714
|
+
if (isDetailNotAttachedRefusal(err)) {
|
|
45715
|
+
this.warnNotAttachedThrottled(deviceId, dev, req);
|
|
45716
|
+
return null;
|
|
45717
|
+
}
|
|
45664
45718
|
this.deps.logger.debug("detail primary call failed — trying frame fallback", {
|
|
45665
45719
|
tags: { deviceId },
|
|
45666
45720
|
meta: {
|
|
@@ -45693,6 +45747,10 @@ var TrackDetailDispatcher = class {
|
|
|
45693
45747
|
if (derived !== null) return derived.details;
|
|
45694
45748
|
}
|
|
45695
45749
|
} catch (err) {
|
|
45750
|
+
if (isDetailNotAttachedRefusal(err)) {
|
|
45751
|
+
this.warnNotAttachedThrottled(deviceId, dev, req);
|
|
45752
|
+
return null;
|
|
45753
|
+
}
|
|
45696
45754
|
this.deps.logger.debug("detail full-frame fallback call failed", {
|
|
45697
45755
|
tags: { deviceId },
|
|
45698
45756
|
meta: {
|
|
@@ -45714,6 +45772,10 @@ var TrackDetailDispatcher = class {
|
|
|
45714
45772
|
if (retry !== null) return retry.details;
|
|
45715
45773
|
}
|
|
45716
45774
|
} catch (err) {
|
|
45775
|
+
if (isDetailNotAttachedRefusal(err)) {
|
|
45776
|
+
this.warnNotAttachedThrottled(deviceId, dev, req);
|
|
45777
|
+
return null;
|
|
45778
|
+
}
|
|
45717
45779
|
this.deps.logger.debug("detail crop-fallback call failed", {
|
|
45718
45780
|
tags: { deviceId },
|
|
45719
45781
|
meta: {
|
|
@@ -45726,6 +45788,26 @@ var TrackDetailDispatcher = class {
|
|
|
45726
45788
|
this.warnFailThrottled(deviceId, dev, req);
|
|
45727
45789
|
return null;
|
|
45728
45790
|
}
|
|
45791
|
+
/**
|
|
45792
|
+
* The typed refusal is EXPECTED for a track that outlives the runner's
|
|
45793
|
+
* detail park grace (a closing track's last dispatches), so it logs its own
|
|
45794
|
+
* line — the reason is knowable, unlike the every-rung-missed warn — and
|
|
45795
|
+
* shares the per-device throttle. Never silent: this branch drops the
|
|
45796
|
+
* track's enrichment for good once the give-up bound is reached.
|
|
45797
|
+
*/
|
|
45798
|
+
warnNotAttachedThrottled(deviceId, dev, req) {
|
|
45799
|
+
const now = Date.now();
|
|
45800
|
+
if (now - dev.lastFailWarnAt < FAIL_WARN_THROTTLE_MS) return;
|
|
45801
|
+
dev.lastFailWarnAt = now;
|
|
45802
|
+
this.deps.logger.warn("detail dispatch refused: camera not attached (park grace lapsed) — skipping fallback rungs", {
|
|
45803
|
+
tags: { deviceId },
|
|
45804
|
+
meta: {
|
|
45805
|
+
trackId: req.trackId,
|
|
45806
|
+
stepId: req.stepId,
|
|
45807
|
+
reason: req.reason
|
|
45808
|
+
}
|
|
45809
|
+
});
|
|
45810
|
+
}
|
|
45729
45811
|
warnFailThrottled(deviceId, dev, req) {
|
|
45730
45812
|
const now = Date.now();
|
|
45731
45813
|
if (now - dev.lastFailWarnAt < FAIL_WARN_THROTTLE_MS) return;
|
|
@@ -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-CSd331cv.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.175",
|
|
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",
|