@camstack/addon-pipeline 1.2.174 → 1.2.176
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/detection-pipeline/index.js +1 -1
- package/dist/detection-pipeline/index.mjs +1 -1
- package/dist/pipeline-runner/index.js +100 -5
- package/dist/pipeline-runner/index.mjs +100 -5
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BsCmUhCX.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-B7kq7iM6.mjs} +3 -3
- package/dist/stream-broker/{hostInit-BDQHgg8L.mjs → hostInit-sjIj64gI.mjs} +3 -3
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/package.json +1 -1
|
@@ -1135,7 +1135,7 @@ var PoolWorker = class {
|
|
|
1135
1135
|
timeoutMs
|
|
1136
1136
|
}
|
|
1137
1137
|
});
|
|
1138
|
-
reject(/* @__PURE__ */ new Error(`PoolWorker[${this.opts.workerLabel}]: inference request ${reqId} timed out after ${timeoutMs}ms (worker alive, no reply)`));
|
|
1138
|
+
reject(/* @__PURE__ */ new Error(`PoolWorker[${this.opts.workerLabel}]: inference request ${reqId} timed out after ${timeoutMs}ms on ${this.opts.poolRuntime}:${this.opts.device ?? "default"} (worker alive, no reply)`));
|
|
1139
1139
|
}
|
|
1140
1140
|
}, timeoutMs);
|
|
1141
1141
|
timer.unref?.();
|
|
@@ -1128,7 +1128,7 @@ var PoolWorker = class {
|
|
|
1128
1128
|
timeoutMs
|
|
1129
1129
|
}
|
|
1130
1130
|
});
|
|
1131
|
-
reject(/* @__PURE__ */ new Error(`PoolWorker[${this.opts.workerLabel}]: inference request ${reqId} timed out after ${timeoutMs}ms (worker alive, no reply)`));
|
|
1131
|
+
reject(/* @__PURE__ */ new Error(`PoolWorker[${this.opts.workerLabel}]: inference request ${reqId} timed out after ${timeoutMs}ms on ${this.opts.poolRuntime}:${this.opts.device ?? "default"} (worker alive, no reply)`));
|
|
1132
1132
|
}
|
|
1133
1133
|
}, timeoutMs);
|
|
1134
1134
|
timer.unref?.();
|
|
@@ -2411,7 +2411,38 @@ var CropConventionSource = class {
|
|
|
2411
2411
|
}
|
|
2412
2412
|
};
|
|
2413
2413
|
//#endregion
|
|
2414
|
+
//#region src/pipeline-runner/detail-park.ts
|
|
2415
|
+
/**
|
|
2416
|
+
* How long a soft-detached camera's detail step tree stays resolvable.
|
|
2417
|
+
* Aligned to the post-analysis durable-track TTL (30 s since `lastSeen`) —
|
|
2418
|
+
* the dispatcher stops asking once the track closes, so a longer park serves
|
|
2419
|
+
* nobody and a shorter one re-opens the refusal window this exists to close.
|
|
2420
|
+
*/
|
|
2421
|
+
var DETAIL_PARK_GRACE_MS = 3e4;
|
|
2422
|
+
/**
|
|
2423
|
+
* The wire marker for the typed not-attached refusal. Twin constant in
|
|
2424
|
+
* `addon-post-analysis/src/pipeline-analytics/detail-refusal.ts` — keep in sync.
|
|
2425
|
+
*/
|
|
2426
|
+
var DETAIL_NOT_ATTACHED_MARKER = "runDetailSubtree-refused:not-attached";
|
|
2427
|
+
/** Is this park still within its grace window at `nowMs`? */
|
|
2428
|
+
function isParkedDetailFresh(parked, nowMs) {
|
|
2429
|
+
return nowMs - parked.parkedAt <= DETAIL_PARK_GRACE_MS;
|
|
2430
|
+
}
|
|
2431
|
+
/**
|
|
2432
|
+
* The error the cap method throws for a not-attached dispatch. The dispatcher
|
|
2433
|
+
* recognises the marker and goes straight to its bounded give-up instead of
|
|
2434
|
+
* burning the full-frame and crop fallback RPCs, both structurally doomed by
|
|
2435
|
+
* the same missing session.
|
|
2436
|
+
*/
|
|
2437
|
+
function buildDetailNotAttachedError(deviceId) {
|
|
2438
|
+
return /* @__PURE__ */ new Error(`${DETAIL_NOT_ATTACHED_MARKER} — camera ${deviceId} is not attached and no detail state is parked within the grace window`);
|
|
2439
|
+
}
|
|
2440
|
+
//#endregion
|
|
2414
2441
|
//#region src/pipeline-runner/detail-subtree.ts
|
|
2442
|
+
/** Did the subtree run refuse because the camera is not attached (park lapsed)? */
|
|
2443
|
+
function isDetailNotAttachedRefusal(outcome) {
|
|
2444
|
+
return "refusal" in outcome;
|
|
2445
|
+
}
|
|
2415
2446
|
/** Did the native-lease fetch report a miss (rather than return pixels)? */
|
|
2416
2447
|
function isNativeCropMiss(fetch) {
|
|
2417
2448
|
return "miss" in fetch;
|
|
@@ -2674,7 +2705,7 @@ async function runDetailSubtree(deps, input) {
|
|
|
2674
2705
|
...input.steps ? { requestedSteps: [...input.steps] } : {}
|
|
2675
2706
|
}
|
|
2676
2707
|
});
|
|
2677
|
-
return
|
|
2708
|
+
return { refusal: "not-attached" };
|
|
2678
2709
|
}
|
|
2679
2710
|
if (matched.length === 0) {
|
|
2680
2711
|
deps.logger.warn("runDetailSubtree: no matching detail step is enabled for this parent class", {
|
|
@@ -5446,6 +5477,14 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
5446
5477
|
* camera, each self-expiring after {@link DETECTION_KEEPWARM_MS}.
|
|
5447
5478
|
*/
|
|
5448
5479
|
warmDetachedDetection = /* @__PURE__ */ new Map();
|
|
5480
|
+
/**
|
|
5481
|
+
* Detail step state parked across a SOFT detach, keyed by deviceId — see
|
|
5482
|
+
* `detail-park.ts` for the fault this closes. Bounded by construction: at
|
|
5483
|
+
* most one entry per camera, each self-expiring after
|
|
5484
|
+
* {@link DETAIL_PARK_GRACE_MS}, dropped early on re-attach / hard detach /
|
|
5485
|
+
* shutdown.
|
|
5486
|
+
*/
|
|
5487
|
+
parkedDetail = /* @__PURE__ */ new Map();
|
|
5449
5488
|
nodeId = "unknown";
|
|
5450
5489
|
metricsSnapshotTimer = null;
|
|
5451
5490
|
unsubMotionEvents = null;
|
|
@@ -5757,6 +5796,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
5757
5796
|
attachment.detectionUnsubscribe?.();
|
|
5758
5797
|
}
|
|
5759
5798
|
for (const deviceId of [...this.warmDetachedDetection.keys()]) this.dropWarmDetectionDecode(deviceId, "shutdown");
|
|
5799
|
+
for (const deviceId of [...this.parkedDetail.keys()]) this.dropParkedDetail(deviceId);
|
|
5760
5800
|
this.attached.clear();
|
|
5761
5801
|
this.lastMotionFrameAt.clear();
|
|
5762
5802
|
this.nativeCropRegistry.clear();
|
|
@@ -6468,6 +6508,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
6468
6508
|
detailSteps: deriveDetailSteps(config.steps)
|
|
6469
6509
|
};
|
|
6470
6510
|
this.attached.set(config.deviceId, attachment);
|
|
6511
|
+
this.dropParkedDetail(config.deviceId);
|
|
6471
6512
|
runner.registerCamera(config.deviceId, {
|
|
6472
6513
|
detectionMode: config.detectionMode,
|
|
6473
6514
|
fps: config.detectionFps,
|
|
@@ -6760,7 +6801,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
6760
6801
|
*/
|
|
6761
6802
|
async runDetailSubtree(input) {
|
|
6762
6803
|
const convention = await this.cropConvention.refresh(this.ctxIfReady?.api);
|
|
6763
|
-
|
|
6804
|
+
const outcome = await runDetailSubtree({
|
|
6764
6805
|
resolveChildSteps: (deviceId, parentClassName, filter) => this.resolveDetailChildSteps(deviceId, parentClassName, filter),
|
|
6765
6806
|
getNativeCrop: (deviceId, handle, paddedBbox) => this.getNativeCropForDetail(deviceId, handle, paddedBbox),
|
|
6766
6807
|
runPipeline: (steps, imageJpeg, deviceId, deviceKey, nativeCropRef) => this.runDetailPipeline(steps, imageJpeg, deviceId, deviceKey, nativeCropRef),
|
|
@@ -6768,6 +6809,8 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
6768
6809
|
resolveCropConvention: () => convention,
|
|
6769
6810
|
logger: this.detailSubtreeLogger()
|
|
6770
6811
|
}, input);
|
|
6812
|
+
if (outcome !== null && isDetailNotAttachedRefusal(outcome)) throw buildDetailNotAttachedError(input.deviceId);
|
|
6813
|
+
return outcome;
|
|
6771
6814
|
}
|
|
6772
6815
|
/**
|
|
6773
6816
|
* Stateless single-step execution — no attach, no handle, no device
|
|
@@ -6939,7 +6982,12 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
6939
6982
|
*/
|
|
6940
6983
|
resolveDetailChildSteps(deviceId, parentClassName, filter) {
|
|
6941
6984
|
const attachment = this.attached.get(deviceId);
|
|
6942
|
-
if (!attachment)
|
|
6985
|
+
if (!attachment) {
|
|
6986
|
+
const parked = this.freshParkedDetail(deviceId);
|
|
6987
|
+
if (!parked) return null;
|
|
6988
|
+
if (!parked.steps) return [];
|
|
6989
|
+
return findMatchingDetailSteps(parked.steps, parentClassName, tryGetStepDefinition, filter);
|
|
6990
|
+
}
|
|
6943
6991
|
const steps = attachment.config.steps;
|
|
6944
6992
|
if (!steps) return [];
|
|
6945
6993
|
return findMatchingDetailSteps(steps, parentClassName, tryGetStepDefinition, filter);
|
|
@@ -6980,7 +7028,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
6980
7028
|
async runDetailPipeline(steps, imageJpeg, deviceId, stepDeviceKey, nativeCropRef) {
|
|
6981
7029
|
const api = this.ctxIfReady?.api;
|
|
6982
7030
|
if (!api) return null;
|
|
6983
|
-
const detailDeviceKey = stepDeviceKey ?? this.attached.get(deviceId)?.config?.deviceKey;
|
|
7031
|
+
const detailDeviceKey = stepDeviceKey ?? this.attached.get(deviceId)?.config?.deviceKey ?? this.freshParkedDetail(deviceId)?.deviceKey;
|
|
6984
7032
|
try {
|
|
6985
7033
|
return await api.pipelineExecutor.runPipeline.mutate({
|
|
6986
7034
|
steps: [...steps],
|
|
@@ -7058,6 +7106,51 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
7058
7106
|
* is a hard one, because in each of those cases the worker is either wrong or
|
|
7059
7107
|
* already gone.
|
|
7060
7108
|
*/
|
|
7109
|
+
/**
|
|
7110
|
+
* Park the detaching camera's detail-relevant config slice for the grace
|
|
7111
|
+
* window, replacing any previous park (older state would resolve a stale
|
|
7112
|
+
* step tree). The expiry timer mirrors {@link parkWarmDetectionDecode};
|
|
7113
|
+
* {@link freshParkedDetail} also expires lazily so a fired-late timer can
|
|
7114
|
+
* never extend the window.
|
|
7115
|
+
*/
|
|
7116
|
+
parkDetailState(deviceId, config) {
|
|
7117
|
+
this.dropParkedDetail(deviceId);
|
|
7118
|
+
const state = {
|
|
7119
|
+
steps: config.steps,
|
|
7120
|
+
deviceKey: config.deviceKey,
|
|
7121
|
+
parkedAt: Date.now()
|
|
7122
|
+
};
|
|
7123
|
+
const timer = setTimeout(() => {
|
|
7124
|
+
this.parkedDetail.delete(deviceId);
|
|
7125
|
+
}, DETAIL_PARK_GRACE_MS);
|
|
7126
|
+
timer.unref?.();
|
|
7127
|
+
this.parkedDetail.set(deviceId, {
|
|
7128
|
+
state,
|
|
7129
|
+
timer
|
|
7130
|
+
});
|
|
7131
|
+
}
|
|
7132
|
+
/** Drop a park now (hard detach, re-attach, shutdown) — timer included. */
|
|
7133
|
+
dropParkedDetail(deviceId) {
|
|
7134
|
+
const parked = this.parkedDetail.get(deviceId);
|
|
7135
|
+
if (!parked) return;
|
|
7136
|
+
clearTimeout(parked.timer);
|
|
7137
|
+
this.parkedDetail.delete(deviceId);
|
|
7138
|
+
}
|
|
7139
|
+
/**
|
|
7140
|
+
* The parked detail state for `deviceId`, or `null` once the grace has
|
|
7141
|
+
* lapsed. Expiry is enforced HERE, not only by the timer: the window must be
|
|
7142
|
+
* bounded by the clock, never by timer-delivery luck — an unbounded park
|
|
7143
|
+
* would be the lease-TTL inflation D73 rejected, by another name.
|
|
7144
|
+
*/
|
|
7145
|
+
freshParkedDetail(deviceId) {
|
|
7146
|
+
const parked = this.parkedDetail.get(deviceId);
|
|
7147
|
+
if (!parked) return null;
|
|
7148
|
+
if (!isParkedDetailFresh(parked.state, Date.now())) {
|
|
7149
|
+
this.dropParkedDetail(deviceId);
|
|
7150
|
+
return null;
|
|
7151
|
+
}
|
|
7152
|
+
return parked.state;
|
|
7153
|
+
}
|
|
7061
7154
|
detachInternal(deviceId, keepDecodeWarm = false) {
|
|
7062
7155
|
const attachment = this.attached.get(deviceId);
|
|
7063
7156
|
if (!attachment) return;
|
|
@@ -7069,6 +7162,8 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
7069
7162
|
attachment.motionUnsubscribe?.();
|
|
7070
7163
|
if (keepDecodeWarm && attachment.detectionUnsubscribe !== null) this.parkWarmDetectionDecode(deviceId, attachment.config, attachment.detectionUnsubscribe);
|
|
7071
7164
|
else attachment.detectionUnsubscribe?.();
|
|
7165
|
+
if (keepDecodeWarm) this.parkDetailState(deviceId, attachment.config);
|
|
7166
|
+
else this.dropParkedDetail(deviceId);
|
|
7072
7167
|
this.lastMotionFrameAt.delete(deviceId);
|
|
7073
7168
|
this.lastDecodeUnexpectedEndAt.delete(deviceId);
|
|
7074
7169
|
this.packageGovernor.forget(deviceId);
|
|
@@ -7808,7 +7903,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
7808
7903
|
error: msg,
|
|
7809
7904
|
nodeId: this.nodeId,
|
|
7810
7905
|
steps: dispatchSteps.map((s) => s.addonId).join(","),
|
|
7811
|
-
|
|
7906
|
+
deviceKey: camConfig?.deviceKey ?? null
|
|
7812
7907
|
} });
|
|
7813
7908
|
return null;
|
|
7814
7909
|
}
|
|
@@ -2404,7 +2404,38 @@ var CropConventionSource = class {
|
|
|
2404
2404
|
}
|
|
2405
2405
|
};
|
|
2406
2406
|
//#endregion
|
|
2407
|
+
//#region src/pipeline-runner/detail-park.ts
|
|
2408
|
+
/**
|
|
2409
|
+
* How long a soft-detached camera's detail step tree stays resolvable.
|
|
2410
|
+
* Aligned to the post-analysis durable-track TTL (30 s since `lastSeen`) —
|
|
2411
|
+
* the dispatcher stops asking once the track closes, so a longer park serves
|
|
2412
|
+
* nobody and a shorter one re-opens the refusal window this exists to close.
|
|
2413
|
+
*/
|
|
2414
|
+
var DETAIL_PARK_GRACE_MS = 3e4;
|
|
2415
|
+
/**
|
|
2416
|
+
* The wire marker for the typed not-attached refusal. Twin constant in
|
|
2417
|
+
* `addon-post-analysis/src/pipeline-analytics/detail-refusal.ts` — keep in sync.
|
|
2418
|
+
*/
|
|
2419
|
+
var DETAIL_NOT_ATTACHED_MARKER = "runDetailSubtree-refused:not-attached";
|
|
2420
|
+
/** Is this park still within its grace window at `nowMs`? */
|
|
2421
|
+
function isParkedDetailFresh(parked, nowMs) {
|
|
2422
|
+
return nowMs - parked.parkedAt <= DETAIL_PARK_GRACE_MS;
|
|
2423
|
+
}
|
|
2424
|
+
/**
|
|
2425
|
+
* The error the cap method throws for a not-attached dispatch. The dispatcher
|
|
2426
|
+
* recognises the marker and goes straight to its bounded give-up instead of
|
|
2427
|
+
* burning the full-frame and crop fallback RPCs, both structurally doomed by
|
|
2428
|
+
* the same missing session.
|
|
2429
|
+
*/
|
|
2430
|
+
function buildDetailNotAttachedError(deviceId) {
|
|
2431
|
+
return /* @__PURE__ */ new Error(`${DETAIL_NOT_ATTACHED_MARKER} — camera ${deviceId} is not attached and no detail state is parked within the grace window`);
|
|
2432
|
+
}
|
|
2433
|
+
//#endregion
|
|
2407
2434
|
//#region src/pipeline-runner/detail-subtree.ts
|
|
2435
|
+
/** Did the subtree run refuse because the camera is not attached (park lapsed)? */
|
|
2436
|
+
function isDetailNotAttachedRefusal(outcome) {
|
|
2437
|
+
return "refusal" in outcome;
|
|
2438
|
+
}
|
|
2408
2439
|
/** Did the native-lease fetch report a miss (rather than return pixels)? */
|
|
2409
2440
|
function isNativeCropMiss(fetch) {
|
|
2410
2441
|
return "miss" in fetch;
|
|
@@ -2667,7 +2698,7 @@ async function runDetailSubtree(deps, input) {
|
|
|
2667
2698
|
...input.steps ? { requestedSteps: [...input.steps] } : {}
|
|
2668
2699
|
}
|
|
2669
2700
|
});
|
|
2670
|
-
return
|
|
2701
|
+
return { refusal: "not-attached" };
|
|
2671
2702
|
}
|
|
2672
2703
|
if (matched.length === 0) {
|
|
2673
2704
|
deps.logger.warn("runDetailSubtree: no matching detail step is enabled for this parent class", {
|
|
@@ -5439,6 +5470,14 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
5439
5470
|
* camera, each self-expiring after {@link DETECTION_KEEPWARM_MS}.
|
|
5440
5471
|
*/
|
|
5441
5472
|
warmDetachedDetection = /* @__PURE__ */ new Map();
|
|
5473
|
+
/**
|
|
5474
|
+
* Detail step state parked across a SOFT detach, keyed by deviceId — see
|
|
5475
|
+
* `detail-park.ts` for the fault this closes. Bounded by construction: at
|
|
5476
|
+
* most one entry per camera, each self-expiring after
|
|
5477
|
+
* {@link DETAIL_PARK_GRACE_MS}, dropped early on re-attach / hard detach /
|
|
5478
|
+
* shutdown.
|
|
5479
|
+
*/
|
|
5480
|
+
parkedDetail = /* @__PURE__ */ new Map();
|
|
5442
5481
|
nodeId = "unknown";
|
|
5443
5482
|
metricsSnapshotTimer = null;
|
|
5444
5483
|
unsubMotionEvents = null;
|
|
@@ -5750,6 +5789,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
5750
5789
|
attachment.detectionUnsubscribe?.();
|
|
5751
5790
|
}
|
|
5752
5791
|
for (const deviceId of [...this.warmDetachedDetection.keys()]) this.dropWarmDetectionDecode(deviceId, "shutdown");
|
|
5792
|
+
for (const deviceId of [...this.parkedDetail.keys()]) this.dropParkedDetail(deviceId);
|
|
5753
5793
|
this.attached.clear();
|
|
5754
5794
|
this.lastMotionFrameAt.clear();
|
|
5755
5795
|
this.nativeCropRegistry.clear();
|
|
@@ -6461,6 +6501,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
6461
6501
|
detailSteps: deriveDetailSteps(config.steps)
|
|
6462
6502
|
};
|
|
6463
6503
|
this.attached.set(config.deviceId, attachment);
|
|
6504
|
+
this.dropParkedDetail(config.deviceId);
|
|
6464
6505
|
runner.registerCamera(config.deviceId, {
|
|
6465
6506
|
detectionMode: config.detectionMode,
|
|
6466
6507
|
fps: config.detectionFps,
|
|
@@ -6753,7 +6794,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
6753
6794
|
*/
|
|
6754
6795
|
async runDetailSubtree(input) {
|
|
6755
6796
|
const convention = await this.cropConvention.refresh(this.ctxIfReady?.api);
|
|
6756
|
-
|
|
6797
|
+
const outcome = await runDetailSubtree({
|
|
6757
6798
|
resolveChildSteps: (deviceId, parentClassName, filter) => this.resolveDetailChildSteps(deviceId, parentClassName, filter),
|
|
6758
6799
|
getNativeCrop: (deviceId, handle, paddedBbox) => this.getNativeCropForDetail(deviceId, handle, paddedBbox),
|
|
6759
6800
|
runPipeline: (steps, imageJpeg, deviceId, deviceKey, nativeCropRef) => this.runDetailPipeline(steps, imageJpeg, deviceId, deviceKey, nativeCropRef),
|
|
@@ -6761,6 +6802,8 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
6761
6802
|
resolveCropConvention: () => convention,
|
|
6762
6803
|
logger: this.detailSubtreeLogger()
|
|
6763
6804
|
}, input);
|
|
6805
|
+
if (outcome !== null && isDetailNotAttachedRefusal(outcome)) throw buildDetailNotAttachedError(input.deviceId);
|
|
6806
|
+
return outcome;
|
|
6764
6807
|
}
|
|
6765
6808
|
/**
|
|
6766
6809
|
* Stateless single-step execution — no attach, no handle, no device
|
|
@@ -6932,7 +6975,12 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
6932
6975
|
*/
|
|
6933
6976
|
resolveDetailChildSteps(deviceId, parentClassName, filter) {
|
|
6934
6977
|
const attachment = this.attached.get(deviceId);
|
|
6935
|
-
if (!attachment)
|
|
6978
|
+
if (!attachment) {
|
|
6979
|
+
const parked = this.freshParkedDetail(deviceId);
|
|
6980
|
+
if (!parked) return null;
|
|
6981
|
+
if (!parked.steps) return [];
|
|
6982
|
+
return findMatchingDetailSteps(parked.steps, parentClassName, tryGetStepDefinition, filter);
|
|
6983
|
+
}
|
|
6936
6984
|
const steps = attachment.config.steps;
|
|
6937
6985
|
if (!steps) return [];
|
|
6938
6986
|
return findMatchingDetailSteps(steps, parentClassName, tryGetStepDefinition, filter);
|
|
@@ -6973,7 +7021,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
6973
7021
|
async runDetailPipeline(steps, imageJpeg, deviceId, stepDeviceKey, nativeCropRef) {
|
|
6974
7022
|
const api = this.ctxIfReady?.api;
|
|
6975
7023
|
if (!api) return null;
|
|
6976
|
-
const detailDeviceKey = stepDeviceKey ?? this.attached.get(deviceId)?.config?.deviceKey;
|
|
7024
|
+
const detailDeviceKey = stepDeviceKey ?? this.attached.get(deviceId)?.config?.deviceKey ?? this.freshParkedDetail(deviceId)?.deviceKey;
|
|
6977
7025
|
try {
|
|
6978
7026
|
return await api.pipelineExecutor.runPipeline.mutate({
|
|
6979
7027
|
steps: [...steps],
|
|
@@ -7051,6 +7099,51 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
7051
7099
|
* is a hard one, because in each of those cases the worker is either wrong or
|
|
7052
7100
|
* already gone.
|
|
7053
7101
|
*/
|
|
7102
|
+
/**
|
|
7103
|
+
* Park the detaching camera's detail-relevant config slice for the grace
|
|
7104
|
+
* window, replacing any previous park (older state would resolve a stale
|
|
7105
|
+
* step tree). The expiry timer mirrors {@link parkWarmDetectionDecode};
|
|
7106
|
+
* {@link freshParkedDetail} also expires lazily so a fired-late timer can
|
|
7107
|
+
* never extend the window.
|
|
7108
|
+
*/
|
|
7109
|
+
parkDetailState(deviceId, config) {
|
|
7110
|
+
this.dropParkedDetail(deviceId);
|
|
7111
|
+
const state = {
|
|
7112
|
+
steps: config.steps,
|
|
7113
|
+
deviceKey: config.deviceKey,
|
|
7114
|
+
parkedAt: Date.now()
|
|
7115
|
+
};
|
|
7116
|
+
const timer = setTimeout(() => {
|
|
7117
|
+
this.parkedDetail.delete(deviceId);
|
|
7118
|
+
}, DETAIL_PARK_GRACE_MS);
|
|
7119
|
+
timer.unref?.();
|
|
7120
|
+
this.parkedDetail.set(deviceId, {
|
|
7121
|
+
state,
|
|
7122
|
+
timer
|
|
7123
|
+
});
|
|
7124
|
+
}
|
|
7125
|
+
/** Drop a park now (hard detach, re-attach, shutdown) — timer included. */
|
|
7126
|
+
dropParkedDetail(deviceId) {
|
|
7127
|
+
const parked = this.parkedDetail.get(deviceId);
|
|
7128
|
+
if (!parked) return;
|
|
7129
|
+
clearTimeout(parked.timer);
|
|
7130
|
+
this.parkedDetail.delete(deviceId);
|
|
7131
|
+
}
|
|
7132
|
+
/**
|
|
7133
|
+
* The parked detail state for `deviceId`, or `null` once the grace has
|
|
7134
|
+
* lapsed. Expiry is enforced HERE, not only by the timer: the window must be
|
|
7135
|
+
* bounded by the clock, never by timer-delivery luck — an unbounded park
|
|
7136
|
+
* would be the lease-TTL inflation D73 rejected, by another name.
|
|
7137
|
+
*/
|
|
7138
|
+
freshParkedDetail(deviceId) {
|
|
7139
|
+
const parked = this.parkedDetail.get(deviceId);
|
|
7140
|
+
if (!parked) return null;
|
|
7141
|
+
if (!isParkedDetailFresh(parked.state, Date.now())) {
|
|
7142
|
+
this.dropParkedDetail(deviceId);
|
|
7143
|
+
return null;
|
|
7144
|
+
}
|
|
7145
|
+
return parked.state;
|
|
7146
|
+
}
|
|
7054
7147
|
detachInternal(deviceId, keepDecodeWarm = false) {
|
|
7055
7148
|
const attachment = this.attached.get(deviceId);
|
|
7056
7149
|
if (!attachment) return;
|
|
@@ -7062,6 +7155,8 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
7062
7155
|
attachment.motionUnsubscribe?.();
|
|
7063
7156
|
if (keepDecodeWarm && attachment.detectionUnsubscribe !== null) this.parkWarmDetectionDecode(deviceId, attachment.config, attachment.detectionUnsubscribe);
|
|
7064
7157
|
else attachment.detectionUnsubscribe?.();
|
|
7158
|
+
if (keepDecodeWarm) this.parkDetailState(deviceId, attachment.config);
|
|
7159
|
+
else this.dropParkedDetail(deviceId);
|
|
7065
7160
|
this.lastMotionFrameAt.delete(deviceId);
|
|
7066
7161
|
this.lastDecodeUnexpectedEndAt.delete(deviceId);
|
|
7067
7162
|
this.packageGovernor.forget(deviceId);
|
|
@@ -7801,7 +7896,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
7801
7896
|
error: msg,
|
|
7802
7897
|
nodeId: this.nodeId,
|
|
7803
7898
|
steps: dispatchSteps.map((s) => s.addonId).join(","),
|
|
7804
|
-
|
|
7899
|
+
deviceKey: camConfig?.deviceKey ?? null
|
|
7805
7900
|
} });
|
|
7806
7901
|
return null;
|
|
7807
7902
|
}
|
|
@@ -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.65",
|
|
7
7
|
scope: ["default"],
|
|
8
8
|
loaded: !1,
|
|
9
9
|
from: "addon_stream_broker_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.145",
|
|
22
22
|
scope: ["default"],
|
|
23
23
|
loaded: !1,
|
|
24
24
|
from: "addon_stream_broker_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.111",
|
|
37
37
|
scope: ["default"],
|
|
38
38
|
loaded: !1,
|
|
39
39
|
from: "addon_stream_broker_widgets",
|
|
@@ -36,7 +36,7 @@ async function r() {
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
"@camstack/types": {
|
|
39
|
-
version: "1.2.
|
|
39
|
+
version: "1.2.145",
|
|
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.65",
|
|
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.111",
|
|
85
85
|
scope: "default",
|
|
86
86
|
shareConfig: {
|
|
87
87
|
singleton: !0,
|
|
@@ -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_stream_broker_widgets-
|
|
33
|
+
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-B7kq7iM6.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-pipeline",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.176",
|
|
4
4
|
"description": "Pipeline bundle — runner, detection, motion, audio + stream broker. Multi-entry npm package shipping pipeline addons under a single bundle.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|