@camstack/addon-pipeline 1.2.74 → 1.2.76
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/{addon-utils-CQs-AjTJ.js → addon-utils-CTpQfjSR.js} +4 -4
- package/dist/audio-analyzer/index.js +5 -6
- package/dist/audio-analyzer/index.mjs +3 -3
- package/dist/detection-pipeline/index.js +9 -10
- package/dist/detection-pipeline/index.mjs +5 -5
- package/dist/{dist-CgJ8MRAy.js → dist-CZLjObZZ.js} +1996 -29
- package/dist/{dist-CKY0efl3.mjs → dist-zksfWnEA.mjs} +1961 -29
- package/dist/{event-loop-stall-monitor-CIapFIez.mjs → event-loop-stall-monitor-BuZA3loB.mjs} +1 -1
- package/dist/{event-loop-stall-monitor-Dx-zXcNg.js → event-loop-stall-monitor-CcBQAI28.js} +1 -1
- package/dist/lazy-sharp-6oymT_yf.mjs +341 -0
- package/dist/lazy-sharp-SWR_D1Um.js +360 -0
- package/dist/motion-wasm/index.js +3 -3
- package/dist/motion-wasm/index.mjs +3 -3
- package/dist/pipeline-runner/index.js +280 -18
- package/dist/pipeline-runner/index.mjs +278 -15
- package/dist/recorder/index.js +138 -32
- package/dist/recorder/index.mjs +137 -30
- package/dist/session-decode/decode-worker-child.js +311 -126
- package/dist/session-decode/decode-worker-child.mjs +311 -123
- package/dist/stream-broker/_stub.js +94 -94
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DVJ4gKkk.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-Dd6XOtVn.mjs} +2 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-RYTOS6B-.mjs +26 -0
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DfsLsn2e.mjs +26 -0
- package/dist/stream-broker/{hostInit-5SFdfUyc.mjs → hostInit-COc_Q_xX.mjs} +2 -2
- package/dist/stream-broker/index.js +12 -13
- package/dist/stream-broker/index.mjs +3 -3
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/dist/{worker-protocol-D44DCkcs.js → worker-protocol-DAQ1iZFK.js} +1 -1
- package/dist/{worker-protocol-BzAQPUR-.mjs → worker-protocol-DyX_HbaJ.mjs} +1 -1
- package/package.json +1 -1
- package/dist/chunk-emK7D4bc.js +0 -35
- package/dist/lazy-sharp-B-mb8uWx.mjs +0 -20
- package/dist/lazy-sharp-CcYuXtsa.js +0 -25
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-C_plRUtD.mjs +0 -26
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CExO0piw.mjs +0 -26
- package/dist/{addon-utils-CZ2xo67g.mjs → addon-utils-A2S9D7pu.mjs} +2 -2
package/dist/recorder/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { At as string, Dt as number, J as recordingExportCapability, Mt as EventCategory, N as deriveRecordingMode, Ot as object, St as array, Z as storageEvictableCapability, _ as OpsLogEntrySchema, b as RECORDING_EXPORT_MAX_READ_BYTES, c as DEFAULT_EVENTS_BAND_BUFFER_SEC, d as EVENT_PAD_MS, ft as hydrateSchema, gt as nodePin, kt as record, p as ExportRecordSchema, q as recordingCapability, st as BaseAddon, tt as errMsg, ut as DeviceType, x as RecordingConfigSchema, yt as selectAssignedProfileSlots } from "../dist-
|
|
1
|
+
import { At as string, Dt as number, J as recordingExportCapability, Mt as EventCategory, N as deriveRecordingMode, Ot as object, St as array, Z as storageEvictableCapability, _ as OpsLogEntrySchema, b as RECORDING_EXPORT_MAX_READ_BYTES, c as DEFAULT_EVENTS_BAND_BUFFER_SEC, d as EVENT_PAD_MS, ft as hydrateSchema, gt as nodePin, kt as record, p as ExportRecordSchema, q as recordingCapability, st as BaseAddon, tt as errMsg, ut as DeviceType, x as RecordingConfigSchema, yt as selectAssignedProfileSlots } from "../dist-zksfWnEA.mjs";
|
|
2
2
|
import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
|
|
3
|
-
import { n as createFileDataPlaneHandler, s as parseRangeHeader, t as contentTypeFor } from "../addon-utils-
|
|
3
|
+
import { n as createFileDataPlaneHandler, s as parseRangeHeader, t as contentTypeFor } from "../addon-utils-A2S9D7pu.mjs";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
|
-
import { createReadStream, promises, realpathSync } from "node:fs";
|
|
7
6
|
import path from "node:path";
|
|
7
|
+
import { createReadStream, promises, realpathSync } from "node:fs";
|
|
8
8
|
import { open } from "node:fs/promises";
|
|
9
9
|
//#region src/recorder/event-capture.ts
|
|
10
10
|
function markerFromMotion(data, pad) {
|
|
@@ -2249,7 +2249,7 @@ var DEFAULT_DEVICE_CONFIG = {
|
|
|
2249
2249
|
enabled: false,
|
|
2250
2250
|
bands: []
|
|
2251
2251
|
};
|
|
2252
|
-
function serialize(map) {
|
|
2252
|
+
function serialize$1(map) {
|
|
2253
2253
|
const out = {};
|
|
2254
2254
|
for (const [id, config] of map) out[String(id)] = config;
|
|
2255
2255
|
return out;
|
|
@@ -2304,7 +2304,7 @@ async function saveDeviceConfig(state, deviceId, config) {
|
|
|
2304
2304
|
};
|
|
2305
2305
|
const map = await readDeviceConfigs(state);
|
|
2306
2306
|
map.set(deviceId, validated);
|
|
2307
|
-
await state.set(serialize(map));
|
|
2307
|
+
await state.set(serialize$1(map));
|
|
2308
2308
|
return validated;
|
|
2309
2309
|
}
|
|
2310
2310
|
/**
|
|
@@ -2642,6 +2642,33 @@ function buildExportArgs(input) {
|
|
|
2642
2642
|
var RECORDING_EXPORTS_KEY = "recordingExports";
|
|
2643
2643
|
/** Persisted shape: export id → full ExportRecord. */
|
|
2644
2644
|
var RecordingExportsBlobSchema = record(string(), ExportRecordSchema);
|
|
2645
|
+
/**
|
|
2646
|
+
* One in-flight mutation chain per durable handle.
|
|
2647
|
+
*
|
|
2648
|
+
* EVERY mutation here is a read-modify-write of the SAME blob, and both halves
|
|
2649
|
+
* are async — so two overlapping cycles read the same snapshot and the second
|
|
2650
|
+
* `set` discards whatever the first one added. Last writer wins, silently.
|
|
2651
|
+
*
|
|
2652
|
+
* That is not a hypothetical. The engine patches `progressPct` roughly once a
|
|
2653
|
+
* second for an in-flight render, unawaited; on 2026-08-14 a `createExport` for
|
|
2654
|
+
* camera 615 landed between one such patch's read and its write, the row was
|
|
2655
|
+
* erased, and five seconds later the poll answered `unknown export
|
|
2656
|
+
* "547ea182-…"`. The camera's whole night was lost to it — the scheduler read a
|
|
2657
|
+
* vanished row as a failed render and re-queued, forever.
|
|
2658
|
+
*
|
|
2659
|
+
* Serialising per handle is the smallest fix that makes the loss impossible:
|
|
2660
|
+
* the cycles queue instead of interleaving, and the queue is per state object
|
|
2661
|
+
* so two recorders in one process never contend. A `WeakMap` keeps a disposed
|
|
2662
|
+
* handle collectable. Reads stay OUTSIDE the chain — a blob replacement is
|
|
2663
|
+
* atomic, so a reader always sees one consistent generation.
|
|
2664
|
+
*/
|
|
2665
|
+
var mutationChains = /* @__PURE__ */ new WeakMap();
|
|
2666
|
+
/** Run `work` after every mutation already queued for `state`, never before. */
|
|
2667
|
+
async function serialize(state, work) {
|
|
2668
|
+
const next = (mutationChains.get(state) ?? Promise.resolve()).then(work, work);
|
|
2669
|
+
mutationChains.set(state, next.catch(() => void 0));
|
|
2670
|
+
return next;
|
|
2671
|
+
}
|
|
2645
2672
|
/** Read every persisted export row, keyed by export id. */
|
|
2646
2673
|
async function readExports(state) {
|
|
2647
2674
|
const blob = await state.get();
|
|
@@ -2650,26 +2677,30 @@ async function readExports(state) {
|
|
|
2650
2677
|
/** Insert or replace one export row. Validates at the boundary. Returns it. */
|
|
2651
2678
|
async function upsertExport(state, record) {
|
|
2652
2679
|
const validated = ExportRecordSchema.parse(record);
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2680
|
+
return serialize(state, async () => {
|
|
2681
|
+
const map = await readExports(state);
|
|
2682
|
+
map.set(validated.id, validated);
|
|
2683
|
+
await state.set(Object.fromEntries(map));
|
|
2684
|
+
return validated;
|
|
2685
|
+
});
|
|
2657
2686
|
}
|
|
2658
2687
|
/**
|
|
2659
2688
|
* Shallow-merge a patch into one export row and persist. Returns the merged
|
|
2660
2689
|
* record, or null when the id is unknown.
|
|
2661
2690
|
*/
|
|
2662
2691
|
async function patchExport(state, id, patch) {
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2692
|
+
return serialize(state, async () => {
|
|
2693
|
+
const map = await readExports(state);
|
|
2694
|
+
const existing = map.get(id);
|
|
2695
|
+
if (!existing) return null;
|
|
2696
|
+
const merged = ExportRecordSchema.parse({
|
|
2697
|
+
...existing,
|
|
2698
|
+
...patch
|
|
2699
|
+
});
|
|
2700
|
+
map.set(id, merged);
|
|
2701
|
+
await state.set(Object.fromEntries(map));
|
|
2702
|
+
return merged;
|
|
2669
2703
|
});
|
|
2670
|
-
map.set(id, merged);
|
|
2671
|
-
await state.set(Object.fromEntries(map));
|
|
2672
|
-
return merged;
|
|
2673
2704
|
}
|
|
2674
2705
|
/** Read one export row by id, or null. */
|
|
2675
2706
|
async function getExportRecord(state, id) {
|
|
@@ -3000,6 +3031,80 @@ async function markDownloaded(id, now, deps, scheduleDelete, graceMs) {
|
|
|
3000
3031
|
}, graceMs);
|
|
3001
3032
|
}
|
|
3002
3033
|
//#endregion
|
|
3034
|
+
//#region src/recorder/addon/export-reconcile.ts
|
|
3035
|
+
/**
|
|
3036
|
+
* States that can only mean "a render was owed and the process went away".
|
|
3037
|
+
*
|
|
3038
|
+
* There is no live render at reconcile time by construction: the engine is
|
|
3039
|
+
* built fresh with an empty queue, and this runs before anything is enqueued.
|
|
3040
|
+
*/
|
|
3041
|
+
function isInterrupted(record) {
|
|
3042
|
+
return record.state === "queued" || record.state === "rendering";
|
|
3043
|
+
}
|
|
3044
|
+
/**
|
|
3045
|
+
* Hand every interrupted row back to the engine, once, at boot.
|
|
3046
|
+
*
|
|
3047
|
+
* A row past its `expiresAt` is FAILED rather than re-rendered: hours of
|
|
3048
|
+
* footage re-encoded for a file the janitor is about to drop costs a recording
|
|
3049
|
+
* node an ffmpeg for nothing. Failing it is also what makes the outcome
|
|
3050
|
+
* visible — a row that silently stays `queued` forever is the defect this
|
|
3051
|
+
* module exists to remove, and swapping it for a quieter one would not be a
|
|
3052
|
+
* fix.
|
|
3053
|
+
*/
|
|
3054
|
+
async function reconcileInterruptedExports(deps) {
|
|
3055
|
+
const now = deps.now();
|
|
3056
|
+
const interrupted = (await listExportsFor(deps.state)).filter(isInterrupted);
|
|
3057
|
+
if (interrupted.length === 0) return {
|
|
3058
|
+
requeued: 0,
|
|
3059
|
+
expired: 0
|
|
3060
|
+
};
|
|
3061
|
+
let requeued = 0;
|
|
3062
|
+
let expired = 0;
|
|
3063
|
+
for (const row of interrupted) {
|
|
3064
|
+
const tags = { deviceId: row.deviceId };
|
|
3065
|
+
const meta = {
|
|
3066
|
+
exportId: row.id,
|
|
3067
|
+
wasState: row.state,
|
|
3068
|
+
fromMs: row.fromMs,
|
|
3069
|
+
toMs: row.toMs,
|
|
3070
|
+
createdAt: row.createdAt
|
|
3071
|
+
};
|
|
3072
|
+
if (row.expiresAt <= now) {
|
|
3073
|
+
expired += 1;
|
|
3074
|
+
await patchExport(deps.state, row.id, {
|
|
3075
|
+
state: "failed",
|
|
3076
|
+
progressPct: null,
|
|
3077
|
+
error: "interrupted by a restart and expired before it could be rendered"
|
|
3078
|
+
});
|
|
3079
|
+
deps.logger.warn("export abandoned: interrupted by a restart, and already expired", {
|
|
3080
|
+
tags,
|
|
3081
|
+
meta
|
|
3082
|
+
});
|
|
3083
|
+
continue;
|
|
3084
|
+
}
|
|
3085
|
+
requeued += 1;
|
|
3086
|
+
await patchExport(deps.state, row.id, {
|
|
3087
|
+
state: "queued",
|
|
3088
|
+
progressPct: null,
|
|
3089
|
+
error: null
|
|
3090
|
+
});
|
|
3091
|
+
deps.logger.warn("export re-queued: it was interrupted by a restart", {
|
|
3092
|
+
tags,
|
|
3093
|
+
meta
|
|
3094
|
+
});
|
|
3095
|
+
deps.engine.enqueue(row.id);
|
|
3096
|
+
}
|
|
3097
|
+
deps.logger.info("recording exports reconciled after restart", { meta: {
|
|
3098
|
+
interrupted: interrupted.length,
|
|
3099
|
+
requeued,
|
|
3100
|
+
expired
|
|
3101
|
+
} });
|
|
3102
|
+
return {
|
|
3103
|
+
requeued,
|
|
3104
|
+
expired
|
|
3105
|
+
};
|
|
3106
|
+
}
|
|
3107
|
+
//#endregion
|
|
3003
3108
|
//#region src/recorder/playlist.ts
|
|
3004
3109
|
/** A VOD variant playlist with an absolute wall-clock anchor per segment. */
|
|
3005
3110
|
function buildVariantPlaylist(segments) {
|
|
@@ -7477,23 +7582,25 @@ var RecorderV2Addon = class extends BaseAddon {
|
|
|
7477
7582
|
this.retentionSweeper?.start();
|
|
7478
7583
|
}
|
|
7479
7584
|
/**
|
|
7480
|
-
* Resume interrupted exports and arm the expiry sweep.
|
|
7481
|
-
*
|
|
7482
|
-
*
|
|
7483
|
-
*
|
|
7585
|
+
* Resume interrupted exports and arm the expiry sweep.
|
|
7586
|
+
*
|
|
7587
|
+
* The resume itself lives in `export-reconcile.ts` — pure, tested, and loud
|
|
7588
|
+
* about every row it moves. It used to be an untested loop inlined here that
|
|
7589
|
+
* said nothing at all, so "why is this export still queued an hour later" had
|
|
7590
|
+
* no answer in the log, and a row whose life had already run out was
|
|
7591
|
+
* re-rendered anyway. Both halves are best-effort: a failure never blocks
|
|
7592
|
+
* boot.
|
|
7484
7593
|
*/
|
|
7485
7594
|
async bootstrapExports() {
|
|
7486
7595
|
const engine = this.exportEngine;
|
|
7487
7596
|
if (!engine) return;
|
|
7488
|
-
const state = this.exportsStore();
|
|
7489
7597
|
try {
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
}
|
|
7598
|
+
await reconcileInterruptedExports({
|
|
7599
|
+
state: this.exportsStore(),
|
|
7600
|
+
engine,
|
|
7601
|
+
now: () => Date.now(),
|
|
7602
|
+
logger: this.ctx.logger.child("export")
|
|
7603
|
+
});
|
|
7497
7604
|
} catch (err) {
|
|
7498
7605
|
this.ctx.logger.warn("recorder: export boot re-queue failed", { meta: { error: errMsg(err) } });
|
|
7499
7606
|
}
|