@camstack/addon-pipeline 1.2.151 → 1.2.153
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/audio-analyzer/index.js +2 -2
- package/dist/audio-analyzer/index.mjs +2 -2
- package/dist/detection-pipeline/index.js +5 -5
- package/dist/detection-pipeline/index.mjs +4 -4
- package/dist/{dist-hmG3nfuW.js → dist-DnVnWACi.js} +346 -214
- package/dist/{dist-BjzcUac4.mjs → dist-Dsritt4-.mjs} +346 -214
- package/dist/{lazy-sharp-RLE6klOt.js → lazy-sharp-DZWYKdV2.js} +1 -1
- package/dist/{local-frame-registry-Ct2vQ7Dp.js → local-frame-registry-BpFLRfbw.js} +1 -1
- package/dist/{local-frame-registry-BFaxbRtK.mjs → local-frame-registry-Yf-uIxbS.mjs} +1 -1
- package/dist/motion-wasm/index.js +2 -2
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/{node-BwXwfrvA.js → node-C5xmFvjS.js} +1 -1
- package/dist/{node-U9fJ-bQN.mjs → node-CNGxkfes.mjs} +1 -1
- package/dist/pipeline-runner/index.js +5 -5
- package/dist/pipeline-runner/index.mjs +4 -4
- package/dist/{process-memory-DR9jSxpX.js → process-memory-COT8rA8L.js} +1 -1
- package/dist/{process-memory-4WDUPavu.mjs → process-memory-DX_KCfdx.mjs} +1 -1
- package/dist/recorder/index.js +167 -28
- package/dist/recorder/index.mjs +167 -28
- package/dist/{segment-demux-js-kUN5AQVv.mjs → segment-demux-js-CTFSl-b9.mjs} +1 -1
- package/dist/{segment-demux-js-zqUNh3pj.js → segment-demux-js-Dwg9Jq5_.js} +1 -1
- package/dist/session-decode/decode-worker-child.js +2 -2
- package/dist/session-decode/decode-worker-child.mjs +1 -1
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BOXQSR0X.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-ZucA907q.mjs} +3 -3
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-B14Zc1oq.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-DO6LkN6o.mjs +26 -0
- package/dist/stream-broker/demux-worker-child.js +1 -1
- package/dist/stream-broker/demux-worker-child.mjs +1 -1
- package/dist/stream-broker/{hostInit-CnUhcNPG.mjs → hostInit-BqUcM0Fh.mjs} +3 -3
- package/dist/stream-broker/index.js +3 -3
- package/dist/stream-broker/index.mjs +3 -3
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/dist/{worker-protocol-DE_jjbFA.js → worker-protocol-BsvaPb-G.js} +1 -1
- package/dist/{worker-protocol-BzlEZ56r.mjs → worker-protocol-CDBQXOIu.mjs} +1 -1
- package/package.json +1 -1
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CyIaTPRY.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-Cyyhy_D8.mjs +0 -26
|
@@ -2,8 +2,8 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
6
|
-
const require_lazy_sharp = require("../lazy-sharp-
|
|
5
|
+
const require_dist = require("../dist-DnVnWACi.js");
|
|
6
|
+
const require_lazy_sharp = require("../lazy-sharp-DZWYKdV2.js");
|
|
7
7
|
let node_fs = require("node:fs");
|
|
8
8
|
let node_path = require("node:path");
|
|
9
9
|
//#region src/motion-wasm/wasm-motion-detector.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { It as hydrateSchema, Pt as DeviceType, Y as evaluateZoneRules, it as motionDetectionCapability, jt as BaseAddon } from "../dist-
|
|
1
|
+
import { It as hydrateSchema, Pt as DeviceType, Y as evaluateZoneRules, it as motionDetectionCapability, jt as BaseAddon } from "../dist-Dsritt4-.mjs";
|
|
2
2
|
import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
|
|
3
3
|
import { readFileSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Dt as buildFfmpegArgs, Et as Fmp4BoxSplitter, kt as isSoftwareDecode, wt as errMsg } from "./dist-
|
|
1
|
+
import { Dt as buildFfmpegArgs, Et as Fmp4BoxSplitter, kt as isSoftwareDecode, wt as errMsg } from "./dist-Dsritt4-.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import "node:fs";
|
|
4
4
|
import "node:path";
|
|
@@ -2,12 +2,12 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
6
|
-
const require_node = require("../node-
|
|
7
|
-
const require_local_frame_registry = require("../local-frame-registry-
|
|
8
|
-
const require_worker_protocol = require("../worker-protocol-
|
|
5
|
+
const require_dist = require("../dist-DnVnWACi.js");
|
|
6
|
+
const require_node = require("../node-C5xmFvjS.js");
|
|
7
|
+
const require_local_frame_registry = require("../local-frame-registry-BpFLRfbw.js");
|
|
8
|
+
const require_worker_protocol = require("../worker-protocol-BsvaPb-G.js");
|
|
9
9
|
const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
|
|
10
|
-
const require_lazy_sharp = require("../lazy-sharp-
|
|
10
|
+
const require_lazy_sharp = require("../lazy-sharp-DZWYKdV2.js");
|
|
11
11
|
const require_restream_intent = require("../restream-intent-Cv9x3jmu.js");
|
|
12
12
|
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-DaUBcb13.js");
|
|
13
13
|
const require_remote_restream = require("../remote-restream-CO36Sr30.js");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { B as defineCustomActions, Bt as nodePin, Ft as createEvent, Gt as _enum, H as deriveDetailCropRect, Kt as array, L as customAction, Qt as object, X as failureContributionCapability, Xt as literal, Yt as lazy, Zt as number, _ as FailureCounters, en as string, et as loadContributionCapability, ft as pipelineRunnerCapability, jt as BaseAddon, lt as pickDetailCropConvention, m as DEVICE_BACKEND_TO_FORMAT, nn as EventCategory, p as DEFAULT_NATIVE_LEASE_SETTINGS, qt as boolean, u as DEFAULT_DETAIL_CROP_CONVENTION, ut as pickNativeLeaseOverride, wt as errMsg } from "../dist-
|
|
2
|
-
import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-
|
|
3
|
-
import { c as getStepDefinition, n as resolveFrameViewGeometry, t as localFrameRegistry } from "../local-frame-registry-
|
|
4
|
-
import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-
|
|
1
|
+
import { B as defineCustomActions, Bt as nodePin, Ft as createEvent, Gt as _enum, H as deriveDetailCropRect, Kt as array, L as customAction, Qt as object, X as failureContributionCapability, Xt as literal, Yt as lazy, Zt as number, _ as FailureCounters, en as string, et as loadContributionCapability, ft as pipelineRunnerCapability, jt as BaseAddon, lt as pickDetailCropConvention, m as DEVICE_BACKEND_TO_FORMAT, nn as EventCategory, p as DEFAULT_NATIVE_LEASE_SETTINGS, qt as boolean, u as DEFAULT_DETAIL_CROP_CONVENTION, ut as pickNativeLeaseOverride, wt as errMsg } from "../dist-Dsritt4-.mjs";
|
|
2
|
+
import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-CNGxkfes.mjs";
|
|
3
|
+
import { c as getStepDefinition, n as resolveFrameViewGeometry, t as localFrameRegistry } from "../local-frame-registry-Yf-uIxbS.mjs";
|
|
4
|
+
import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-CDBQXOIu.mjs";
|
|
5
5
|
import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
|
|
6
6
|
import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
|
|
7
7
|
import { n as withDetectionIntent } from "../restream-intent-B4BXZra7.mjs";
|
package/dist/recorder/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const require_dist = require("../dist-
|
|
2
|
-
const require_node = require("../node-
|
|
1
|
+
const require_dist = require("../dist-DnVnWACi.js");
|
|
2
|
+
const require_node = require("../node-C5xmFvjS.js");
|
|
3
3
|
const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
|
|
4
4
|
const require_restream_intent = require("../restream-intent-Cv9x3jmu.js");
|
|
5
5
|
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-DaUBcb13.js");
|
|
@@ -1621,32 +1621,73 @@ function snapshot(j) {
|
|
|
1621
1621
|
filesMoved: j.filesMoved,
|
|
1622
1622
|
bytesMoved: j.bytesMoved,
|
|
1623
1623
|
filesTotal: j.filesTotal,
|
|
1624
|
+
rowsReconciled: j.rowsReconciled,
|
|
1624
1625
|
startedAt: j.startedAt,
|
|
1625
1626
|
finishedAt: j.finishedAt,
|
|
1626
1627
|
error: j.error
|
|
1627
1628
|
};
|
|
1628
1629
|
}
|
|
1629
1630
|
/**
|
|
1630
|
-
*
|
|
1631
|
+
* The row's source file is not on disk.
|
|
1632
|
+
*
|
|
1633
|
+
* Carries `code: 'ENOENT'` because that is how every caller here already tells
|
|
1634
|
+
* a ghost row from a real failure, and {@link copyVerified} now discovers the
|
|
1635
|
+
* absence with a `stat` rather than by letting `copyFile` raise it.
|
|
1636
|
+
*/
|
|
1637
|
+
var RelocateSourceMissingError = class extends Error {
|
|
1638
|
+
code = "ENOENT";
|
|
1639
|
+
constructor(src) {
|
|
1640
|
+
super(`relocate source missing: ${src}`);
|
|
1641
|
+
this.name = "RelocateSourceMissingError";
|
|
1642
|
+
}
|
|
1643
|
+
};
|
|
1644
|
+
/**
|
|
1645
|
+
* One file's COPY: copy-if-absent → verify the destination against the SOURCE'S
|
|
1646
|
+
* OWN SIZE. The source is left in place.
|
|
1631
1647
|
*
|
|
1632
1648
|
* Split out of {@link moveFile} because the durable index re-point has to
|
|
1633
1649
|
* happen while BOTH locations still hold the bytes — see
|
|
1634
|
-
* `SegmentHourLedger.repointSegments`.
|
|
1635
|
-
*
|
|
1650
|
+
* `SegmentHourLedger.repointSegments`.
|
|
1651
|
+
*
|
|
1652
|
+
* **`recordedBytes` is never the verify's reference.** It used to be, and it
|
|
1653
|
+
* cannot be: `fs.copyFile` truncates and replaces, so the destination always
|
|
1654
|
+
* equals the source, and comparing that result against a number the LEDGER
|
|
1655
|
+
* remembers can only ever fail when the ledger is wrong. On 2026-08-30 that
|
|
1656
|
+
* reported a byte-perfect copy as corruption and killed a 110 749-file drain
|
|
1657
|
+
* on its 12 440th file:
|
|
1658
|
+
*
|
|
1659
|
+
* relocate verify failed: …/1787926410000-9966-274432.m4s
|
|
1660
|
+
* is 783801B, expected 274432B
|
|
1661
|
+
*
|
|
1662
|
+
* Both files measured 783801 B on the hub. What is faithful is "the
|
|
1663
|
+
* destination equals the source", and that is what is asserted here; the
|
|
1664
|
+
* recorded number survives only as the reference for a destination whose
|
|
1665
|
+
* source is already GONE, where there is nothing else left to compare against.
|
|
1636
1666
|
*/
|
|
1637
|
-
async function copyVerified(src, dst,
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
dstBytes
|
|
1643
|
-
}
|
|
1644
|
-
if (
|
|
1667
|
+
async function copyVerified(src, dst, recordedBytes) {
|
|
1668
|
+
const dstBytes = await fileSize(dst);
|
|
1669
|
+
const srcBytes = await fileSize(src);
|
|
1670
|
+
if (dstBytes !== null && dstBytes === (srcBytes ?? recordedBytes)) return {
|
|
1671
|
+
copied: 0,
|
|
1672
|
+
srcBytes: dstBytes
|
|
1673
|
+
};
|
|
1674
|
+
if (srcBytes === null) throw new RelocateSourceMissingError(src);
|
|
1645
1675
|
await node_fs.promises.mkdir(node_path.default.dirname(dst), { recursive: true });
|
|
1646
1676
|
await node_fs.promises.copyFile(src, dst);
|
|
1647
1677
|
const after = await node_fs.promises.stat(dst);
|
|
1648
1678
|
if (after.size !== srcBytes) throw new Error(`relocate verify failed: ${dst} is ${after.size}B, expected ${srcBytes}B`);
|
|
1649
|
-
return
|
|
1679
|
+
return {
|
|
1680
|
+
copied: srcBytes,
|
|
1681
|
+
srcBytes
|
|
1682
|
+
};
|
|
1683
|
+
}
|
|
1684
|
+
/** A file's size, or `null` when it is not there. */
|
|
1685
|
+
async function fileSize(p) {
|
|
1686
|
+
try {
|
|
1687
|
+
return (await node_fs.promises.stat(p)).size;
|
|
1688
|
+
} catch {
|
|
1689
|
+
return null;
|
|
1690
|
+
}
|
|
1650
1691
|
}
|
|
1651
1692
|
var RelocateEngine = class {
|
|
1652
1693
|
deps;
|
|
@@ -1700,6 +1741,14 @@ var RelocateEngine = class {
|
|
|
1700
1741
|
if (!to) throw new Error(`unknown target location: ${input.toLocationId}`);
|
|
1701
1742
|
if (from.id === to.id) throw new Error("source and target locations are identical");
|
|
1702
1743
|
if (to.readOnly) throw new Error(`target location is read-only: ${to.id}`);
|
|
1744
|
+
if (to.enabled === false) this.deps.logger.warn("relocate: target location is DISABLED (standby) — moving to it because the operator named it; placement still never chooses it for new writes", {
|
|
1745
|
+
...input.deviceId !== void 0 ? { tags: { deviceId: input.deviceId } } : {},
|
|
1746
|
+
meta: {
|
|
1747
|
+
fromLocationId: from.id,
|
|
1748
|
+
toLocationId: to.id,
|
|
1749
|
+
footageClass: input.footageClass ?? null
|
|
1750
|
+
}
|
|
1751
|
+
});
|
|
1703
1752
|
const job = {
|
|
1704
1753
|
jobId: this.deps.newId(),
|
|
1705
1754
|
state: "queued",
|
|
@@ -1714,6 +1763,7 @@ var RelocateEngine = class {
|
|
|
1714
1763
|
filesMoved: 0,
|
|
1715
1764
|
bytesMoved: 0,
|
|
1716
1765
|
filesTotal: null,
|
|
1766
|
+
rowsReconciled: 0,
|
|
1717
1767
|
startedAt: this.deps.now(),
|
|
1718
1768
|
finishedAt: null,
|
|
1719
1769
|
error: null,
|
|
@@ -1867,7 +1917,8 @@ var RelocateEngine = class {
|
|
|
1867
1917
|
toLocationId: job.toLocationId,
|
|
1868
1918
|
archiveSegments: job.filesTotal,
|
|
1869
1919
|
seen,
|
|
1870
|
-
moved: job.filesMoved
|
|
1920
|
+
moved: job.filesMoved,
|
|
1921
|
+
rowsReconciled: job.rowsReconciled
|
|
1871
1922
|
};
|
|
1872
1923
|
if (archive === null) {
|
|
1873
1924
|
this.deps.logger.warn("relocate: coverage UNKNOWN — with no durable ledger this node cannot say what the source still holds", {
|
|
@@ -1962,6 +2013,56 @@ var RelocateEngine = class {
|
|
|
1962
2013
|
return `${DESTINATION_FULL_PREFIX}: ${to.id} has ${(Math.round(free * 100) / 100).toString()}% free, below its ${floor.toString()}% floor — everything not yet moved is still readable at ${job.fromLocationId}`;
|
|
1963
2014
|
}
|
|
1964
2015
|
/**
|
|
2016
|
+
* The row as the TARGET should record it, given what the source file
|
|
2017
|
+
* actually measured.
|
|
2018
|
+
*
|
|
2019
|
+
* Equal sizes — every ordinary segment — hand the row straight back. A
|
|
2020
|
+
* disagreement is reconciled rather than carried over, and reconciling it
|
|
2021
|
+
* means RENAMING: a segment's byte count is part of its name
|
|
2022
|
+
* (`segmentRelPath`), the durable hour row derives `bytes` from those names
|
|
2023
|
+
* (`hourAggregate`), and those sums are what `StorageEvictableProvider` reads
|
|
2024
|
+
* when a disk fills. Copying the file under its wrong name would carry the
|
|
2025
|
+
* wrong number to the new disk and leave nothing able to correct it — a disk
|
|
2026
|
+
* walk re-parses the same name and agrees with itself.
|
|
2027
|
+
*
|
|
2028
|
+
* The rename happens at the DESTINATION, before the ledger is touched, so a
|
|
2029
|
+
* crash here leaves the source wholly authoritative and untouched: the next
|
|
2030
|
+
* run re-copies under the old name and re-renames. Nothing is dropped
|
|
2031
|
+
* silently — every re-stamp is one `warn` with `tags: { deviceId }` and both
|
|
2032
|
+
* numbers, and the count rides the job record to the operator.
|
|
2033
|
+
*/
|
|
2034
|
+
async reconciled(job, row, to, srcBytes) {
|
|
2035
|
+
if (srcBytes === row.bytes) return row;
|
|
2036
|
+
const fixed = restampSegmentBytes(row, srcBytes);
|
|
2037
|
+
if (fixed === null) {
|
|
2038
|
+
this.deps.logger.warn("relocate: the recorded size disagrees with the file, and the path is not a canonical segment name — moved as-is, the durable byte count stays WRONG", {
|
|
2039
|
+
tags: { deviceId: row.deviceId },
|
|
2040
|
+
meta: {
|
|
2041
|
+
jobId: job.jobId,
|
|
2042
|
+
path: row.path,
|
|
2043
|
+
recordedBytes: row.bytes,
|
|
2044
|
+
actualBytes: srcBytes
|
|
2045
|
+
}
|
|
2046
|
+
});
|
|
2047
|
+
return row;
|
|
2048
|
+
}
|
|
2049
|
+
await node_fs.promises.rename(node_path.default.join(to.root, row.path), node_path.default.join(to.root, fixed.path));
|
|
2050
|
+
job.rowsReconciled += 1;
|
|
2051
|
+
this.deps.logger.warn("relocate: RECONCILED a row whose recorded size disagreed with the file — the file is the fact, the name and the durable row now say so", {
|
|
2052
|
+
tags: { deviceId: row.deviceId },
|
|
2053
|
+
meta: {
|
|
2054
|
+
jobId: job.jobId,
|
|
2055
|
+
fromPath: row.path,
|
|
2056
|
+
toPath: fixed.path,
|
|
2057
|
+
recordedBytes: row.bytes,
|
|
2058
|
+
actualBytes: srcBytes,
|
|
2059
|
+
deltaBytes: srcBytes - row.bytes,
|
|
2060
|
+
toLocationId: to.id
|
|
2061
|
+
}
|
|
2062
|
+
});
|
|
2063
|
+
return fixed;
|
|
2064
|
+
}
|
|
2065
|
+
/**
|
|
1965
2066
|
* Move ONE hour of one (device, profile): copy+verify every file, re-point
|
|
1966
2067
|
* the durable hour row, delete the sources, re-point the RAM index.
|
|
1967
2068
|
*
|
|
@@ -1980,9 +2081,12 @@ var RelocateEngine = class {
|
|
|
1980
2081
|
if (job.cancelRequested) return;
|
|
1981
2082
|
const src = node_path.default.join(from.root, row.path);
|
|
1982
2083
|
const dst = node_path.default.join(to.root, row.path);
|
|
2084
|
+
let pacedBytes = row.bytes;
|
|
1983
2085
|
try {
|
|
1984
|
-
|
|
1985
|
-
|
|
2086
|
+
const outcome = await copyVerified(src, dst, row.bytes);
|
|
2087
|
+
pacedBytes = outcome.srcBytes;
|
|
2088
|
+
copiedBytes += outcome.copied;
|
|
2089
|
+
movable.push(await this.reconciled(job, row, to, outcome.srcBytes));
|
|
1986
2090
|
} catch (err) {
|
|
1987
2091
|
if (!isEnoent(err)) throw err;
|
|
1988
2092
|
this.deps.index.removeSegments([row.path]);
|
|
@@ -1994,7 +2098,7 @@ var RelocateEngine = class {
|
|
|
1994
2098
|
}
|
|
1995
2099
|
});
|
|
1996
2100
|
}
|
|
1997
|
-
await sleep(
|
|
2101
|
+
await sleep(pacedBytes / bytesPerMs);
|
|
1998
2102
|
}
|
|
1999
2103
|
if (movable.length === 0) return;
|
|
2000
2104
|
if (job.cancelRequested) return;
|
|
@@ -2017,11 +2121,16 @@ var RelocateEngine = class {
|
|
|
2017
2121
|
});
|
|
2018
2122
|
return;
|
|
2019
2123
|
}
|
|
2020
|
-
if (!samePhysicalRoot) for (const row of movable) await node_fs.promises.rm(node_path.default.join(from.root, row.path), { force: true });
|
|
2124
|
+
if (!samePhysicalRoot) for (const row of movable) await node_fs.promises.rm(node_path.default.join(from.root, row.fromPath ?? row.path), { force: true });
|
|
2021
2125
|
for (const row of movable) {
|
|
2022
|
-
this.deps.index.removeSegments([row.path]);
|
|
2126
|
+
this.deps.index.removeSegments([row.fromPath ?? row.path]);
|
|
2023
2127
|
this.deps.index.addSegment({
|
|
2024
|
-
|
|
2128
|
+
deviceId: row.deviceId,
|
|
2129
|
+
profile: row.profile,
|
|
2130
|
+
startMs: row.startMs,
|
|
2131
|
+
durMs: row.durMs,
|
|
2132
|
+
bytes: row.bytes,
|
|
2133
|
+
path: row.path,
|
|
2025
2134
|
locationId: to.id
|
|
2026
2135
|
});
|
|
2027
2136
|
}
|
|
@@ -2031,6 +2140,25 @@ var RelocateEngine = class {
|
|
|
2031
2140
|
}
|
|
2032
2141
|
};
|
|
2033
2142
|
/**
|
|
2143
|
+
* The same segment, recorded at its REAL size — or `null` when this path is not
|
|
2144
|
+
* one this repo names, in which case nothing here may rename it.
|
|
2145
|
+
*
|
|
2146
|
+
* The refusal is a round-trip, not a shape guess: the canonical name for the
|
|
2147
|
+
* row's own fields must reproduce `row.path` exactly before the corrected name
|
|
2148
|
+
* is trusted. A path that fails it came from somewhere else (a hand-placed
|
|
2149
|
+
* file, a future layout), and renaming it would move footage to a name no
|
|
2150
|
+
* reader derives.
|
|
2151
|
+
*/
|
|
2152
|
+
function restampSegmentBytes(row, actualBytes) {
|
|
2153
|
+
if (segmentRelPath(row.deviceId, row.profile, row.startMs, row.durMs, row.bytes) !== row.path) return null;
|
|
2154
|
+
return {
|
|
2155
|
+
...row,
|
|
2156
|
+
bytes: actualBytes,
|
|
2157
|
+
path: segmentRelPath(row.deviceId, row.profile, row.startMs, row.durMs, actualBytes),
|
|
2158
|
+
fromPath: row.path
|
|
2159
|
+
};
|
|
2160
|
+
}
|
|
2161
|
+
/**
|
|
2034
2162
|
* The archive slice this job moves, or `null` when it selects nothing at all.
|
|
2035
2163
|
*
|
|
2036
2164
|
* ONE derivation for the census and for the stream. Deriving them separately
|
|
@@ -8630,6 +8758,13 @@ var SegmentHourLedger = class SegmentHourLedger {
|
|
|
8630
8758
|
* the index `hydrated`: nothing would ever walk that hour again, and the
|
|
8631
8759
|
* segment would sit on disk permanently unreachable.
|
|
8632
8760
|
*
|
|
8761
|
+
* **Two path sets, not one.** A path can arrive at the target under a
|
|
8762
|
+
* DIFFERENT name than it leaves the source under: a mover that found a file
|
|
8763
|
+
* larger than its recorded size reconciles the row, and the byte count is
|
|
8764
|
+
* part of the name. So the source row is shrunk by what is LEAVING it and the
|
|
8765
|
+
* target row grows by what is ARRIVING — conflating them would leave the
|
|
8766
|
+
* source row naming a file the caller is about to delete.
|
|
8767
|
+
*
|
|
8633
8768
|
* Returns `false` when NOTHING was repointed and the caller must delete
|
|
8634
8769
|
* nothing. An hour whose detail could not be read decides nothing (D49) —
|
|
8635
8770
|
* the same refusal {@link dropSegments} makes for eviction.
|
|
@@ -8642,11 +8777,15 @@ var SegmentHourLedger = class SegmentHourLedger {
|
|
|
8642
8777
|
const entry = byHour.get(key);
|
|
8643
8778
|
if (entry === void 0) byHour.set(key, {
|
|
8644
8779
|
row,
|
|
8645
|
-
|
|
8780
|
+
leaving: new Set([row.fromPath ?? row.path]),
|
|
8781
|
+
arriving: new Set([row.path])
|
|
8646
8782
|
});
|
|
8647
|
-
else
|
|
8783
|
+
else {
|
|
8784
|
+
entry.leaving.add(row.fromPath ?? row.path);
|
|
8785
|
+
entry.arriving.add(row.path);
|
|
8786
|
+
}
|
|
8648
8787
|
}
|
|
8649
|
-
for (const [sourceKey, { row,
|
|
8788
|
+
for (const [sourceKey, { row, leaving, arriving }] of byHour) {
|
|
8650
8789
|
const held = await this.resident(sourceKey, row.deviceId);
|
|
8651
8790
|
if (held === null) {
|
|
8652
8791
|
this.logger.warn("recorder: hour detail unavailable — this relocation is REFUSED and nothing is deleted; the segments stay where they are", {
|
|
@@ -8654,7 +8793,7 @@ var SegmentHourLedger = class SegmentHourLedger {
|
|
|
8654
8793
|
meta: {
|
|
8655
8794
|
key: sourceKey,
|
|
8656
8795
|
toLocationId,
|
|
8657
|
-
paths:
|
|
8796
|
+
paths: leaving.size
|
|
8658
8797
|
}
|
|
8659
8798
|
});
|
|
8660
8799
|
return false;
|
|
@@ -8667,12 +8806,12 @@ var SegmentHourLedger = class SegmentHourLedger {
|
|
|
8667
8806
|
meta: {
|
|
8668
8807
|
key: targetKey,
|
|
8669
8808
|
fromLocationId: row.locationId,
|
|
8670
|
-
paths:
|
|
8809
|
+
paths: arriving.size
|
|
8671
8810
|
}
|
|
8672
8811
|
});
|
|
8673
8812
|
return false;
|
|
8674
8813
|
}
|
|
8675
|
-
const merged = uniquePaths([...target?.paths ?? [], ...
|
|
8814
|
+
const merged = uniquePaths([...target?.paths ?? [], ...arriving]);
|
|
8676
8815
|
await this.ledger.put(segmentHourRow({
|
|
8677
8816
|
key: targetKey,
|
|
8678
8817
|
deviceId: row.deviceId,
|
|
@@ -8681,7 +8820,7 @@ var SegmentHourLedger = class SegmentHourLedger {
|
|
|
8681
8820
|
hourStartMs: held.hourStartMs,
|
|
8682
8821
|
paths: merged
|
|
8683
8822
|
}));
|
|
8684
|
-
const next = held.paths.filter((p) => !
|
|
8823
|
+
const next = held.paths.filter((p) => !leaving.has(p));
|
|
8685
8824
|
if (next.length === 0) await this.ledger.forget(sourceKey);
|
|
8686
8825
|
else await this.ledger.put(segmentHourRow({
|
|
8687
8826
|
...held,
|