@camstack/addon-pipeline 1.2.171 → 1.2.172

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.
Files changed (38) hide show
  1. package/dist/audio-analyzer/index.js +2 -2
  2. package/dist/audio-analyzer/index.mjs +2 -2
  3. package/dist/detection-pipeline/index.js +5 -5
  4. package/dist/detection-pipeline/index.mjs +4 -4
  5. package/dist/{dist-D0liXHO7.mjs → dist-A-CKFNg9.mjs} +142 -1
  6. package/dist/{dist-M39Js6iu.js → dist-CpmqDTel.js} +142 -1
  7. package/dist/{lazy-sharp-CO-c2L9_.js → lazy-sharp-c_IKosOs.js} +1 -1
  8. package/dist/{local-frame-registry-CHUbcz6r.js → local-frame-registry-CHzo5v0z.js} +1 -1
  9. package/dist/{local-frame-registry--_WjAPa2.mjs → local-frame-registry-DuEPtfBk.mjs} +1 -1
  10. package/dist/motion-wasm/index.js +2 -2
  11. package/dist/motion-wasm/index.mjs +1 -1
  12. package/dist/{node-CQ6VBSrE.mjs → node-CNhb6GOd.mjs} +1 -1
  13. package/dist/{node-Byy6tlFm.js → node-DudW4uSe.js} +1 -1
  14. package/dist/pipeline-runner/index.js +63 -6
  15. package/dist/pipeline-runner/index.mjs +62 -5
  16. package/dist/{process-memory-CH3OIHHe.js → process-memory-CcWK6O93.js} +1 -1
  17. package/dist/{process-memory-DjLHImhM.mjs → process-memory-DVPPoQS1.mjs} +1 -1
  18. package/dist/recorder/index.js +97 -13
  19. package/dist/recorder/index.mjs +97 -13
  20. package/dist/{segment-demux-js-Bmy3u2VM.mjs → segment-demux-js-B0MPr5g4.mjs} +1 -1
  21. package/dist/{segment-demux-js-B0KzROD9.js → segment-demux-js-ChcjdSdF.js} +1 -1
  22. package/dist/session-decode/decode-worker-child.js +2 -2
  23. package/dist/session-decode/decode-worker-child.mjs +1 -1
  24. package/dist/stream-broker/_stub.js +2 -2
  25. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CN6ybZtQ.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DDhnhOI4.mjs} +3 -3
  26. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BVpZlsT7.mjs +26 -0
  27. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CwP-r0hs.mjs +26 -0
  28. package/dist/stream-broker/demux-worker-child.js +1 -1
  29. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  30. package/dist/stream-broker/{hostInit-Dq40Ieaf.mjs → hostInit-CrI9kLNo.mjs} +3 -3
  31. package/dist/stream-broker/index.js +87 -4
  32. package/dist/stream-broker/index.mjs +87 -4
  33. package/dist/stream-broker/remoteEntry.js +1 -1
  34. package/dist/{worker-protocol-CAWMqnxs.mjs → worker-protocol-BuUyu8aI.mjs} +1 -1
  35. package/dist/{worker-protocol-NB-CjUQf.js → worker-protocol-IC_mPIhk.js} +1 -1
  36. package/package.json +8 -1
  37. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BjYSKqCM.mjs +0 -26
  38. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-E0nHxt6U.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-M39Js6iu.js");
6
- const require_process_memory = require("../process-memory-CH3OIHHe.js");
5
+ const require_dist = require("../dist-CpmqDTel.js");
6
+ const require_process_memory = require("../process-memory-CcWK6O93.js");
7
7
  let node_fs = require("node:fs");
8
8
  node_fs = require_dist.__toESM(node_fs);
9
9
  let node_path = require("node:path");
@@ -1,6 +1,6 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { A as audioAnalysisCapability, It as hydrateSchema, S as PoolMemoryWatchdog, _t as resolvePoolMemoryPolicy, j as audioAnalyzerCapability, jt as BaseAddon, n as AUDIO_BACKEND_CHOICES, nt as mapAudioLabelToMacro, s as DEFAULT_AUDIO_ANALYZER_CONFIG, v as HF_BASE_URL, wt as errMsg } from "../dist-D0liXHO7.mjs";
3
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DjLHImhM.mjs";
2
+ import { A as audioAnalysisCapability, It as hydrateSchema, S as PoolMemoryWatchdog, _t as resolvePoolMemoryPolicy, j as audioAnalyzerCapability, jt as BaseAddon, n as AUDIO_BACKEND_CHOICES, nt as mapAudioLabelToMacro, s as DEFAULT_AUDIO_ANALYZER_CONFIG, v as HF_BASE_URL, wt as errMsg } from "../dist-A-CKFNg9.mjs";
3
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DVPPoQS1.mjs";
4
4
  import * as fs from "node:fs";
5
5
  import * as path$1 from "node:path";
6
6
  import { downloadFile } from "@camstack/system/addon-utils";
@@ -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-M39Js6iu.js");
6
- const require_node = require("../node-Byy6tlFm.js");
7
- const require_local_frame_registry = require("../local-frame-registry-CHUbcz6r.js");
8
- const require_lazy_sharp = require("../lazy-sharp-CO-c2L9_.js");
5
+ const require_dist = require("../dist-CpmqDTel.js");
6
+ const require_node = require("../node-DudW4uSe.js");
7
+ const require_local_frame_registry = require("../local-frame-registry-CHzo5v0z.js");
8
+ const require_lazy_sharp = require("../lazy-sharp-c_IKosOs.js");
9
9
  const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-DaUBcb13.js");
10
- const require_process_memory = require("../process-memory-CH3OIHHe.js");
10
+ const require_process_memory = require("../process-memory-CcWK6O93.js");
11
11
  let node_fs = require("node:fs");
12
12
  node_fs = require_dist.__toESM(node_fs);
13
13
  let node_path = require("node:path");
@@ -1,10 +1,10 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { Bt as nodePin, Ft as createEvent, It as hydrateSchema, Kt as array, O as YAMNET_TO_MACRO, Q as inferModelProvider, Qt as object, S as PoolMemoryWatchdog, St as supportedRuntimes$1, Vt as parseJsonUnknown, W as detectionPipelineCapability, Wt as sleep, Y as evaluateZoneRules, _t as resolvePoolMemoryPolicy, at as overlayClusterStepSettings, c as DEFAULT_CLUSTER_STEP_MODELS, ct as pickClusterStepSettings, dt as pipelineExecutorCapability, en as string, et as loadContributionCapability, ht as resolveClusterStepModelId, jt as BaseAddon, l as DEFAULT_CLUSTER_STEP_SETTINGS, m as DEVICE_BACKEND_TO_FORMAT, nn as EventCategory, q as enumerateInferenceDevices, st as pickClusterStepModels, t as APPLE_SA_TO_MACRO, tn as union, wt as errMsg, yt as runtimeDevices$1, z as defaultDeviceFor$1 } from "../dist-D0liXHO7.mjs";
3
- import { a as readProcessCost } from "../node-CQ6VBSrE.mjs";
4
- import { a as getDefaultModelForFormat, c as getStepDefinition, i as ALL_STEPS, l as resolveModelForFormat, o as getDefaultModelForFormatFromDef, r as ALL_PIPELINE_STEPS, s as getStep, t as localFrameRegistry, u as landmarkPrecisionVerdict } from "../local-frame-registry--_WjAPa2.mjs";
2
+ import { Bt as nodePin, Ft as createEvent, It as hydrateSchema, Kt as array, O as YAMNET_TO_MACRO, Q as inferModelProvider, Qt as object, S as PoolMemoryWatchdog, St as supportedRuntimes$1, Vt as parseJsonUnknown, W as detectionPipelineCapability, Wt as sleep, Y as evaluateZoneRules, _t as resolvePoolMemoryPolicy, at as overlayClusterStepSettings, c as DEFAULT_CLUSTER_STEP_MODELS, ct as pickClusterStepSettings, dt as pipelineExecutorCapability, en as string, et as loadContributionCapability, ht as resolveClusterStepModelId, jt as BaseAddon, l as DEFAULT_CLUSTER_STEP_SETTINGS, m as DEVICE_BACKEND_TO_FORMAT, nn as EventCategory, q as enumerateInferenceDevices, st as pickClusterStepModels, t as APPLE_SA_TO_MACRO, tn as union, wt as errMsg, yt as runtimeDevices$1, z as defaultDeviceFor$1 } from "../dist-A-CKFNg9.mjs";
3
+ import { a as readProcessCost } from "../node-CNhb6GOd.mjs";
4
+ import { a as getDefaultModelForFormat, c as getStepDefinition, i as ALL_STEPS, l as resolveModelForFormat, o as getDefaultModelForFormatFromDef, r as ALL_PIPELINE_STEPS, s as getStep, t as localFrameRegistry, u as landmarkPrecisionVerdict } from "../local-frame-registry-DuEPtfBk.mjs";
5
5
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
6
6
  import { n as startEventLoopStallMonitor } from "../event-loop-stall-monitor-DXLNBMkY.mjs";
7
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DjLHImhM.mjs";
7
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DVPPoQS1.mjs";
8
8
  import * as fs from "node:fs";
9
9
  import * as path$1 from "node:path";
10
10
  import { spawn } from "node:child_process";
@@ -12061,6 +12061,89 @@ var LocationStatSchema = object({
12061
12061
  fileCount: number(),
12062
12062
  present: boolean()
12063
12063
  });
12064
+ /** Lifecycle of a backup run. Terminal states: succeeded / failed / cancelled. */
12065
+ var BackupRunStateSchema = _enum([
12066
+ "queued",
12067
+ "running",
12068
+ "succeeded",
12069
+ "failed",
12070
+ "cancelled"
12071
+ ]);
12072
+ /**
12073
+ * Where a running backup currently is. `queued` before it starts,
12074
+ * `building` while the tar.gz is being staged, `uploading` during the
12075
+ * per-destination fan-out, `done` once terminal.
12076
+ */
12077
+ var BackupRunPhaseSchema = _enum([
12078
+ "queued",
12079
+ "building",
12080
+ "uploading",
12081
+ "done"
12082
+ ]);
12083
+ /**
12084
+ * Observable state of one backup run — readable WHILE it runs via
12085
+ * `backup.listRuns`. This is what makes the execution queue and
12086
+ * `backup.cancel` usable: the 2026-09-04 incident (two concurrent
12087
+ * multi-GB builds, staging 5.1 GB → 18 GB, load 62) was only
12088
+ * diagnosable with `du` because nothing reported that runs existed or
12089
+ * how large the staged archive had grown.
12090
+ */
12091
+ var BackupRunSchema = object({
12092
+ /** Stable run id — the handle `backup.cancel` takes. */
12093
+ id: string(),
12094
+ state: BackupRunStateSchema,
12095
+ phase: BackupRunPhaseSchema,
12096
+ /**
12097
+ * Resolved destination location ids. Empty while queued (targets are
12098
+ * resolved when the run starts, against the then-current policies).
12099
+ */
12100
+ destinationIds: array(string()).readonly(),
12101
+ label: string().optional(),
12102
+ /** ms-epoch when the run was submitted (trigger call / schedule fire). */
12103
+ requestedAt: number(),
12104
+ /** ms-epoch when the run left the queue and started building. */
12105
+ startedAt: number().optional(),
12106
+ /** ms-epoch when the run reached a terminal state. */
12107
+ finishedAt: number().optional(),
12108
+ /** Compressed bytes of the staging archive written so far. */
12109
+ stagedBytes: number(),
12110
+ /** Final staged archive size, once the build phase completes. */
12111
+ archiveSizeBytes: number().optional(),
12112
+ /** Bytes pushed to the destination currently uploading. */
12113
+ uploadedBytes: number(),
12114
+ /** Destinations where the archive fully landed (uploaded + indexed). */
12115
+ completedDestinationIds: array(string()).readonly(),
12116
+ /** Destinations that failed during the fan-out. */
12117
+ failedDestinationIds: array(string()).readonly(),
12118
+ /** Failure message when `state === 'failed'`. */
12119
+ error: string().optional(),
12120
+ /**
12121
+ * 1-based place in the execution queue — 1 = runs next. Present only
12122
+ * while `state === 'queued'`. Stamped by the orchestrator from the
12123
+ * queue's OWN pending order, never derived from timestamps, so the
12124
+ * UI cannot show an order the executor will not honour.
12125
+ */
12126
+ queuePosition: number().int().min(1).optional()
12127
+ });
12128
+ /**
12129
+ * Result of `backup.trigger`. The call still resolves when the run
12130
+ * terminates (compat with schedule-driven runs and the admin UI), but
12131
+ * it now names the run and says whether it had to WAIT: a trigger that
12132
+ * arrives while another run is in flight is enqueued (or joined onto
12133
+ * an identical already-queued run), never started concurrently.
12134
+ */
12135
+ var BackupTriggerResultSchema = object({
12136
+ /** The run this trigger mapped to — poll it via `listRuns`, stop it via `cancel`. */
12137
+ runId: string(),
12138
+ /** True when the run waited behind an in-flight run instead of starting immediately. */
12139
+ queued: boolean(),
12140
+ /** True when this trigger was coalesced onto an identical already-queued run. */
12141
+ joined: boolean(),
12142
+ /** True when the run was cancelled before completing every destination. */
12143
+ cancelled: boolean(),
12144
+ /** One entry per destination the archive landed at (partial on cancel). */
12145
+ entries: array(BackupEntrySchema).readonly()
12146
+ });
12064
12147
  /**
12065
12148
  * A backup schedule — the N:M "entry" that binds one cron cadence to a
12066
12149
  * SET of destination locations. Supersedes the per-location cron on
@@ -12108,7 +12191,10 @@ method(_void(), array(BackupDestinationInfoSchema).readonly(), { auth: "admin" }
12108
12191
  * retention (manual runs).
12109
12192
  */
12110
12193
  retentionCount: number().int().min(1).max(1e3).optional()
12111
- }).optional(), array(BackupEntrySchema).readonly(), {
12194
+ }).optional(), BackupTriggerResultSchema, {
12195
+ kind: "mutation",
12196
+ auth: "admin"
12197
+ }), method(_void(), array(BackupRunSchema).readonly(), { auth: "admin" }), method(object({ runId: string() }), object({ cancelled: boolean() }), {
12112
12198
  kind: "mutation",
12113
12199
  auth: "admin"
12114
12200
  }), method(_void(), array(BackupEntrySchema).readonly(), { auth: "admin" }), method(_void(), array(LocationStatSchema).readonly(), { auth: "admin" }), method(object({
@@ -12836,6 +12922,38 @@ var streamBrokerCapability = {
12836
12922
  auth: "admin"
12837
12923
  }),
12838
12924
  /**
12925
+ * The HARDWARE behind a device number was replaced
12926
+ * (`deviceManager.migrateDevice`). Forget every piece of broker state that
12927
+ * described the old box, so the next catalog pull derives everything from
12928
+ * the camera that is actually there:
12929
+ *
12930
+ * - every `derived:*` stream definition — a derived is authored against a
12931
+ * specific profile layout, and against the wrong hardware its feeder
12932
+ * respawns forever (observed at attempt 2732 on the live hub,
12933
+ * 2026-09-01);
12934
+ * - the profile-slot assignment entry, PURGED (not unassigned — unassign
12935
+ * marks the slot manual, which would pin the stale choice instead of
12936
+ * letting `computeInitialAssignment` re-derive it);
12937
+ * - the probe snapshots (`<deviceId>/…` — probed codec/resolution of the
12938
+ * old hardware);
12939
+ * - the persisted RTSP token rows for the device's brokers (keyed
12940
+ * `<deviceId>/<camStreamId>`; the stream ids change with the hardware,
12941
+ * so the rows are dead URLs).
12942
+ *
12943
+ * An RPC, deliberately — an event is telemetry and may be dropped (D8),
12944
+ * and a dropped forget leaves a feeder respawning against a stream that
12945
+ * does not exist.
12946
+ */
12947
+ forgetDeviceHardware: method(object({ deviceId: number().int().nonnegative() }), object({
12948
+ derivedStreamsDeleted: array(string()).readonly(),
12949
+ assignmentsPurged: boolean(),
12950
+ probeSnapshotsDropped: number().int().nonnegative(),
12951
+ rtspTokenRowsDeleted: number().int().nonnegative()
12952
+ }), {
12953
+ kind: "mutation",
12954
+ auth: "admin"
12955
+ }),
12956
+ /**
12839
12957
  * Render a short GIF or MP4 from the broker's PRE-BUFFER around an instant.
12840
12958
  *
12841
12959
  * The pre-buffer is the only source that already holds the seconds BEFORE
@@ -32555,6 +32673,12 @@ Object.freeze({
32555
32673
  addonId: null,
32556
32674
  access: "create"
32557
32675
  },
32676
+ "backup.cancel": {
32677
+ capName: "backup",
32678
+ capScope: "system",
32679
+ addonId: null,
32680
+ access: "create"
32681
+ },
32558
32682
  "backup.delete": {
32559
32683
  capName: "backup",
32560
32684
  capScope: "system",
@@ -32597,6 +32721,12 @@ Object.freeze({
32597
32721
  addonId: null,
32598
32722
  access: "view"
32599
32723
  },
32724
+ "backup.listRuns": {
32725
+ capName: "backup",
32726
+ capScope: "system",
32727
+ addonId: null,
32728
+ access: "view"
32729
+ },
32600
32730
  "backup.listSchedules": {
32601
32731
  capName: "backup",
32602
32732
  capScope: "system",
@@ -37163,6 +37293,12 @@ Object.freeze({
37163
37293
  addonId: null,
37164
37294
  access: "create"
37165
37295
  },
37296
+ "streamBroker.forgetDeviceHardware": {
37297
+ capName: "stream-broker",
37298
+ capScope: "system",
37299
+ addonId: null,
37300
+ access: "delete"
37301
+ },
37166
37302
  "streamBroker.getAllRtspEntries": {
37167
37303
  capName: "stream-broker",
37168
37304
  capScope: "system",
@@ -39621,6 +39757,11 @@ Object.freeze({
39621
39757
  form: "single",
39622
39758
  optional: false
39623
39759
  }],
39760
+ "streamBroker.forgetDeviceHardware": [{
39761
+ name: "deviceId",
39762
+ form: "single",
39763
+ optional: false
39764
+ }],
39624
39765
  "streamBroker.getDeviceAudioMute": [{
39625
39766
  name: "deviceId",
39626
39767
  form: "single",
@@ -12084,6 +12084,89 @@ var LocationStatSchema = object({
12084
12084
  fileCount: number(),
12085
12085
  present: boolean()
12086
12086
  });
12087
+ /** Lifecycle of a backup run. Terminal states: succeeded / failed / cancelled. */
12088
+ var BackupRunStateSchema = _enum([
12089
+ "queued",
12090
+ "running",
12091
+ "succeeded",
12092
+ "failed",
12093
+ "cancelled"
12094
+ ]);
12095
+ /**
12096
+ * Where a running backup currently is. `queued` before it starts,
12097
+ * `building` while the tar.gz is being staged, `uploading` during the
12098
+ * per-destination fan-out, `done` once terminal.
12099
+ */
12100
+ var BackupRunPhaseSchema = _enum([
12101
+ "queued",
12102
+ "building",
12103
+ "uploading",
12104
+ "done"
12105
+ ]);
12106
+ /**
12107
+ * Observable state of one backup run — readable WHILE it runs via
12108
+ * `backup.listRuns`. This is what makes the execution queue and
12109
+ * `backup.cancel` usable: the 2026-09-04 incident (two concurrent
12110
+ * multi-GB builds, staging 5.1 GB → 18 GB, load 62) was only
12111
+ * diagnosable with `du` because nothing reported that runs existed or
12112
+ * how large the staged archive had grown.
12113
+ */
12114
+ var BackupRunSchema = object({
12115
+ /** Stable run id — the handle `backup.cancel` takes. */
12116
+ id: string(),
12117
+ state: BackupRunStateSchema,
12118
+ phase: BackupRunPhaseSchema,
12119
+ /**
12120
+ * Resolved destination location ids. Empty while queued (targets are
12121
+ * resolved when the run starts, against the then-current policies).
12122
+ */
12123
+ destinationIds: array(string()).readonly(),
12124
+ label: string().optional(),
12125
+ /** ms-epoch when the run was submitted (trigger call / schedule fire). */
12126
+ requestedAt: number(),
12127
+ /** ms-epoch when the run left the queue and started building. */
12128
+ startedAt: number().optional(),
12129
+ /** ms-epoch when the run reached a terminal state. */
12130
+ finishedAt: number().optional(),
12131
+ /** Compressed bytes of the staging archive written so far. */
12132
+ stagedBytes: number(),
12133
+ /** Final staged archive size, once the build phase completes. */
12134
+ archiveSizeBytes: number().optional(),
12135
+ /** Bytes pushed to the destination currently uploading. */
12136
+ uploadedBytes: number(),
12137
+ /** Destinations where the archive fully landed (uploaded + indexed). */
12138
+ completedDestinationIds: array(string()).readonly(),
12139
+ /** Destinations that failed during the fan-out. */
12140
+ failedDestinationIds: array(string()).readonly(),
12141
+ /** Failure message when `state === 'failed'`. */
12142
+ error: string().optional(),
12143
+ /**
12144
+ * 1-based place in the execution queue — 1 = runs next. Present only
12145
+ * while `state === 'queued'`. Stamped by the orchestrator from the
12146
+ * queue's OWN pending order, never derived from timestamps, so the
12147
+ * UI cannot show an order the executor will not honour.
12148
+ */
12149
+ queuePosition: number().int().min(1).optional()
12150
+ });
12151
+ /**
12152
+ * Result of `backup.trigger`. The call still resolves when the run
12153
+ * terminates (compat with schedule-driven runs and the admin UI), but
12154
+ * it now names the run and says whether it had to WAIT: a trigger that
12155
+ * arrives while another run is in flight is enqueued (or joined onto
12156
+ * an identical already-queued run), never started concurrently.
12157
+ */
12158
+ var BackupTriggerResultSchema = object({
12159
+ /** The run this trigger mapped to — poll it via `listRuns`, stop it via `cancel`. */
12160
+ runId: string(),
12161
+ /** True when the run waited behind an in-flight run instead of starting immediately. */
12162
+ queued: boolean(),
12163
+ /** True when this trigger was coalesced onto an identical already-queued run. */
12164
+ joined: boolean(),
12165
+ /** True when the run was cancelled before completing every destination. */
12166
+ cancelled: boolean(),
12167
+ /** One entry per destination the archive landed at (partial on cancel). */
12168
+ entries: array(BackupEntrySchema).readonly()
12169
+ });
12087
12170
  /**
12088
12171
  * A backup schedule — the N:M "entry" that binds one cron cadence to a
12089
12172
  * SET of destination locations. Supersedes the per-location cron on
@@ -12131,7 +12214,10 @@ method(_void(), array(BackupDestinationInfoSchema).readonly(), { auth: "admin" }
12131
12214
  * retention (manual runs).
12132
12215
  */
12133
12216
  retentionCount: number().int().min(1).max(1e3).optional()
12134
- }).optional(), array(BackupEntrySchema).readonly(), {
12217
+ }).optional(), BackupTriggerResultSchema, {
12218
+ kind: "mutation",
12219
+ auth: "admin"
12220
+ }), method(_void(), array(BackupRunSchema).readonly(), { auth: "admin" }), method(object({ runId: string() }), object({ cancelled: boolean() }), {
12135
12221
  kind: "mutation",
12136
12222
  auth: "admin"
12137
12223
  }), method(_void(), array(BackupEntrySchema).readonly(), { auth: "admin" }), method(_void(), array(LocationStatSchema).readonly(), { auth: "admin" }), method(object({
@@ -12859,6 +12945,38 @@ var streamBrokerCapability = {
12859
12945
  auth: "admin"
12860
12946
  }),
12861
12947
  /**
12948
+ * The HARDWARE behind a device number was replaced
12949
+ * (`deviceManager.migrateDevice`). Forget every piece of broker state that
12950
+ * described the old box, so the next catalog pull derives everything from
12951
+ * the camera that is actually there:
12952
+ *
12953
+ * - every `derived:*` stream definition — a derived is authored against a
12954
+ * specific profile layout, and against the wrong hardware its feeder
12955
+ * respawns forever (observed at attempt 2732 on the live hub,
12956
+ * 2026-09-01);
12957
+ * - the profile-slot assignment entry, PURGED (not unassigned — unassign
12958
+ * marks the slot manual, which would pin the stale choice instead of
12959
+ * letting `computeInitialAssignment` re-derive it);
12960
+ * - the probe snapshots (`<deviceId>/…` — probed codec/resolution of the
12961
+ * old hardware);
12962
+ * - the persisted RTSP token rows for the device's brokers (keyed
12963
+ * `<deviceId>/<camStreamId>`; the stream ids change with the hardware,
12964
+ * so the rows are dead URLs).
12965
+ *
12966
+ * An RPC, deliberately — an event is telemetry and may be dropped (D8),
12967
+ * and a dropped forget leaves a feeder respawning against a stream that
12968
+ * does not exist.
12969
+ */
12970
+ forgetDeviceHardware: method(object({ deviceId: number().int().nonnegative() }), object({
12971
+ derivedStreamsDeleted: array(string()).readonly(),
12972
+ assignmentsPurged: boolean(),
12973
+ probeSnapshotsDropped: number().int().nonnegative(),
12974
+ rtspTokenRowsDeleted: number().int().nonnegative()
12975
+ }), {
12976
+ kind: "mutation",
12977
+ auth: "admin"
12978
+ }),
12979
+ /**
12862
12980
  * Render a short GIF or MP4 from the broker's PRE-BUFFER around an instant.
12863
12981
  *
12864
12982
  * The pre-buffer is the only source that already holds the seconds BEFORE
@@ -32578,6 +32696,12 @@ Object.freeze({
32578
32696
  addonId: null,
32579
32697
  access: "create"
32580
32698
  },
32699
+ "backup.cancel": {
32700
+ capName: "backup",
32701
+ capScope: "system",
32702
+ addonId: null,
32703
+ access: "create"
32704
+ },
32581
32705
  "backup.delete": {
32582
32706
  capName: "backup",
32583
32707
  capScope: "system",
@@ -32620,6 +32744,12 @@ Object.freeze({
32620
32744
  addonId: null,
32621
32745
  access: "view"
32622
32746
  },
32747
+ "backup.listRuns": {
32748
+ capName: "backup",
32749
+ capScope: "system",
32750
+ addonId: null,
32751
+ access: "view"
32752
+ },
32623
32753
  "backup.listSchedules": {
32624
32754
  capName: "backup",
32625
32755
  capScope: "system",
@@ -37186,6 +37316,12 @@ Object.freeze({
37186
37316
  addonId: null,
37187
37317
  access: "create"
37188
37318
  },
37319
+ "streamBroker.forgetDeviceHardware": {
37320
+ capName: "stream-broker",
37321
+ capScope: "system",
37322
+ addonId: null,
37323
+ access: "delete"
37324
+ },
37189
37325
  "streamBroker.getAllRtspEntries": {
37190
37326
  capName: "stream-broker",
37191
37327
  capScope: "system",
@@ -39644,6 +39780,11 @@ Object.freeze({
39644
39780
  form: "single",
39645
39781
  optional: false
39646
39782
  }],
39783
+ "streamBroker.forgetDeviceHardware": [{
39784
+ name: "deviceId",
39785
+ form: "single",
39786
+ optional: false
39787
+ }],
39647
39788
  "streamBroker.getDeviceAudioMute": [{
39648
39789
  name: "deviceId",
39649
39790
  form: "single",
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-M39Js6iu.js");
1
+ const require_dist = require("./dist-CpmqDTel.js");
2
2
  let node_path = require("node:path");
3
3
  node_path = require_dist.__toESM(node_path);
4
4
  let node_url = require("node:url");
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-M39Js6iu.js");
1
+ const require_dist = require("./dist-CpmqDTel.js");
2
2
  let node_crypto = require("node:crypto");
3
3
  //#region src/detection-pipeline/registry/model-catalogs.ts
4
4
  var HF_REPO = "camstack/camstack-models";
@@ -1,4 +1,4 @@
1
- import { M as audioKindId, Z as hfModelUrl, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-D0liXHO7.mjs";
1
+ import { M as audioKindId, Z as hfModelUrl, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-A-CKFNg9.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  //#region src/detection-pipeline/registry/model-catalogs.ts
4
4
  var HF_REPO = "camstack/camstack-models";
@@ -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-M39Js6iu.js");
6
- const require_lazy_sharp = require("../lazy-sharp-CO-c2L9_.js");
5
+ const require_dist = require("../dist-CpmqDTel.js");
6
+ const require_lazy_sharp = require("../lazy-sharp-c_IKosOs.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-D0liXHO7.mjs";
1
+ import { It as hydrateSchema, Pt as DeviceType, Y as evaluateZoneRules, it as motionDetectionCapability, jt as BaseAddon } from "../dist-A-CKFNg9.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-D0liXHO7.mjs";
1
+ import { Dt as buildFfmpegArgs, Et as Fmp4BoxSplitter, kt as isSoftwareDecode, wt as errMsg } from "./dist-A-CKFNg9.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import "node:fs";
4
4
  import "node:path";
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-M39Js6iu.js");
1
+ const require_dist = require("./dist-CpmqDTel.js");
2
2
  let node_crypto = require("node:crypto");
3
3
  let node_fs = require("node:fs");
4
4
  node_fs = require_dist.__toESM(node_fs, 1);
@@ -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-M39Js6iu.js");
6
- const require_node = require("../node-Byy6tlFm.js");
7
- const require_local_frame_registry = require("../local-frame-registry-CHUbcz6r.js");
8
- const require_worker_protocol = require("../worker-protocol-NB-CjUQf.js");
5
+ const require_dist = require("../dist-CpmqDTel.js");
6
+ const require_node = require("../node-DudW4uSe.js");
7
+ const require_local_frame_registry = require("../local-frame-registry-CHzo5v0z.js");
8
+ const require_worker_protocol = require("../worker-protocol-IC_mPIhk.js");
9
9
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
10
- const require_lazy_sharp = require("../lazy-sharp-CO-c2L9_.js");
10
+ const require_lazy_sharp = require("../lazy-sharp-c_IKosOs.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");
@@ -18,6 +18,51 @@ let node_url = require("node:url");
18
18
  let node_perf_hooks = require("node:perf_hooks");
19
19
  let node_os = require("node:os");
20
20
  node_os = require_dist.__toESM(node_os);
21
+ //#region src/pipeline-runner/first-detection-frame.ts
22
+ /**
23
+ * How long a camera waits, after `attachCamera`, before a decoded frame
24
+ * actually reaches the detection queue.
25
+ *
26
+ * The orchestrator already measures `session motion → attach latency` and it
27
+ * is small — 11, 13 and 18 ms across three consecutive sessions on the same
28
+ * camera. What nothing measured is the NEXT leg: from the attach to the first
29
+ * frame the detector is given. An operator reporting "detection starts late"
30
+ * is describing that leg, and answering them required reading the timestamps
31
+ * of unrelated INFO lines and inferring — which produced a wrong first answer
32
+ * (the absence of a `frame processed` line means the frame produced nothing
33
+ * notable, not that no frame arrived).
34
+ *
35
+ * One number, once per attach, so a slow start is a value rather than an
36
+ * inference.
37
+ */
38
+ /** Pending attach marks, keyed by device. */
39
+ var FirstDetectionFrameTimer = class {
40
+ attachedAt = /* @__PURE__ */ new Map();
41
+ /** A camera attached. Replaces any pending mark: the newest attach is the
42
+ * one the next frame belongs to. */
43
+ markAttached(deviceId, nowMs) {
44
+ this.attachedAt.set(deviceId, nowMs);
45
+ }
46
+ /**
47
+ * A decoded frame was admitted to the detection queue. Returns the elapsed
48
+ * ms since the attach the FIRST time it is called after one, and `null`
49
+ * every time after — so the caller logs once per attach, not once per frame.
50
+ */
51
+ takeLatency(deviceId, nowMs) {
52
+ const at = this.attachedAt.get(deviceId);
53
+ if (at === void 0) return null;
54
+ this.attachedAt.delete(deviceId);
55
+ return Math.max(0, nowMs - at);
56
+ }
57
+ /** A camera detached with no frame ever admitted — drop the mark so the
58
+ * NEXT attach is not measured from this one. Returns whether one was
59
+ * pending, which is itself the interesting fact: a session that ran and
60
+ * fed the detector nothing. */
61
+ forget(deviceId) {
62
+ return this.attachedAt.delete(deviceId);
63
+ }
64
+ };
65
+ //#endregion
21
66
  //#region src/session-decode/fork-decode-worker.ts
22
67
  /** Absolute path to the built decode-worker child entry (a vite build entry). */
23
68
  var CHILD_ENTRY_PATH = (0, node_url.fileURLToPath)(new URL("../session-decode/decode-worker-child.js", require("url").pathToFileURL(__filename).href));
@@ -6434,6 +6479,8 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
6434
6479
  if (config.motionSources.includes("analyzer")) attachment.motionUnsubscribe = await this.subscribeMotionFrames(config);
6435
6480
  const stepsCount = config.steps?.length ?? 0;
6436
6481
  const dispatch = stepsCount > 0 ? `runPipeline(${stepsCount}step${stepsCount === 1 ? "" : "s"})` : config.steps !== void 0 ? "skip(0steps)" : "runFrame(legacy)";
6482
+ const engineLabel = "node-local";
6483
+ this.firstDetectionFrame.markAttached(config.deviceId, Date.now());
6437
6484
  this.ctx.logger.info("attachCamera", {
6438
6485
  tags: { deviceId: config.deviceId },
6439
6486
  meta: {
@@ -6443,7 +6490,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
6443
6490
  detectionFps: config.detectionFps,
6444
6491
  motionSources: config.motionSources,
6445
6492
  dispatch,
6446
- engine: "node-local"
6493
+ engine: engineLabel
6447
6494
  }
6448
6495
  });
6449
6496
  return { success: true };
@@ -7292,10 +7339,20 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
7292
7339
  * no second dial, no second decode, no GPU). Mirrors the shm shared-motion
7293
7340
  * seam (`subscribeMotionFrames` `shared` branch).
7294
7341
  */
7342
+ /** Attach → first decoded detection frame, one line per attach. See
7343
+ * {@link FirstDetectionFrameTimer}. */
7344
+ firstDetectionFrame = new FirstDetectionFrameTimer();
7295
7345
  enqueueSharedDetectionFrame(deviceId, frame, handle, reservation) {
7296
7346
  const runner = this.runner;
7297
7347
  if (!runner) return false;
7298
7348
  const admitted = reservation ? reservation.detection && runner.enqueueReservedDetectionFrame(deviceId, frame, handle) : runner.enqueueDetectionFrame(deviceId, frame, handle);
7349
+ if (admitted) {
7350
+ const latencyMs = this.firstDetectionFrame.takeLatency(deviceId, Date.now());
7351
+ if (latencyMs !== null) this.ctx?.logger.info("session-decode: first detection frame after attach", {
7352
+ tags: { deviceId },
7353
+ meta: { latencyMs }
7354
+ });
7355
+ }
7299
7356
  if (reservation?.motion) runner.enqueueMotionFrame(deviceId, rgbFrameToGrayFrame(frame), void 0);
7300
7357
  else if (!reservation) {
7301
7358
  const sink = this.sharedMotionSinks.get(deviceId);