@camstack/addon-pipeline 1.2.602 → 1.2.603
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 +3 -3
- package/dist/audio-analyzer/index.mjs +3 -3
- package/dist/{custom-model-catalog-CVvdKnH2.js → custom-model-catalog-BAnOZBOf.js} +2 -2
- package/dist/{custom-model-catalog--ms2wSDI.mjs → custom-model-catalog-Dv09Pvq_.mjs} +2 -2
- package/dist/detection-pipeline/index.js +4 -4
- package/dist/detection-pipeline/index.mjs +4 -4
- package/dist/{dist-BmSyTuy4.mjs → dist-CsCflIM1.mjs} +287 -45
- package/dist/{dist-B4HyxJe1.js → dist-DvXRw_dM.js} +292 -44
- package/dist/{model-catalogs-Bj0f2Obs.js → model-catalogs-B95QZeYt.js} +1 -1
- package/dist/{model-catalogs-OnXVUgQY.mjs → model-catalogs-aTwF92Re.mjs} +1 -1
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/{node--4HtlkFo.mjs → node-DAp5MmRJ.mjs} +1 -1
- package/dist/{node-DfuKhWUZ.js → node-DxAtLKEn.js} +1 -1
- package/dist/pipeline-runner/index.js +3 -3
- package/dist/pipeline-runner/index.mjs +3 -3
- package/dist/{process-memory-uf7ZfkSz.mjs → process-memory-1_2L6U3Q.mjs} +1 -1
- package/dist/{process-memory-BZ1_q3g3.js → process-memory-CmWDOMmE.js} +1 -1
- package/dist/recorder/index.js +240 -40
- package/dist/recorder/index.mjs +240 -40
- package/dist/{segment-demux-js-CURD3CEv.mjs → segment-demux-js-DQo9qSHm.mjs} +1 -1
- package/dist/{segment-demux-js-C7fMqBGZ.js → segment-demux-js-HagdockZ.js} +1 -1
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-Cd6rjANN.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DoBB8xYv.mjs} +3 -3
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DkA9R3eo.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-RrTYeVaZ.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-CV-FMXnr.mjs → hostInit-DaZYQhX4.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/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-DUPQbxcH.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-CGcD3ujP.mjs +0 -26
package/dist/recorder/index.js
CHANGED
|
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../chunk-emK7D4bc.js");
|
|
6
|
-
const require_dist = require("../dist-
|
|
7
|
-
const require_node = require("../node-
|
|
6
|
+
const require_dist = require("../dist-DvXRw_dM.js");
|
|
7
|
+
const require_node = require("../node-DxAtLKEn.js");
|
|
8
8
|
const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
|
|
9
9
|
const require_restream_intent = require("../restream-intent-7uDNqMKs.js");
|
|
10
10
|
let node_crypto = require("node:crypto");
|
|
@@ -6737,6 +6737,15 @@ Object.freeze({
|
|
|
6737
6737
|
"valueType": "boolean"
|
|
6738
6738
|
}],
|
|
6739
6739
|
"dishwasher": [
|
|
6740
|
+
{
|
|
6741
|
+
"path": "availability",
|
|
6742
|
+
"valueType": "enum",
|
|
6743
|
+
"enumValues": [
|
|
6744
|
+
"available",
|
|
6745
|
+
"offline",
|
|
6746
|
+
"description-missing"
|
|
6747
|
+
]
|
|
6748
|
+
},
|
|
6740
6749
|
{
|
|
6741
6750
|
"path": "state",
|
|
6742
6751
|
"valueType": "enum",
|
|
@@ -6749,12 +6758,35 @@ Object.freeze({
|
|
|
6749
6758
|
"unavailable"
|
|
6750
6759
|
]
|
|
6751
6760
|
},
|
|
6761
|
+
{
|
|
6762
|
+
"path": "operationState",
|
|
6763
|
+
"valueType": "enum",
|
|
6764
|
+
"enumValues": [
|
|
6765
|
+
"Inactive",
|
|
6766
|
+
"Ready",
|
|
6767
|
+
"DelayedStart",
|
|
6768
|
+
"Run",
|
|
6769
|
+
"Pause",
|
|
6770
|
+
"ActionRequired",
|
|
6771
|
+
"Finished",
|
|
6772
|
+
"Error",
|
|
6773
|
+
"Aborting"
|
|
6774
|
+
]
|
|
6775
|
+
},
|
|
6752
6776
|
{
|
|
6753
6777
|
"path": "program",
|
|
6754
6778
|
"valueType": "string"
|
|
6755
6779
|
},
|
|
6756
6780
|
{
|
|
6757
|
-
"path": "
|
|
6781
|
+
"path": "selectedProgram",
|
|
6782
|
+
"valueType": "string"
|
|
6783
|
+
},
|
|
6784
|
+
{
|
|
6785
|
+
"path": "remainingSeconds",
|
|
6786
|
+
"valueType": "number"
|
|
6787
|
+
},
|
|
6788
|
+
{
|
|
6789
|
+
"path": "delayedStartSeconds",
|
|
6758
6790
|
"valueType": "number"
|
|
6759
6791
|
},
|
|
6760
6792
|
{
|
|
@@ -6765,14 +6797,30 @@ Object.freeze({
|
|
|
6765
6797
|
"path": "doorOpen",
|
|
6766
6798
|
"valueType": "boolean"
|
|
6767
6799
|
},
|
|
6800
|
+
{
|
|
6801
|
+
"path": "doorLocked",
|
|
6802
|
+
"valueType": "boolean"
|
|
6803
|
+
},
|
|
6768
6804
|
{
|
|
6769
6805
|
"path": "remoteStartAllowed",
|
|
6770
6806
|
"valueType": "boolean"
|
|
6771
6807
|
},
|
|
6808
|
+
{
|
|
6809
|
+
"path": "remoteControlActive",
|
|
6810
|
+
"valueType": "boolean"
|
|
6811
|
+
},
|
|
6812
|
+
{
|
|
6813
|
+
"path": "localControlActive",
|
|
6814
|
+
"valueType": "boolean"
|
|
6815
|
+
},
|
|
6772
6816
|
{
|
|
6773
6817
|
"path": "powerOn",
|
|
6774
6818
|
"valueType": "boolean"
|
|
6775
6819
|
},
|
|
6820
|
+
{
|
|
6821
|
+
"path": "powerState",
|
|
6822
|
+
"valueType": "string"
|
|
6823
|
+
},
|
|
6776
6824
|
{
|
|
6777
6825
|
"path": "saltLevel",
|
|
6778
6826
|
"valueType": "enum",
|
|
@@ -10422,6 +10470,22 @@ var LOCATE_HYDRATE_MARGIN_MS = 6e4;
|
|
|
10422
10470
|
*/
|
|
10423
10471
|
var WINDOW_READ_MAX_BYTES = 2e7;
|
|
10424
10472
|
/** Empty "no playback" manifest. */
|
|
10473
|
+
/**
|
|
10474
|
+
* Start a footage move only while no single-location repoint holds an
|
|
10475
|
+
* overlapping physical root (the storage orchestrator owns that claim).
|
|
10476
|
+
*/
|
|
10477
|
+
function startFootageMover(deps, engine, input) {
|
|
10478
|
+
const ask = deps.moverClearance;
|
|
10479
|
+
if (ask === void 0) return Promise.resolve(engine.start(input));
|
|
10480
|
+
return require_dist.startMoverUnderClearance({
|
|
10481
|
+
clearance: ask,
|
|
10482
|
+
start: () => engine.start(input),
|
|
10483
|
+
cancel: (jobId) => {
|
|
10484
|
+
engine.cancel(jobId);
|
|
10485
|
+
},
|
|
10486
|
+
locationIds: [input.fromLocationId, input.toLocationId]
|
|
10487
|
+
});
|
|
10488
|
+
}
|
|
10425
10489
|
function noPlayback(deviceId) {
|
|
10426
10490
|
return {
|
|
10427
10491
|
deviceId,
|
|
@@ -11224,13 +11288,13 @@ function buildRecordingProvider(deps) {
|
|
|
11224
11288
|
startStorageMigrationMove: async (input) => {
|
|
11225
11289
|
if (!deps.relocate) throw new Error("relocation unavailable on this node");
|
|
11226
11290
|
deps.assertStorageMigrationLease?.(input.leaseId);
|
|
11227
|
-
return { jobId: deps.relocate
|
|
11291
|
+
return { jobId: await startFootageMover(deps, deps.relocate, input) };
|
|
11228
11292
|
},
|
|
11229
11293
|
getStorageMigrationMoveStatus: async ({ jobId }) => deps.relocate?.list().find((job) => job.jobId === jobId) ?? null,
|
|
11230
11294
|
cancelStorageMigrationMove: async ({ jobId }) => ({ cancelled: deps.relocate?.cancel(jobId) ?? false }),
|
|
11231
11295
|
relocateFootage: async (input) => {
|
|
11232
11296
|
if (!deps.relocate) throw new Error("relocation unavailable on this node");
|
|
11233
|
-
const jobId = deps.relocate
|
|
11297
|
+
const jobId = await startFootageMover(deps, deps.relocate, input);
|
|
11234
11298
|
deps.logger.info("recorder: relocate job enqueued", {
|
|
11235
11299
|
...input.deviceId !== void 0 ? { tags: { deviceId: input.deviceId } } : {},
|
|
11236
11300
|
meta: {
|
|
@@ -15206,6 +15270,135 @@ function startPeriodicPass(deps) {
|
|
|
15206
15270
|
};
|
|
15207
15271
|
}
|
|
15208
15272
|
//#endregion
|
|
15273
|
+
//#region src/recorder/addon/placement-alerts.ts
|
|
15274
|
+
var SEVERITY = {
|
|
15275
|
+
unusable: "critical",
|
|
15276
|
+
"shared-root": "error",
|
|
15277
|
+
"writer-restart": "warning"
|
|
15278
|
+
};
|
|
15279
|
+
var TITLE = {
|
|
15280
|
+
unusable: "Recordings storage location unusable",
|
|
15281
|
+
"shared-root": "Recordings storage locations share one disk",
|
|
15282
|
+
"writer-restart": "Recording placement waiting on a writer restart"
|
|
15283
|
+
};
|
|
15284
|
+
/** Stable identity of one fault: the alert id AND its episode key. */
|
|
15285
|
+
function placementAlertId(locationId, reason) {
|
|
15286
|
+
return `recorder-placement:${locationId}:${reason}`;
|
|
15287
|
+
}
|
|
15288
|
+
var PlacementAlertPublisher = class {
|
|
15289
|
+
deps;
|
|
15290
|
+
episodes = /* @__PURE__ */ new Map();
|
|
15291
|
+
constructor(deps) {
|
|
15292
|
+
this.deps = deps;
|
|
15293
|
+
}
|
|
15294
|
+
/** Raise (or refresh) the alert of one fault. Advisory: never throws. */
|
|
15295
|
+
raise(input) {
|
|
15296
|
+
const id = placementAlertId(input.locationId, input.reason);
|
|
15297
|
+
const now = this.deps.now();
|
|
15298
|
+
const episode = this.episodes.get(id) ?? {
|
|
15299
|
+
createdAt: now,
|
|
15300
|
+
count: 0
|
|
15301
|
+
};
|
|
15302
|
+
episode.count += 1;
|
|
15303
|
+
this.episodes.set(id, episode);
|
|
15304
|
+
const alert = {
|
|
15305
|
+
id,
|
|
15306
|
+
category: "storage",
|
|
15307
|
+
severity: SEVERITY[input.reason],
|
|
15308
|
+
title: TITLE[input.reason],
|
|
15309
|
+
message: input.detail,
|
|
15310
|
+
status: "active",
|
|
15311
|
+
read: false,
|
|
15312
|
+
createdAt: episode.createdAt,
|
|
15313
|
+
updatedAt: now,
|
|
15314
|
+
source: {
|
|
15315
|
+
type: "addon",
|
|
15316
|
+
id: this.deps.sourceId
|
|
15317
|
+
},
|
|
15318
|
+
metadata: {
|
|
15319
|
+
locationId: input.locationId,
|
|
15320
|
+
nodeId: this.deps.nodeId,
|
|
15321
|
+
reason: input.reason,
|
|
15322
|
+
episodeKey: id,
|
|
15323
|
+
count: episode.count
|
|
15324
|
+
}
|
|
15325
|
+
};
|
|
15326
|
+
this.deps.port.emit(alert).catch((err) => {
|
|
15327
|
+
this.deps.logger.warn("recorder: storage alert emit failed (advisory)", { meta: {
|
|
15328
|
+
locationId: input.locationId,
|
|
15329
|
+
reason: input.reason,
|
|
15330
|
+
error: require_dist.errMsg(err)
|
|
15331
|
+
} });
|
|
15332
|
+
});
|
|
15333
|
+
}
|
|
15334
|
+
/** The fault is gone: close its alert. A fault that never fired is a no-op. */
|
|
15335
|
+
resolve(locationId, reason) {
|
|
15336
|
+
const id = placementAlertId(locationId, reason);
|
|
15337
|
+
const episode = this.episodes.get(id);
|
|
15338
|
+
if (episode === void 0) return;
|
|
15339
|
+
this.episodes.delete(id);
|
|
15340
|
+
this.deps.logger.info("recorder: storage fault recovered — closing its alert", { meta: {
|
|
15341
|
+
locationId,
|
|
15342
|
+
reason,
|
|
15343
|
+
alertId: id,
|
|
15344
|
+
raisedTimes: episode.count
|
|
15345
|
+
} });
|
|
15346
|
+
this.deps.port.update({
|
|
15347
|
+
alertId: id,
|
|
15348
|
+
patch: {
|
|
15349
|
+
status: "completed",
|
|
15350
|
+
read: true,
|
|
15351
|
+
updatedAt: this.deps.now()
|
|
15352
|
+
}
|
|
15353
|
+
}).catch((err) => {
|
|
15354
|
+
this.deps.logger.warn("recorder: closing a recovered storage alert failed (advisory)", { meta: {
|
|
15355
|
+
locationId,
|
|
15356
|
+
reason,
|
|
15357
|
+
alertId: id,
|
|
15358
|
+
error: require_dist.errMsg(err)
|
|
15359
|
+
} });
|
|
15360
|
+
});
|
|
15361
|
+
}
|
|
15362
|
+
};
|
|
15363
|
+
/**
|
|
15364
|
+
* Keeps the `writer-restart` alerts true to the live set of pending writer
|
|
15365
|
+
* moves: one alert per PLANNED location, raised while any camera is still
|
|
15366
|
+
* pending for it, completed when none is (the move landed, or the plan was
|
|
15367
|
+
* dropped - the target was drained or deleted).
|
|
15368
|
+
*/
|
|
15369
|
+
var WriterRestartAlerts = class {
|
|
15370
|
+
publisher;
|
|
15371
|
+
logger;
|
|
15372
|
+
previous = [];
|
|
15373
|
+
constructor(publisher, logger) {
|
|
15374
|
+
this.publisher = publisher;
|
|
15375
|
+
this.logger = logger;
|
|
15376
|
+
}
|
|
15377
|
+
update(moves) {
|
|
15378
|
+
const byLocation = /* @__PURE__ */ new Map();
|
|
15379
|
+
for (const move of moves) byLocation.set(move.plannedFor, (byLocation.get(move.plannedFor) ?? 0) + 1);
|
|
15380
|
+
for (const [locationId, count] of byLocation) this.publisher.raise({
|
|
15381
|
+
locationId,
|
|
15382
|
+
reason: "writer-restart",
|
|
15383
|
+
detail: `${String(count)} recording profile(s) are planned for ${locationId} and will keep writing to their current location until each camera next attaches. Continuously-recording cameras never re-attach on their own.`
|
|
15384
|
+
});
|
|
15385
|
+
const stillPending = new Set(moves.map((m) => `${String(m.deviceId)}:${m.profile}>${m.plannedFor}`));
|
|
15386
|
+
for (const gone of this.previous) {
|
|
15387
|
+
if (stillPending.has(`${String(gone.deviceId)}:${gone.profile}>${gone.plannedFor}`)) continue;
|
|
15388
|
+
this.logger.info("recorder placement: writer-restart no longer pending for this camera", {
|
|
15389
|
+
tags: { deviceId: gone.deviceId },
|
|
15390
|
+
meta: {
|
|
15391
|
+
locationId: gone.plannedFor,
|
|
15392
|
+
profile: gone.profile,
|
|
15393
|
+
writingTo: gone.writingTo
|
|
15394
|
+
}
|
|
15395
|
+
});
|
|
15396
|
+
}
|
|
15397
|
+
for (const gone of this.previous) if (!byLocation.has(gone.plannedFor)) this.publisher.resolve(gone.plannedFor, "writer-restart");
|
|
15398
|
+
this.previous = moves;
|
|
15399
|
+
}
|
|
15400
|
+
};
|
|
15401
|
+
//#endregion
|
|
15209
15402
|
//#region src/recorder/addon/placement-guard.ts
|
|
15210
15403
|
/**
|
|
15211
15404
|
* Same-root guard for recordings placement.
|
|
@@ -15850,6 +16043,9 @@ var PlacementService = class {
|
|
|
15850
16043
|
verified = /* @__PURE__ */ new Set();
|
|
15851
16044
|
/** Locations the probe declared unusable — re-probed after a change. */
|
|
15852
16045
|
unusable = /* @__PURE__ */ new Set();
|
|
16046
|
+
/** Locations with an OPEN mount-fault alert. Survives a re-resolve (unlike
|
|
16047
|
+
* `unusable`): the alert closes only when the probe verifies the volume. */
|
|
16048
|
+
faulted = /* @__PURE__ */ new Set();
|
|
15853
16049
|
/** Locations whose capacity could not be read, by reason. One line per
|
|
15854
16050
|
* distinct fault (this is on the 30 s tick) and one when it clears. */
|
|
15855
16051
|
capacityFaults = /* @__PURE__ */ new Map();
|
|
@@ -16364,6 +16560,7 @@ var PlacementService = class {
|
|
|
16364
16560
|
return chosen;
|
|
16365
16561
|
}
|
|
16366
16562
|
this.verified.add(chosen.id);
|
|
16563
|
+
this.reportMountRecovered(chosen.id);
|
|
16367
16564
|
if (result.outcome === "adopted" && result.foundVolumeId !== null) {
|
|
16368
16565
|
try {
|
|
16369
16566
|
await rememberVolumeId(this.deps.state, chosen.id, result.foundVolumeId);
|
|
@@ -16387,6 +16584,13 @@ var PlacementService = class {
|
|
|
16387
16584
|
}
|
|
16388
16585
|
return chosen;
|
|
16389
16586
|
}
|
|
16587
|
+
/** The probe verified a location that had an open fault: close its alert. */
|
|
16588
|
+
reportMountRecovered(locationId) {
|
|
16589
|
+
if (!this.faulted.delete(locationId)) return;
|
|
16590
|
+
try {
|
|
16591
|
+
this.deps.recovered?.(locationId);
|
|
16592
|
+
} catch {}
|
|
16593
|
+
}
|
|
16390
16594
|
/** One loud line + one alert + one audit row per mount fault. */
|
|
16391
16595
|
reportMountFault(result, deviceId) {
|
|
16392
16596
|
this.deps.logger.error("recorder placement: storage volume MISMATCH — the disk under this location is not the one it last wrote to; failing over", {
|
|
@@ -16400,8 +16604,10 @@ var PlacementService = class {
|
|
|
16400
16604
|
}
|
|
16401
16605
|
});
|
|
16402
16606
|
try {
|
|
16607
|
+
this.faulted.add(result.locationId);
|
|
16403
16608
|
this.deps.alert?.({
|
|
16404
16609
|
locationId: result.locationId,
|
|
16610
|
+
reason: "unusable",
|
|
16405
16611
|
detail: result.detail
|
|
16406
16612
|
});
|
|
16407
16613
|
} catch {}
|
|
@@ -23659,6 +23865,7 @@ var RecorderV2Addon = class extends require_dist.BaseAddon {
|
|
|
23659
23865
|
state: this.placementStore(),
|
|
23660
23866
|
opsLog,
|
|
23661
23867
|
alert: (input) => this.emitPlacementAlert(input),
|
|
23868
|
+
recovered: (locationId) => this.resolvePlacementAlert(locationId),
|
|
23662
23869
|
capacityFor: (location) => this.locationCapacity(location.root),
|
|
23663
23870
|
usedOnLocation: async (locationId) => (await this.segmentHours?.accountingForLocations(new Set([locationId])))?.bytes ?? 0,
|
|
23664
23871
|
dailyBytesFor: (deviceId, profile) => this.dailyBytesFor(deviceId, profile)
|
|
@@ -23860,6 +24067,7 @@ var RecorderV2Addon = class extends require_dist.BaseAddon {
|
|
|
23860
24067
|
resumeForStorageMigration: (leaseId) => this.resumeForStorageMigration(leaseId),
|
|
23861
24068
|
refreshStorageLocationsForMigration: (leaseId) => this.refreshStorageLocationsForMigration(leaseId),
|
|
23862
24069
|
assertStorageMigrationLease: (leaseId) => this.assertStorageMigrationLease(leaseId),
|
|
24070
|
+
moverClearance: (locationIds) => this.ctx.api.storageMigration.moverClearance.query({ locationIds }),
|
|
23863
24071
|
placementSnapshot: () => this.placementSnapshot(),
|
|
23864
24072
|
placementView: () => {
|
|
23865
24073
|
const placement = this.placement;
|
|
@@ -24835,6 +25043,7 @@ var RecorderV2Addon = class extends require_dist.BaseAddon {
|
|
|
24835
25043
|
} });
|
|
24836
25044
|
this.emitPlacementAlert({
|
|
24837
25045
|
locationId: conflict.keptId,
|
|
25046
|
+
reason: "shared-root",
|
|
24838
25047
|
detail: `Storage locations ${[conflict.keptId, ...conflict.demotedIds].join(", ")} all resolve to ${conflict.root}. Only ${conflict.keptId} will be written to.`
|
|
24839
25048
|
});
|
|
24840
25049
|
}
|
|
@@ -24973,6 +25182,7 @@ var RecorderV2Addon = class extends require_dist.BaseAddon {
|
|
|
24973
25182
|
const signature = pendingMovesSignature(moves);
|
|
24974
25183
|
if (signature === this.pendingWriterMoves) return;
|
|
24975
25184
|
this.pendingWriterMoves = signature;
|
|
25185
|
+
this.writerRestartAlerts().update(moves);
|
|
24976
25186
|
if (moves.length === 0) return;
|
|
24977
25187
|
for (const move of moves) this.ctx.logger.warn("recorder placement: this camera is PLANNED for another location and its writer will not move until it next attaches", {
|
|
24978
25188
|
tags: { deviceId: move.deviceId },
|
|
@@ -24983,12 +25193,6 @@ var RecorderV2Addon = class extends require_dist.BaseAddon {
|
|
|
24983
25193
|
hint: "a continuously-recording camera never re-attaches on its own — toggle its recording switch, or restart the recorder, to apply the plan (each costs one gap on that camera)"
|
|
24984
25194
|
}
|
|
24985
25195
|
});
|
|
24986
|
-
this.emitAlert({
|
|
24987
|
-
severity: "warning",
|
|
24988
|
-
title: "Recording placement waiting on a writer restart",
|
|
24989
|
-
message: `${String(moves.length)} recording profile(s) are planned for a different storage location and will keep writing to their current one until each camera next attaches. Continuously-recording cameras never re-attach on their own.`,
|
|
24990
|
-
locationId: moves[0]?.plannedFor ?? ""
|
|
24991
|
-
});
|
|
24992
25196
|
}
|
|
24993
25197
|
/**
|
|
24994
25198
|
* A placement pass that plans NOTHING says so — once per episode.
|
|
@@ -25210,38 +25414,34 @@ var RecorderV2Addon = class extends require_dist.BaseAddon {
|
|
|
25210
25414
|
/**
|
|
25211
25415
|
* Surface a storage-placement fault on the liveness/alert surface. STRICTLY
|
|
25212
25416
|
* best-effort: the alerts cap is a nice-to-have and an unmounted disk must
|
|
25213
|
-
* still be shouted about in the log even when it is unreachable.
|
|
25417
|
+
* still be shouted about in the log even when it is unreachable. One row per
|
|
25418
|
+
* (location, reason) episode - see `placement-alerts.ts`.
|
|
25214
25419
|
*/
|
|
25215
25420
|
emitPlacementAlert(input) {
|
|
25216
|
-
this.
|
|
25217
|
-
|
|
25218
|
-
|
|
25219
|
-
|
|
25220
|
-
|
|
25221
|
-
|
|
25222
|
-
|
|
25223
|
-
|
|
25224
|
-
|
|
25225
|
-
|
|
25226
|
-
this.
|
|
25227
|
-
|
|
25228
|
-
|
|
25229
|
-
|
|
25230
|
-
|
|
25231
|
-
|
|
25232
|
-
|
|
25233
|
-
read: false,
|
|
25234
|
-
createdAt: Date.now(),
|
|
25235
|
-
updatedAt: Date.now(),
|
|
25236
|
-
source: {
|
|
25237
|
-
type: "addon",
|
|
25238
|
-
id: this.ctx.id
|
|
25421
|
+
this.placementAlerts().raise(input);
|
|
25422
|
+
}
|
|
25423
|
+
/** The faulted location passed its volume probe again: close its alert. */
|
|
25424
|
+
resolvePlacementAlert(locationId) {
|
|
25425
|
+
this.placementAlerts().resolve(locationId, "unusable");
|
|
25426
|
+
}
|
|
25427
|
+
placementAlertPublisher = null;
|
|
25428
|
+
writerRestartAlertSync = null;
|
|
25429
|
+
writerRestartAlerts() {
|
|
25430
|
+
this.writerRestartAlertSync ??= new WriterRestartAlerts(this.placementAlerts(), this.ctx.logger);
|
|
25431
|
+
return this.writerRestartAlertSync;
|
|
25432
|
+
}
|
|
25433
|
+
placementAlerts() {
|
|
25434
|
+
this.placementAlertPublisher ??= new PlacementAlertPublisher({
|
|
25435
|
+
port: {
|
|
25436
|
+
emit: (alert) => this.ctx.api.alerts.emit.mutate(alert),
|
|
25437
|
+
update: (input) => this.ctx.api.alerts.update.mutate(input)
|
|
25239
25438
|
},
|
|
25240
|
-
|
|
25241
|
-
|
|
25242
|
-
|
|
25243
|
-
|
|
25244
|
-
})
|
|
25439
|
+
logger: this.ctx.logger,
|
|
25440
|
+
sourceId: this.ctx.id,
|
|
25441
|
+
nodeId: this.nodeId,
|
|
25442
|
+
now: () => Date.now()
|
|
25443
|
+
});
|
|
25444
|
+
return this.placementAlertPublisher;
|
|
25245
25445
|
}
|
|
25246
25446
|
async pauseForStorageMigration(leaseId) {
|
|
25247
25447
|
if (this.storageMigrationLeaseId !== null && this.storageMigrationLeaseId !== leaseId) throw new Error("recorder is already paused by another storage migration");
|