@camstack/addon-pipeline 1.2.309 → 1.2.310
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/pipeline-runner/index.js +15 -1
- package/dist/pipeline-runner/index.mjs +15 -1
- package/dist/recorder/index.js +70 -3
- package/dist/recorder/index.mjs +70 -3
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-7H0Oxf23.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DZh9jQi-.mjs} +1 -1
- package/dist/stream-broker/{hostInit-DEY-Dqqo.mjs → hostInit-BJYQvQ3e.mjs} +1 -1
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/package.json +1 -1
|
@@ -5298,6 +5298,19 @@ async function resolveMotionFrameView(registry, ref) {
|
|
|
5298
5298
|
/** The step id (`PipelineStepInput.addonId`) the governor gates. */
|
|
5299
5299
|
var PACKAGE_DETECTION_STEP_ID = "package-detection";
|
|
5300
5300
|
/**
|
|
5301
|
+
* The executor's frame, stamped `packageLooked` when the `package-detection`
|
|
5302
|
+
* root was among the steps actually DISPATCHED for it (the governor let it
|
|
5303
|
+
* through) and the frame was not shed. Post-analysis reads it as "an empty
|
|
5304
|
+
* doormat on this frame is an ABSENCE, not silence" (D687). Never mutates.
|
|
5305
|
+
*/
|
|
5306
|
+
function withPackageLook(result, dispatched) {
|
|
5307
|
+
if (result.shed === true) return result;
|
|
5308
|
+
return dispatched.some((s) => s.addonId === "package-detection" && s.enabled !== false) ? {
|
|
5309
|
+
...result,
|
|
5310
|
+
packageLooked: true
|
|
5311
|
+
} : result;
|
|
5312
|
+
}
|
|
5313
|
+
/**
|
|
5301
5314
|
* Burst: 5 runs, 5s apart — 0s, 5s, 10s, 15s, 20s after the settle edge.
|
|
5302
5315
|
*
|
|
5303
5316
|
* Sized as a SAFETY NET when the operator raises `packageDropDwellSec` above
|
|
@@ -11385,7 +11398,8 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
11385
11398
|
return null;
|
|
11386
11399
|
}
|
|
11387
11400
|
if (result === null) return null;
|
|
11388
|
-
|
|
11401
|
+
const looked = withPackageLook(result, dispatchSteps);
|
|
11402
|
+
return this.recoverSmallSubjects(deviceId, frame, looked, dispatchSteps, camConfig?.deviceKey);
|
|
11389
11403
|
}
|
|
11390
11404
|
/**
|
|
11391
11405
|
* The second detector pass at native resolution — `small-subject-recovery.ts`
|
|
@@ -5290,6 +5290,19 @@ async function resolveMotionFrameView(registry, ref) {
|
|
|
5290
5290
|
/** The step id (`PipelineStepInput.addonId`) the governor gates. */
|
|
5291
5291
|
var PACKAGE_DETECTION_STEP_ID = "package-detection";
|
|
5292
5292
|
/**
|
|
5293
|
+
* The executor's frame, stamped `packageLooked` when the `package-detection`
|
|
5294
|
+
* root was among the steps actually DISPATCHED for it (the governor let it
|
|
5295
|
+
* through) and the frame was not shed. Post-analysis reads it as "an empty
|
|
5296
|
+
* doormat on this frame is an ABSENCE, not silence" (D687). Never mutates.
|
|
5297
|
+
*/
|
|
5298
|
+
function withPackageLook(result, dispatched) {
|
|
5299
|
+
if (result.shed === true) return result;
|
|
5300
|
+
return dispatched.some((s) => s.addonId === "package-detection" && s.enabled !== false) ? {
|
|
5301
|
+
...result,
|
|
5302
|
+
packageLooked: true
|
|
5303
|
+
} : result;
|
|
5304
|
+
}
|
|
5305
|
+
/**
|
|
5293
5306
|
* Burst: 5 runs, 5s apart — 0s, 5s, 10s, 15s, 20s after the settle edge.
|
|
5294
5307
|
*
|
|
5295
5308
|
* Sized as a SAFETY NET when the operator raises `packageDropDwellSec` above
|
|
@@ -11377,7 +11390,8 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
11377
11390
|
return null;
|
|
11378
11391
|
}
|
|
11379
11392
|
if (result === null) return null;
|
|
11380
|
-
|
|
11393
|
+
const looked = withPackageLook(result, dispatchSteps);
|
|
11394
|
+
return this.recoverSmallSubjects(deviceId, frame, looked, dispatchSteps, camConfig?.deviceKey);
|
|
11381
11395
|
}
|
|
11382
11396
|
/**
|
|
11383
11397
|
* The second detector pass at native resolution — `small-subject-recovery.ts`
|
package/dist/recorder/index.js
CHANGED
|
@@ -6777,6 +6777,30 @@ async function patchExport(state, id, patch) {
|
|
|
6777
6777
|
return merged;
|
|
6778
6778
|
});
|
|
6779
6779
|
}
|
|
6780
|
+
/**
|
|
6781
|
+
* Patch a row UNLESS its current state says not to — the check and the write
|
|
6782
|
+
* are ONE serialized step, so a delete that lands between a separate read and
|
|
6783
|
+
* a separate patch can no longer be overwritten (review R5).
|
|
6784
|
+
*/
|
|
6785
|
+
async function patchExportUnless(state, id, patch, refuse) {
|
|
6786
|
+
return serialize(state, id, async () => {
|
|
6787
|
+
const existing = await state.read(id);
|
|
6788
|
+
if (existing === null) return { kind: "missing" };
|
|
6789
|
+
if (refuse(existing)) return {
|
|
6790
|
+
kind: "refused",
|
|
6791
|
+
record: existing
|
|
6792
|
+
};
|
|
6793
|
+
const merged = require_dist.ExportRecordSchema.parse({
|
|
6794
|
+
...existing,
|
|
6795
|
+
...patch
|
|
6796
|
+
});
|
|
6797
|
+
await state.write(id, merged);
|
|
6798
|
+
return {
|
|
6799
|
+
kind: "patched",
|
|
6800
|
+
record: merged
|
|
6801
|
+
};
|
|
6802
|
+
});
|
|
6803
|
+
}
|
|
6780
6804
|
/** Read one export row by id — ONE keyed row read. */
|
|
6781
6805
|
async function getExportRecord(state, id) {
|
|
6782
6806
|
return state.read(id);
|
|
@@ -6996,6 +7020,13 @@ function expectedOutSeconds(rec) {
|
|
|
6996
7020
|
}
|
|
6997
7021
|
return rangeSec / (rec.options.speed ?? 1);
|
|
6998
7022
|
}
|
|
7023
|
+
/**
|
|
7024
|
+
* A row nobody will read: its caller deleted it, it expired, or it already
|
|
7025
|
+
* failed (a cancel finalises as `failed`). The engine renders none of these.
|
|
7026
|
+
*/
|
|
7027
|
+
function isAbandonedExportState(state) {
|
|
7028
|
+
return state === "deleted" || state === "expired" || state === "failed";
|
|
7029
|
+
}
|
|
6999
7030
|
var ExportEngine = class {
|
|
7000
7031
|
deps;
|
|
7001
7032
|
queue = [];
|
|
@@ -7056,16 +7087,37 @@ var ExportEngine = class {
|
|
|
7056
7087
|
async render(id) {
|
|
7057
7088
|
const existing = await getExportRecord(this.deps.state, id);
|
|
7058
7089
|
if (!existing) return;
|
|
7090
|
+
if (isAbandonedExportState(existing.state)) {
|
|
7091
|
+
this.deps.logger.info("export render skipped: the export was abandoned before it ran", {
|
|
7092
|
+
tags: { deviceId: existing.deviceId },
|
|
7093
|
+
meta: {
|
|
7094
|
+
exportId: id,
|
|
7095
|
+
state: existing.state
|
|
7096
|
+
}
|
|
7097
|
+
});
|
|
7098
|
+
return;
|
|
7099
|
+
}
|
|
7059
7100
|
const subject = require_dist.exportSubjectOf(existing);
|
|
7060
7101
|
if (subject.kind === "clip" && subject.source !== ANALYTICS_CLIP_SOURCE) {
|
|
7061
7102
|
await this.fetchClip(id, existing, subject);
|
|
7062
7103
|
return;
|
|
7063
7104
|
}
|
|
7064
|
-
const
|
|
7105
|
+
const claimed = await patchExportUnless(this.deps.state, id, {
|
|
7065
7106
|
state: "rendering",
|
|
7066
7107
|
progressPct: 0
|
|
7067
|
-
});
|
|
7068
|
-
if (
|
|
7108
|
+
}, (current) => isAbandonedExportState(current.state));
|
|
7109
|
+
if (claimed.kind === "missing") return;
|
|
7110
|
+
if (claimed.kind === "refused") {
|
|
7111
|
+
this.deps.logger.info("export render skipped: the export was abandoned before it ran", {
|
|
7112
|
+
tags: { deviceId: claimed.record.deviceId },
|
|
7113
|
+
meta: {
|
|
7114
|
+
exportId: id,
|
|
7115
|
+
state: claimed.record.state
|
|
7116
|
+
}
|
|
7117
|
+
});
|
|
7118
|
+
return;
|
|
7119
|
+
}
|
|
7120
|
+
const rec = claimed.record;
|
|
7069
7121
|
const playlist = await this.deps.resolvePlaylist(rec);
|
|
7070
7122
|
if (!playlist) {
|
|
7071
7123
|
await this.fail(id, "no footage for range");
|
|
@@ -7699,6 +7751,19 @@ var ExportEngine = class {
|
|
|
7699
7751
|
await this.fail(id, `render produced no video frames (${bytes} bytes, < ${EXPORT_MIN_PLAUSIBLE_BYTES})`);
|
|
7700
7752
|
return;
|
|
7701
7753
|
}
|
|
7754
|
+
const current = await getExportRecord(this.deps.state, id);
|
|
7755
|
+
if (current !== null && isAbandonedExportState(current.state)) {
|
|
7756
|
+
await this.deps.removeFile(outPath);
|
|
7757
|
+
this.deps.logger.info("export render discarded: the export was abandoned while it ran", {
|
|
7758
|
+
tags: { deviceId: current.deviceId },
|
|
7759
|
+
meta: {
|
|
7760
|
+
exportId: id,
|
|
7761
|
+
state: current.state,
|
|
7762
|
+
bytes
|
|
7763
|
+
}
|
|
7764
|
+
});
|
|
7765
|
+
return;
|
|
7766
|
+
}
|
|
7702
7767
|
await patchExport(this.deps.state, id, {
|
|
7703
7768
|
state: "ready",
|
|
7704
7769
|
progressPct: 100,
|
|
@@ -7726,6 +7791,8 @@ var ExportEngine = class {
|
|
|
7726
7791
|
exportId: id,
|
|
7727
7792
|
error
|
|
7728
7793
|
} });
|
|
7794
|
+
const current = await getExportRecord(this.deps.state, id);
|
|
7795
|
+
if (current !== null && current.state === "deleted") return;
|
|
7729
7796
|
await patchExport(this.deps.state, id, {
|
|
7730
7797
|
state: "failed",
|
|
7731
7798
|
progressPct: null,
|
package/dist/recorder/index.mjs
CHANGED
|
@@ -6769,6 +6769,30 @@ async function patchExport(state, id, patch) {
|
|
|
6769
6769
|
return merged;
|
|
6770
6770
|
});
|
|
6771
6771
|
}
|
|
6772
|
+
/**
|
|
6773
|
+
* Patch a row UNLESS its current state says not to — the check and the write
|
|
6774
|
+
* are ONE serialized step, so a delete that lands between a separate read and
|
|
6775
|
+
* a separate patch can no longer be overwritten (review R5).
|
|
6776
|
+
*/
|
|
6777
|
+
async function patchExportUnless(state, id, patch, refuse) {
|
|
6778
|
+
return serialize(state, id, async () => {
|
|
6779
|
+
const existing = await state.read(id);
|
|
6780
|
+
if (existing === null) return { kind: "missing" };
|
|
6781
|
+
if (refuse(existing)) return {
|
|
6782
|
+
kind: "refused",
|
|
6783
|
+
record: existing
|
|
6784
|
+
};
|
|
6785
|
+
const merged = ExportRecordSchema.parse({
|
|
6786
|
+
...existing,
|
|
6787
|
+
...patch
|
|
6788
|
+
});
|
|
6789
|
+
await state.write(id, merged);
|
|
6790
|
+
return {
|
|
6791
|
+
kind: "patched",
|
|
6792
|
+
record: merged
|
|
6793
|
+
};
|
|
6794
|
+
});
|
|
6795
|
+
}
|
|
6772
6796
|
/** Read one export row by id — ONE keyed row read. */
|
|
6773
6797
|
async function getExportRecord(state, id) {
|
|
6774
6798
|
return state.read(id);
|
|
@@ -6988,6 +7012,13 @@ function expectedOutSeconds(rec) {
|
|
|
6988
7012
|
}
|
|
6989
7013
|
return rangeSec / (rec.options.speed ?? 1);
|
|
6990
7014
|
}
|
|
7015
|
+
/**
|
|
7016
|
+
* A row nobody will read: its caller deleted it, it expired, or it already
|
|
7017
|
+
* failed (a cancel finalises as `failed`). The engine renders none of these.
|
|
7018
|
+
*/
|
|
7019
|
+
function isAbandonedExportState(state) {
|
|
7020
|
+
return state === "deleted" || state === "expired" || state === "failed";
|
|
7021
|
+
}
|
|
6991
7022
|
var ExportEngine = class {
|
|
6992
7023
|
deps;
|
|
6993
7024
|
queue = [];
|
|
@@ -7048,16 +7079,37 @@ var ExportEngine = class {
|
|
|
7048
7079
|
async render(id) {
|
|
7049
7080
|
const existing = await getExportRecord(this.deps.state, id);
|
|
7050
7081
|
if (!existing) return;
|
|
7082
|
+
if (isAbandonedExportState(existing.state)) {
|
|
7083
|
+
this.deps.logger.info("export render skipped: the export was abandoned before it ran", {
|
|
7084
|
+
tags: { deviceId: existing.deviceId },
|
|
7085
|
+
meta: {
|
|
7086
|
+
exportId: id,
|
|
7087
|
+
state: existing.state
|
|
7088
|
+
}
|
|
7089
|
+
});
|
|
7090
|
+
return;
|
|
7091
|
+
}
|
|
7051
7092
|
const subject = exportSubjectOf(existing);
|
|
7052
7093
|
if (subject.kind === "clip" && subject.source !== ANALYTICS_CLIP_SOURCE) {
|
|
7053
7094
|
await this.fetchClip(id, existing, subject);
|
|
7054
7095
|
return;
|
|
7055
7096
|
}
|
|
7056
|
-
const
|
|
7097
|
+
const claimed = await patchExportUnless(this.deps.state, id, {
|
|
7057
7098
|
state: "rendering",
|
|
7058
7099
|
progressPct: 0
|
|
7059
|
-
});
|
|
7060
|
-
if (
|
|
7100
|
+
}, (current) => isAbandonedExportState(current.state));
|
|
7101
|
+
if (claimed.kind === "missing") return;
|
|
7102
|
+
if (claimed.kind === "refused") {
|
|
7103
|
+
this.deps.logger.info("export render skipped: the export was abandoned before it ran", {
|
|
7104
|
+
tags: { deviceId: claimed.record.deviceId },
|
|
7105
|
+
meta: {
|
|
7106
|
+
exportId: id,
|
|
7107
|
+
state: claimed.record.state
|
|
7108
|
+
}
|
|
7109
|
+
});
|
|
7110
|
+
return;
|
|
7111
|
+
}
|
|
7112
|
+
const rec = claimed.record;
|
|
7061
7113
|
const playlist = await this.deps.resolvePlaylist(rec);
|
|
7062
7114
|
if (!playlist) {
|
|
7063
7115
|
await this.fail(id, "no footage for range");
|
|
@@ -7691,6 +7743,19 @@ var ExportEngine = class {
|
|
|
7691
7743
|
await this.fail(id, `render produced no video frames (${bytes} bytes, < ${EXPORT_MIN_PLAUSIBLE_BYTES})`);
|
|
7692
7744
|
return;
|
|
7693
7745
|
}
|
|
7746
|
+
const current = await getExportRecord(this.deps.state, id);
|
|
7747
|
+
if (current !== null && isAbandonedExportState(current.state)) {
|
|
7748
|
+
await this.deps.removeFile(outPath);
|
|
7749
|
+
this.deps.logger.info("export render discarded: the export was abandoned while it ran", {
|
|
7750
|
+
tags: { deviceId: current.deviceId },
|
|
7751
|
+
meta: {
|
|
7752
|
+
exportId: id,
|
|
7753
|
+
state: current.state,
|
|
7754
|
+
bytes
|
|
7755
|
+
}
|
|
7756
|
+
});
|
|
7757
|
+
return;
|
|
7758
|
+
}
|
|
7694
7759
|
await patchExport(this.deps.state, id, {
|
|
7695
7760
|
state: "ready",
|
|
7696
7761
|
progressPct: 100,
|
|
@@ -7718,6 +7783,8 @@ var ExportEngine = class {
|
|
|
7718
7783
|
exportId: id,
|
|
7719
7784
|
error
|
|
7720
7785
|
} });
|
|
7786
|
+
const current = await getExportRecord(this.deps.state, id);
|
|
7787
|
+
if (current !== null && current.state === "deleted") return;
|
|
7721
7788
|
await patchExport(this.deps.state, id, {
|
|
7722
7789
|
state: "failed",
|
|
7723
7790
|
progressPct: null,
|
|
@@ -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-DZh9jQi-.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.310",
|
|
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",
|