@camstack/addon-pipeline 1.2.270 → 1.2.272

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 (33) hide show
  1. package/dist/audio-analyzer/index.js +2 -2
  2. package/dist/audio-analyzer/index.mjs +2 -2
  3. package/dist/{default-detection-model-pXamampo.mjs → default-detection-model-DqrqHCuw.mjs} +1 -1
  4. package/dist/{default-detection-model-BfMsW_XK.js → default-detection-model-kQnvoRyv.js} +1 -1
  5. package/dist/detection-pipeline/index.js +4 -4
  6. package/dist/detection-pipeline/index.mjs +4 -4
  7. package/dist/{dist-Cqf-U6EN.mjs → dist-DBHsAlUE.mjs} +102 -7
  8. package/dist/{dist-CkNVb7Zh.js → dist-DygcLvgG.js} +102 -7
  9. package/dist/motion-wasm/index.js +1 -1
  10. package/dist/motion-wasm/index.mjs +1 -1
  11. package/dist/{node-CqC8R84-.js → node-CACCuE7t.js} +53 -1
  12. package/dist/{node-jLmcbaar.mjs → node-j_3VvNQJ.mjs} +53 -1
  13. package/dist/pipeline-runner/index.js +3 -3
  14. package/dist/pipeline-runner/index.mjs +3 -3
  15. package/dist/{process-memory-B1YHg1_g.mjs → process-memory-DcoIQGG5.mjs} +1 -1
  16. package/dist/{process-memory-D7LlWXty.js → process-memory-fse8NnRi.js} +1 -1
  17. package/dist/recorder/index.js +24 -7
  18. package/dist/recorder/index.mjs +24 -7
  19. package/dist/{segment-demux-js-Bu-_Q7Um.js → segment-demux-js-Ce24Y2G0.js} +1 -1
  20. package/dist/{segment-demux-js-B2TLcR_g.mjs → segment-demux-js-DSgNEMf6.mjs} +1 -1
  21. package/dist/stream-broker/_stub.js +1 -1
  22. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DZlxPoTV.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BSZUBMBY.mjs} +2 -2
  23. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-_bHa4uUp.mjs +26 -0
  24. package/dist/stream-broker/demux-worker-child.js +1 -1
  25. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  26. package/dist/stream-broker/{hostInit-DFerKhvZ.mjs → hostInit-lVR0hopj.mjs} +2 -2
  27. package/dist/stream-broker/index.js +3 -3
  28. package/dist/stream-broker/index.mjs +3 -3
  29. package/dist/stream-broker/remoteEntry.js +1 -1
  30. package/package.json +1 -1
  31. package/python/inference_pool.py +163 -34
  32. package/python/test_inference_pool_cache_lock.py +185 -0
  33. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DJVznXRG.mjs +0 -26
@@ -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-CkNVb7Zh.js");
7
- const require_process_memory = require("../process-memory-D7LlWXty.js");
6
+ const require_dist = require("../dist-DygcLvgG.js");
7
+ const require_process_memory = require("../process-memory-fse8NnRi.js");
8
8
  let node_fs = require("node:fs");
9
9
  node_fs = require_chunk.__toESM(node_fs);
10
10
  let node_path = require("node:path");
@@ -1,6 +1,6 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { $t as hydrateSchema, Jt as audioChunkBytesPerSample, Lt as errMsg, N as audioAnalysisCapability, Ot as resolvePoolMemoryPolicy, P as audioAnalyzerCapability, Qt as expandAudioChunkToF32le, Wt as BaseAddon, bn as EventCategory, n as AUDIO_BACKEND_CHOICES, ot as mapAudioLabelToMacro, rn as nodePin, s as DEFAULT_AUDIO_ANALYZER_CONFIG, w as PoolMemoryWatchdog, y as HF_BASE_URL } from "../dist-Cqf-U6EN.mjs";
3
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-B1YHg1_g.mjs";
2
+ import { $t as hydrateSchema, Jt as audioChunkBytesPerSample, Lt as errMsg, N as audioAnalysisCapability, Ot as resolvePoolMemoryPolicy, P as audioAnalyzerCapability, Qt as expandAudioChunkToF32le, Wt as BaseAddon, bn as EventCategory, n as AUDIO_BACKEND_CHOICES, ot as mapAudioLabelToMacro, rn as nodePin, s as DEFAULT_AUDIO_ANALYZER_CONFIG, w as PoolMemoryWatchdog, y as HF_BASE_URL } from "../dist-DBHsAlUE.mjs";
3
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DcoIQGG5.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";
@@ -1,4 +1,4 @@
1
- import { F as audioKindId, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS, tt as hfModelUrl } from "./dist-Cqf-U6EN.mjs";
1
+ import { F as audioKindId, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS, tt as hfModelUrl } from "./dist-DBHsAlUE.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  //#region src/detection-pipeline/pipeline/landmark-precision-gate.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-CkNVb7Zh.js");
1
+ const require_dist = require("./dist-DygcLvgG.js");
2
2
  let node_crypto = require("node:crypto");
3
3
  //#region src/detection-pipeline/pipeline/landmark-precision-gate.ts
4
4
  /**
@@ -3,11 +3,11 @@ 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-CkNVb7Zh.js");
7
- const require_node = require("../node-CqC8R84-.js");
8
- const require_default_detection_model = require("../default-detection-model-BfMsW_XK.js");
6
+ const require_dist = require("../dist-DygcLvgG.js");
7
+ const require_node = require("../node-CACCuE7t.js");
8
+ const require_default_detection_model = require("../default-detection-model-kQnvoRyv.js");
9
9
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
10
- const require_process_memory = require("../process-memory-D7LlWXty.js");
10
+ const require_process_memory = require("../process-memory-fse8NnRi.js");
11
11
  let node_os = require("node:os");
12
12
  node_os = require_chunk.__toESM(node_os);
13
13
  let node_fs = require("node:fs");
@@ -1,9 +1,9 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { $t as hydrateSchema, At as runtimeDevices$1, Ft as supportedRuntimes$1, G as detectionPipelineCapability, J as enumerateInferenceDevices, Lt as errMsg, Ot as resolvePoolMemoryPolicy, Tt as resolveClusterStepModelId, V as defaultDeviceFor$1, Wt as BaseAddon, X as evaluateZoneRules, Yt as createEvent, bn as EventCategory, c as DEFAULT_CLUSTER_STEP_MODELS, gt as pickClusterStepSettings, hn as object, ht as pickClusterStepModels, in as parseJsonUnknown, it as loadContributionCapability, j as YAMNET_TO_MACRO, l as DEFAULT_CLUSTER_STEP_SETTINGS, ln as array, m as DEVICE_BACKEND_TO_FORMAT, nt as inferModelProvider, pt as overlayClusterStepSettings, rn as nodePin, sn as sleep, t as APPLE_SA_TO_MACRO, vn as string, w as PoolMemoryWatchdog, yn as union, yt as pipelineExecutorCapability } from "../dist-Cqf-U6EN.mjs";
3
- import { s as readProcessCost } from "../node-jLmcbaar.mjs";
4
- import { a as localFrameRegistry, c as ALL_STEPS, d as getStepDefinition, f as resolveModelForFormat, l as getDefaultModelForFormat, n as resolveDefaultDetectionModel, p as landmarkPrecisionVerdict, r as macroGateVerdict, s as ALL_PIPELINE_STEPS, u as getStep } from "../default-detection-model-pXamampo.mjs";
2
+ import { $t as hydrateSchema, At as runtimeDevices$1, Ft as supportedRuntimes$1, G as detectionPipelineCapability, J as enumerateInferenceDevices, Lt as errMsg, Ot as resolvePoolMemoryPolicy, Tt as resolveClusterStepModelId, V as defaultDeviceFor$1, Wt as BaseAddon, X as evaluateZoneRules, Yt as createEvent, bn as EventCategory, c as DEFAULT_CLUSTER_STEP_MODELS, gt as pickClusterStepSettings, hn as object, ht as pickClusterStepModels, in as parseJsonUnknown, it as loadContributionCapability, j as YAMNET_TO_MACRO, l as DEFAULT_CLUSTER_STEP_SETTINGS, ln as array, m as DEVICE_BACKEND_TO_FORMAT, nt as inferModelProvider, pt as overlayClusterStepSettings, rn as nodePin, sn as sleep, t as APPLE_SA_TO_MACRO, vn as string, w as PoolMemoryWatchdog, yn as union, yt as pipelineExecutorCapability } from "../dist-DBHsAlUE.mjs";
3
+ import { s as readProcessCost } from "../node-j_3VvNQJ.mjs";
4
+ import { a as localFrameRegistry, c as ALL_STEPS, d as getStepDefinition, f as resolveModelForFormat, l as getDefaultModelForFormat, n as resolveDefaultDetectionModel, p as landmarkPrecisionVerdict, r as macroGateVerdict, s as ALL_PIPELINE_STEPS, u as getStep } from "../default-detection-model-DqrqHCuw.mjs";
5
5
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
6
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-B1YHg1_g.mjs";
6
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DcoIQGG5.mjs";
7
7
  import * as os from "node:os";
8
8
  import * as fs from "node:fs";
9
9
  import * as path$1 from "node:path";
@@ -8943,6 +8943,7 @@ var CameraSwitchIdSchema = _enum([
8943
8943
  "device-audio",
8944
8944
  "broker-audio",
8945
8945
  "audio-analysis",
8946
+ "event-saving",
8946
8947
  "recording",
8947
8948
  "notifications"
8948
8949
  ]);
@@ -9425,11 +9426,31 @@ var RecordingBandTriggersSchema = RecordingTriggersSchema;
9425
9426
  * band engine's `applies` rule). `start`/`end` are `HH:MM`; an `end <= start`
9426
9427
  * span wraps past midnight (handled by the band engine).
9427
9428
  */
9429
+ /**
9430
+ * Whether a band's footage carries sound.
9431
+ *
9432
+ * The recorder has always attached with `audio: 'aac'`, so every band of every
9433
+ * camera recorded sound whether anyone wanted it or not. The broker already
9434
+ * serves the other answer — `audio: 'none'` takes the video-only `/muted`
9435
+ * restream — so this was a choice the product could always have offered.
9436
+ *
9437
+ * It belongs on the BAND rather than the camera because one camera can want
9438
+ * both: silent across the shop floor during opening hours, sound overnight.
9439
+ * And it applies to BOTH modes — an events band firing on motion has the same
9440
+ * question to answer as a continuous one.
9441
+ */
9442
+ var RecordingBandAudioSchema = _enum(["on", "muted"]);
9428
9443
  var RecordingBandSchema = object({
9429
9444
  days: array(RecordingWeekdaySchema),
9430
9445
  start: string().regex(HHMM),
9431
9446
  end: string().regex(HHMM),
9432
9447
  mode: RecordingBandModeSchema,
9448
+ /**
9449
+ * Sound, or silence. OPTIONAL and absent-means-`on`: every recording
9450
+ * written before this existed carried sound, and a band whose key is
9451
+ * missing must keep meaning what it meant. See {@link RecordingBandAudioSchema}.
9452
+ */
9453
+ audio: RecordingBandAudioSchema.optional(),
9433
9454
  triggers: RecordingBandTriggersSchema.optional(),
9434
9455
  /**
9435
9456
  * RETIRED (D381). A band no longer carries a pre-buffer of its own.
@@ -25765,10 +25786,9 @@ var ServerBootModeSchema = _enum([
25765
25786
  * - `idle` / `checking` / `staging` — steady / in-flight registry work.
25766
25787
  * - `pending-restart` — a version is staged and the node has NOT yet
25767
25788
  * restarted onto it (still running the OLD version).
25768
- * - `awaiting-confirmation` — the node HAS restarted onto the staged version
25769
- * (it is the active probation boot) and is waiting to confirm boot-health.
25770
- * Apply/rollback are refused in this state and the node must NOT be
25771
- * manually restarted, or the probation boot auto-rolls-back.
25789
+ * - `awaiting-confirmation` — RETIRED with the probation boot (single-copy
25790
+ * collapse, 2026-07-18). Kept in the enum so an older client still parses;
25791
+ * no provider emits it.
25772
25792
  */
25773
25793
  var ServerUpdateStateSchema = _enum([
25774
25794
  "idle",
@@ -25857,12 +25877,35 @@ var ServerRollbackInfoSchema = object({
25857
25877
  var ServerPackageStatusSchema = object({
25858
25878
  /** Root package name (`@camstack/server` on the hub). */
25859
25879
  packageName: string(),
25860
- /** Version of the code the running process ACTUALLY loaded. */
25880
+ /**
25881
+ * Version of the code THIS PROCESS loaded — captured once, at boot, from the
25882
+ * package.json of the copy the code was loaded from, and never re-read. A
25883
+ * copy replaced on disk under a live process must not move this number;
25884
+ * that divergence is what `installedVersion` is for. Before 2026-09-20 this
25885
+ * was a lazy disk read that would have followed such a swap silently.
25886
+ */
25861
25887
  runningVersion: string().nullable(),
25862
25888
  /** Node.js runtime version the node's process runs on (`process.versions.node`). */
25863
25889
  nodeRuntimeVersion: string().nullable(),
25864
25890
  /** Active data-dir root version; null when booted from seed/workspace. */
25865
25891
  activeVersion: string().nullable(),
25892
+ /**
25893
+ * Version of the root package in the data-root `current/` copy RIGHT NOW —
25894
+ * what the next boot would load if nothing is staged. Normally equal to
25895
+ * `runningVersion`; differs only when the copy on disk changed under the
25896
+ * live process. `null` when there is no data-root copy (baked seed or
25897
+ * workspace boot). Optional for version skew: an older provider omits it.
25898
+ */
25899
+ installedVersion: string().nullable().optional(),
25900
+ /**
25901
+ * True when the code that would run after a restart is NOT the code running
25902
+ * now: a version is staged (`pendingVersion`), or `installedVersion` differs
25903
+ * from `runningVersion`. Derived on every read, never stored. This is the
25904
+ * one field that lets an operator or a script say "1.2.353 is installed and
25905
+ * will run after a restart" instead of reading it off a number that means
25906
+ * "installed". Optional for version skew.
25907
+ */
25908
+ restartRequired: boolean().optional(),
25866
25909
  /** N-1 version kept for rollback; null when no previous version exists. */
25867
25910
  previousVersion: string().nullable(),
25868
25911
  /** Version of the immutable baked seed closure (image fallback). */
@@ -25897,19 +25940,71 @@ var ServerPackageStatusSchema = object({
25897
25940
  });
25898
25941
  var ServerUpdateCheckResultSchema = object({
25899
25942
  packageName: string(),
25943
+ /** Same meaning as on the status payload: what THIS process loaded. */
25900
25944
  runningVersion: string().nullable(),
25901
25945
  latestVersion: string().nullable(),
25946
+ /**
25947
+ * `latestVersion` is newer than `runningVersion` AND is not the version
25948
+ * already staged on this node. A staged-and-waiting version is not "an
25949
+ * update available" — applying it again is refused (`already-staged`), and
25950
+ * a button that announced "updating…" on this boolean then got refused
25951
+ * would be lying. It is reported through `pendingVersion` instead.
25952
+ */
25902
25953
  updateAvailable: boolean(),
25903
25954
  checkedAtMs: number(),
25904
25955
  /** Non-null when the registry lookup failed (offline, bad registry, …). */
25905
- error: string().nullable()
25956
+ error: string().nullable(),
25957
+ /**
25958
+ * Version staged on this node and awaiting its restart, when one is. Before
25959
+ * 2026-09-20 a check answered `{runningVersion, updateAvailable:false}` for a
25960
+ * node whose staged closure had never booted, and the caller had no way to
25961
+ * see the difference. Optional for version skew.
25962
+ */
25963
+ pendingVersion: string().nullable().optional(),
25964
+ /** See the status payload: staged, or installed-on-disk ≠ running. Optional for skew. */
25965
+ restartRequired: boolean().optional()
25906
25966
  });
25967
+ /**
25968
+ * What an action DID — the discriminant `accepted` cannot carry. Before
25969
+ * 2026-09-20 `applyServerUpdate` answered `accepted:false` both for a refusal
25970
+ * where nothing was wrong (already current, already staged) and for a staging
25971
+ * install that died on `npm error code ECONNRESET`; the only difference was
25972
+ * prose in `message`, and an operator restarted a container on the strength of
25973
+ * it, booting the previous version.
25974
+ *
25975
+ * - `staged` — the closure is installed and validated; the node
25976
+ * restarts to apply it (`restarting:true`). NOTHING
25977
+ * runs the new code until that restart completes.
25978
+ * - `restart-scheduled` — a plain, version-preserving restart was accepted.
25979
+ * - `already-current` — the target IS the running version; nothing done.
25980
+ * - `refused` — dropped by a gate; `reason` names which.
25981
+ * - `failed` — attempted and did not land; `error` says why.
25982
+ */
25983
+ var ServerUpdateOutcomeSchema = _enum([
25984
+ "staged",
25985
+ "restart-scheduled",
25986
+ "already-current",
25987
+ "refused",
25988
+ "failed"
25989
+ ]);
25907
25990
  var ServerUpdateActionResultSchema = object({
25908
25991
  accepted: boolean(),
25909
25992
  targetVersion: string().nullable(),
25910
25993
  /** True when a graceful restart was scheduled to apply the change. */
25911
25994
  restarting: boolean(),
25912
- message: string()
25995
+ message: string(),
25996
+ /** See {@link ServerUpdateOutcomeSchema}. Optional for version skew. */
25997
+ outcome: ServerUpdateOutcomeSchema.optional(),
25998
+ /**
25999
+ * Stable, greppable cause for `refused` / `failed` (the engine's
26000
+ * `UpdateRefusalReason`, `staging-failed`, …). `null` on success.
26001
+ */
26002
+ reason: string().nullable().optional(),
26003
+ /**
26004
+ * The failure itself, verbatim enough to act on (the npm output for a
26005
+ * staging install). Non-null only for `failed`.
26006
+ */
26007
+ error: string().nullable().optional()
25913
26008
  });
25914
26009
  method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), ServerUpdateCheckResultSchema, {
25915
26010
  kind: "mutation",
@@ -8943,6 +8943,7 @@ var CameraSwitchIdSchema = _enum([
8943
8943
  "device-audio",
8944
8944
  "broker-audio",
8945
8945
  "audio-analysis",
8946
+ "event-saving",
8946
8947
  "recording",
8947
8948
  "notifications"
8948
8949
  ]);
@@ -9425,11 +9426,31 @@ var RecordingBandTriggersSchema = RecordingTriggersSchema;
9425
9426
  * band engine's `applies` rule). `start`/`end` are `HH:MM`; an `end <= start`
9426
9427
  * span wraps past midnight (handled by the band engine).
9427
9428
  */
9429
+ /**
9430
+ * Whether a band's footage carries sound.
9431
+ *
9432
+ * The recorder has always attached with `audio: 'aac'`, so every band of every
9433
+ * camera recorded sound whether anyone wanted it or not. The broker already
9434
+ * serves the other answer — `audio: 'none'` takes the video-only `/muted`
9435
+ * restream — so this was a choice the product could always have offered.
9436
+ *
9437
+ * It belongs on the BAND rather than the camera because one camera can want
9438
+ * both: silent across the shop floor during opening hours, sound overnight.
9439
+ * And it applies to BOTH modes — an events band firing on motion has the same
9440
+ * question to answer as a continuous one.
9441
+ */
9442
+ var RecordingBandAudioSchema = _enum(["on", "muted"]);
9428
9443
  var RecordingBandSchema = object({
9429
9444
  days: array(RecordingWeekdaySchema),
9430
9445
  start: string().regex(HHMM),
9431
9446
  end: string().regex(HHMM),
9432
9447
  mode: RecordingBandModeSchema,
9448
+ /**
9449
+ * Sound, or silence. OPTIONAL and absent-means-`on`: every recording
9450
+ * written before this existed carried sound, and a band whose key is
9451
+ * missing must keep meaning what it meant. See {@link RecordingBandAudioSchema}.
9452
+ */
9453
+ audio: RecordingBandAudioSchema.optional(),
9433
9454
  triggers: RecordingBandTriggersSchema.optional(),
9434
9455
  /**
9435
9456
  * RETIRED (D381). A band no longer carries a pre-buffer of its own.
@@ -25765,10 +25786,9 @@ var ServerBootModeSchema = _enum([
25765
25786
  * - `idle` / `checking` / `staging` — steady / in-flight registry work.
25766
25787
  * - `pending-restart` — a version is staged and the node has NOT yet
25767
25788
  * restarted onto it (still running the OLD version).
25768
- * - `awaiting-confirmation` — the node HAS restarted onto the staged version
25769
- * (it is the active probation boot) and is waiting to confirm boot-health.
25770
- * Apply/rollback are refused in this state and the node must NOT be
25771
- * manually restarted, or the probation boot auto-rolls-back.
25789
+ * - `awaiting-confirmation` — RETIRED with the probation boot (single-copy
25790
+ * collapse, 2026-07-18). Kept in the enum so an older client still parses;
25791
+ * no provider emits it.
25772
25792
  */
25773
25793
  var ServerUpdateStateSchema = _enum([
25774
25794
  "idle",
@@ -25857,12 +25877,35 @@ var ServerRollbackInfoSchema = object({
25857
25877
  var ServerPackageStatusSchema = object({
25858
25878
  /** Root package name (`@camstack/server` on the hub). */
25859
25879
  packageName: string(),
25860
- /** Version of the code the running process ACTUALLY loaded. */
25880
+ /**
25881
+ * Version of the code THIS PROCESS loaded — captured once, at boot, from the
25882
+ * package.json of the copy the code was loaded from, and never re-read. A
25883
+ * copy replaced on disk under a live process must not move this number;
25884
+ * that divergence is what `installedVersion` is for. Before 2026-09-20 this
25885
+ * was a lazy disk read that would have followed such a swap silently.
25886
+ */
25861
25887
  runningVersion: string().nullable(),
25862
25888
  /** Node.js runtime version the node's process runs on (`process.versions.node`). */
25863
25889
  nodeRuntimeVersion: string().nullable(),
25864
25890
  /** Active data-dir root version; null when booted from seed/workspace. */
25865
25891
  activeVersion: string().nullable(),
25892
+ /**
25893
+ * Version of the root package in the data-root `current/` copy RIGHT NOW —
25894
+ * what the next boot would load if nothing is staged. Normally equal to
25895
+ * `runningVersion`; differs only when the copy on disk changed under the
25896
+ * live process. `null` when there is no data-root copy (baked seed or
25897
+ * workspace boot). Optional for version skew: an older provider omits it.
25898
+ */
25899
+ installedVersion: string().nullable().optional(),
25900
+ /**
25901
+ * True when the code that would run after a restart is NOT the code running
25902
+ * now: a version is staged (`pendingVersion`), or `installedVersion` differs
25903
+ * from `runningVersion`. Derived on every read, never stored. This is the
25904
+ * one field that lets an operator or a script say "1.2.353 is installed and
25905
+ * will run after a restart" instead of reading it off a number that means
25906
+ * "installed". Optional for version skew.
25907
+ */
25908
+ restartRequired: boolean().optional(),
25866
25909
  /** N-1 version kept for rollback; null when no previous version exists. */
25867
25910
  previousVersion: string().nullable(),
25868
25911
  /** Version of the immutable baked seed closure (image fallback). */
@@ -25897,19 +25940,71 @@ var ServerPackageStatusSchema = object({
25897
25940
  });
25898
25941
  var ServerUpdateCheckResultSchema = object({
25899
25942
  packageName: string(),
25943
+ /** Same meaning as on the status payload: what THIS process loaded. */
25900
25944
  runningVersion: string().nullable(),
25901
25945
  latestVersion: string().nullable(),
25946
+ /**
25947
+ * `latestVersion` is newer than `runningVersion` AND is not the version
25948
+ * already staged on this node. A staged-and-waiting version is not "an
25949
+ * update available" — applying it again is refused (`already-staged`), and
25950
+ * a button that announced "updating…" on this boolean then got refused
25951
+ * would be lying. It is reported through `pendingVersion` instead.
25952
+ */
25902
25953
  updateAvailable: boolean(),
25903
25954
  checkedAtMs: number(),
25904
25955
  /** Non-null when the registry lookup failed (offline, bad registry, …). */
25905
- error: string().nullable()
25956
+ error: string().nullable(),
25957
+ /**
25958
+ * Version staged on this node and awaiting its restart, when one is. Before
25959
+ * 2026-09-20 a check answered `{runningVersion, updateAvailable:false}` for a
25960
+ * node whose staged closure had never booted, and the caller had no way to
25961
+ * see the difference. Optional for version skew.
25962
+ */
25963
+ pendingVersion: string().nullable().optional(),
25964
+ /** See the status payload: staged, or installed-on-disk ≠ running. Optional for skew. */
25965
+ restartRequired: boolean().optional()
25906
25966
  });
25967
+ /**
25968
+ * What an action DID — the discriminant `accepted` cannot carry. Before
25969
+ * 2026-09-20 `applyServerUpdate` answered `accepted:false` both for a refusal
25970
+ * where nothing was wrong (already current, already staged) and for a staging
25971
+ * install that died on `npm error code ECONNRESET`; the only difference was
25972
+ * prose in `message`, and an operator restarted a container on the strength of
25973
+ * it, booting the previous version.
25974
+ *
25975
+ * - `staged` — the closure is installed and validated; the node
25976
+ * restarts to apply it (`restarting:true`). NOTHING
25977
+ * runs the new code until that restart completes.
25978
+ * - `restart-scheduled` — a plain, version-preserving restart was accepted.
25979
+ * - `already-current` — the target IS the running version; nothing done.
25980
+ * - `refused` — dropped by a gate; `reason` names which.
25981
+ * - `failed` — attempted and did not land; `error` says why.
25982
+ */
25983
+ var ServerUpdateOutcomeSchema = _enum([
25984
+ "staged",
25985
+ "restart-scheduled",
25986
+ "already-current",
25987
+ "refused",
25988
+ "failed"
25989
+ ]);
25907
25990
  var ServerUpdateActionResultSchema = object({
25908
25991
  accepted: boolean(),
25909
25992
  targetVersion: string().nullable(),
25910
25993
  /** True when a graceful restart was scheduled to apply the change. */
25911
25994
  restarting: boolean(),
25912
- message: string()
25995
+ message: string(),
25996
+ /** See {@link ServerUpdateOutcomeSchema}. Optional for version skew. */
25997
+ outcome: ServerUpdateOutcomeSchema.optional(),
25998
+ /**
25999
+ * Stable, greppable cause for `refused` / `failed` (the engine's
26000
+ * `UpdateRefusalReason`, `staging-failed`, …). `null` on success.
26001
+ */
26002
+ reason: string().nullable().optional(),
26003
+ /**
26004
+ * The failure itself, verbatim enough to act on (the npm output for a
26005
+ * staging install). Non-null only for `failed`.
26006
+ */
26007
+ error: string().nullable().optional()
25913
26008
  });
25914
26009
  method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), ServerUpdateCheckResultSchema, {
25915
26010
  kind: "mutation",
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-CkNVb7Zh.js");
5
+ const require_dist = require("../dist-DygcLvgG.js");
6
6
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
7
7
  let node_fs = require("node:fs");
8
8
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { $t as hydrateSchema, Wt as BaseAddon, X as evaluateZoneRules, ft as motionDetectionCapability, qt as DeviceType } from "../dist-Cqf-U6EN.mjs";
1
+ import { $t as hydrateSchema, Wt as BaseAddon, X as evaluateZoneRules, ft as motionDetectionCapability, qt as DeviceType } from "../dist-DBHsAlUE.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,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-emK7D4bc.js");
2
- const require_dist = require("./dist-CkNVb7Zh.js");
2
+ const require_dist = require("./dist-DygcLvgG.js");
3
3
  let node_crypto = require("node:crypto");
4
4
  let node_fs = require("node:fs");
5
5
  node_fs = require_chunk.__toESM(node_fs, 1);
@@ -115,6 +115,58 @@ async function probeFfmpegBinary(path) {
115
115
  ]);
116
116
  return parseFfmpegCapabilities(path, versionOut, hwaccelOut, encoderOut);
117
117
  }
118
+ /**
119
+ * The ffmpeg build every CamStack node downloads, per platform and arch.
120
+ *
121
+ * ## Why a download, on every node, including the container
122
+ *
123
+ * The version of ffmpeg used to be CODE: baked into the image, changeable only
124
+ * by rebuilding and rolling it. Now it is DATA — this file states the release,
125
+ * and a node that boots with a different one downloads it. Changing ffmpeg is a
126
+ * framework bump, not an image rebuild.
127
+ *
128
+ * It also settles the licence question by removing it. FFmpeg's licence is
129
+ * chosen at compile time: the core is LGPL 2.1+, `--enable-gpl` makes it GPL
130
+ * (for x264/x265), `--enable-version3` makes that v3, and `--enable-nonfree`
131
+ * makes the result undistributable. These are GPL v3 builds, and we do not
132
+ * distribute them: the user's own node fetches the archive from the project
133
+ * that publishes it, so we convey no GPL work and inherit none of the
134
+ * obligations that come with conveying one. That is the whole reason the image
135
+ * no longer installs ffmpeg at all — not a technical preference.
136
+ *
137
+ * ## Why jellyfin-ffmpeg
138
+ *
139
+ * One vendor covering linux-amd64, linux-arm64, darwin-arm64 and darwin-x64
140
+ * from one release, with the widest hardware surface of anything maintained:
141
+ * VAAPI, QSV, NVENC/NVDEC, AMF, Vulkan, OpenCL and DRM on amd64, plus Rockchip
142
+ * MPP on arm64. It reaches the vendor libraries through dlopen trampolines,
143
+ * so the binary is not linked against a driver stack it may not find.
144
+ *
145
+ * **What it still needs from the host, measured 2026-09-19.** On the Unraid
146
+ * HOST, which has no libva, `-vaapi_device` aborts the process outright —
147
+ * `implib-gen: libva-drm.so.2: failed to load library ... Assertion '0 &&
148
+ * "Assertion in generated code"' failed`. Inside our container, which installs
149
+ * libva plus the iHD driver, the same command encodes: verified end to end with
150
+ * `testsrc → format=nv12,hwupload → h264_vaapi`. So the image drops ffmpeg and
151
+ * KEEPS the Intel media stack; the drivers are the part a binary cannot bring.
152
+ *
153
+ * ## Why each artifact carries a checksum and a claim
154
+ *
155
+ * The download is now the only source, so `sha256` is verified before anything
156
+ * is extracted — jellyfin publishes no checksums on its release assets, so
157
+ * these are ours, taken at the version bump. And `expectedHwaccels` is what the
158
+ * build is supposed to be able to do: a binary that probes short of its own
159
+ * claim is a source that changed under us, which is precisely what went
160
+ * unnoticed for months when a static build turned out to carry no VAAPI at all
161
+ * (D536).
162
+ */
163
+ /** The pinned jellyfin-ffmpeg release. Changing this is the version change. */
164
+ var FFMPEG_RELEASE = "8.1.2-5";
165
+ var BASE = `https://github.com/jellyfin/jellyfin-ffmpeg/releases/download/v${FFMPEG_RELEASE}`;
166
+ function portable(target) {
167
+ return `${BASE}/jellyfin-ffmpeg_${FFMPEG_RELEASE}_portable_${target}-gpl.tar.xz`;
168
+ }
169
+ portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64");
118
170
  var DEFAULT_FIRST_UNIT_TIMEOUT_MS = 12e3;
119
171
  /** Heartbeat cadence — ~2 minutes of 4 s fragments. */
120
172
  var FRAGMENT_LOG_EVERY = 30;
@@ -1,4 +1,4 @@
1
- import { Bt as buildFfmpegArgs, Ht as isSoftwareDecode, Lt as errMsg, zt as Fmp4BoxSplitter } from "./dist-Cqf-U6EN.mjs";
1
+ import { Bt as buildFfmpegArgs, Ht as isSoftwareDecode, Lt as errMsg, zt as Fmp4BoxSplitter } from "./dist-DBHsAlUE.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { realpathSync } from "node:fs";
4
4
  import path from "node:path";
@@ -112,6 +112,58 @@ async function probeFfmpegBinary(path) {
112
112
  ]);
113
113
  return parseFfmpegCapabilities(path, versionOut, hwaccelOut, encoderOut);
114
114
  }
115
+ /**
116
+ * The ffmpeg build every CamStack node downloads, per platform and arch.
117
+ *
118
+ * ## Why a download, on every node, including the container
119
+ *
120
+ * The version of ffmpeg used to be CODE: baked into the image, changeable only
121
+ * by rebuilding and rolling it. Now it is DATA — this file states the release,
122
+ * and a node that boots with a different one downloads it. Changing ffmpeg is a
123
+ * framework bump, not an image rebuild.
124
+ *
125
+ * It also settles the licence question by removing it. FFmpeg's licence is
126
+ * chosen at compile time: the core is LGPL 2.1+, `--enable-gpl` makes it GPL
127
+ * (for x264/x265), `--enable-version3` makes that v3, and `--enable-nonfree`
128
+ * makes the result undistributable. These are GPL v3 builds, and we do not
129
+ * distribute them: the user's own node fetches the archive from the project
130
+ * that publishes it, so we convey no GPL work and inherit none of the
131
+ * obligations that come with conveying one. That is the whole reason the image
132
+ * no longer installs ffmpeg at all — not a technical preference.
133
+ *
134
+ * ## Why jellyfin-ffmpeg
135
+ *
136
+ * One vendor covering linux-amd64, linux-arm64, darwin-arm64 and darwin-x64
137
+ * from one release, with the widest hardware surface of anything maintained:
138
+ * VAAPI, QSV, NVENC/NVDEC, AMF, Vulkan, OpenCL and DRM on amd64, plus Rockchip
139
+ * MPP on arm64. It reaches the vendor libraries through dlopen trampolines,
140
+ * so the binary is not linked against a driver stack it may not find.
141
+ *
142
+ * **What it still needs from the host, measured 2026-09-19.** On the Unraid
143
+ * HOST, which has no libva, `-vaapi_device` aborts the process outright —
144
+ * `implib-gen: libva-drm.so.2: failed to load library ... Assertion '0 &&
145
+ * "Assertion in generated code"' failed`. Inside our container, which installs
146
+ * libva plus the iHD driver, the same command encodes: verified end to end with
147
+ * `testsrc → format=nv12,hwupload → h264_vaapi`. So the image drops ffmpeg and
148
+ * KEEPS the Intel media stack; the drivers are the part a binary cannot bring.
149
+ *
150
+ * ## Why each artifact carries a checksum and a claim
151
+ *
152
+ * The download is now the only source, so `sha256` is verified before anything
153
+ * is extracted — jellyfin publishes no checksums on its release assets, so
154
+ * these are ours, taken at the version bump. And `expectedHwaccels` is what the
155
+ * build is supposed to be able to do: a binary that probes short of its own
156
+ * claim is a source that changed under us, which is precisely what went
157
+ * unnoticed for months when a static build turned out to carry no VAAPI at all
158
+ * (D536).
159
+ */
160
+ /** The pinned jellyfin-ffmpeg release. Changing this is the version change. */
161
+ var FFMPEG_RELEASE = "8.1.2-5";
162
+ var BASE = `https://github.com/jellyfin/jellyfin-ffmpeg/releases/download/v${FFMPEG_RELEASE}`;
163
+ function portable(target) {
164
+ return `${BASE}/jellyfin-ffmpeg_${FFMPEG_RELEASE}_portable_${target}-gpl.tar.xz`;
165
+ }
166
+ portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64");
115
167
  var DEFAULT_FIRST_UNIT_TIMEOUT_MS = 12e3;
116
168
  /** Heartbeat cadence — ~2 minutes of 4 s fragments. */
117
169
  var FRAGMENT_LOG_EVERY = 30;
@@ -3,9 +3,9 @@ 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-CkNVb7Zh.js");
7
- const require_node = require("../node-CqC8R84-.js");
8
- const require_default_detection_model = require("../default-detection-model-BfMsW_XK.js");
6
+ const require_dist = require("../dist-DygcLvgG.js");
7
+ const require_node = require("../node-CACCuE7t.js");
8
+ const require_default_detection_model = require("../default-detection-model-kQnvoRyv.js");
9
9
  const require_worker_protocol = require("../worker-protocol-B2MfQLlu.js");
10
10
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
11
11
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
@@ -1,6 +1,6 @@
1
- import { $ as failureContributionCapability, Lt as errMsg, S as NativeLeaseSettingsSchema, U as deriveDetailCropRect, Wt as BaseAddon, Xt as customAction, Yt as createEvent, Zt as defineCustomActions, _ as FailureCounters, _t as pickDetailCropConvention, b as MOTION_CLOSE_AFTER_MS, bn as EventCategory, bt as pipelineRunnerCapability, cn as _enum, fn as lazy, hn as object, it as loadContributionCapability, ln as array, m as DEVICE_BACKEND_TO_FORMAT, mn as number, p as DEFAULT_NATIVE_LEASE_SETTINGS, pn as literal, rn as nodePin, u as DEFAULT_DETAIL_CROP_CONVENTION, un as boolean, vn as string, vt as pickNativeLeaseOverride, x as NativeLeaseAdmissionSchema } from "../dist-Cqf-U6EN.mjs";
2
- import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-jLmcbaar.mjs";
3
- import { a as localFrameRegistry, d as getStepDefinition, i as rootObjectGate, o as resolveFrameViewGeometry, r as macroGateVerdict } from "../default-detection-model-pXamampo.mjs";
1
+ import { $ as failureContributionCapability, Lt as errMsg, S as NativeLeaseSettingsSchema, U as deriveDetailCropRect, Wt as BaseAddon, Xt as customAction, Yt as createEvent, Zt as defineCustomActions, _ as FailureCounters, _t as pickDetailCropConvention, b as MOTION_CLOSE_AFTER_MS, bn as EventCategory, bt as pipelineRunnerCapability, cn as _enum, fn as lazy, hn as object, it as loadContributionCapability, ln as array, m as DEVICE_BACKEND_TO_FORMAT, mn as number, p as DEFAULT_NATIVE_LEASE_SETTINGS, pn as literal, rn as nodePin, u as DEFAULT_DETAIL_CROP_CONVENTION, un as boolean, vn as string, vt as pickNativeLeaseOverride, x as NativeLeaseAdmissionSchema } from "../dist-DBHsAlUE.mjs";
2
+ import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-j_3VvNQJ.mjs";
3
+ import { a as localFrameRegistry, d as getStepDefinition, i as rootObjectGate, o as resolveFrameViewGeometry, r as macroGateVerdict } from "../default-detection-model-DqrqHCuw.mjs";
4
4
  import { t as isWorkerReply } from "../worker-protocol-C_W-P_g-.mjs";
5
5
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
6
6
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
@@ -1,4 +1,4 @@
1
- import { mt as parseProcStatus } from "./dist-Cqf-U6EN.mjs";
1
+ import { mt as parseProcStatus } from "./dist-DBHsAlUE.mjs";
2
2
  import * as fs from "node:fs";
3
3
  import { execFile } from "node:child_process";
4
4
  //#region src/shared/node-topology-platform.ts
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-emK7D4bc.js");
2
- const require_dist = require("./dist-CkNVb7Zh.js");
2
+ const require_dist = require("./dist-DygcLvgG.js");
3
3
  let node_fs = require("node:fs");
4
4
  node_fs = require_chunk.__toESM(node_fs);
5
5
  let node_child_process = require("node:child_process");