@camstack/system 1.2.101 → 1.2.102

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 (50) hide show
  1. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  2. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  3. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/alerts/alerts.addon.js +1 -1
  6. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  7. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  8. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  9. package/dist/builtins/console-logging/index.js +1 -1
  10. package/dist/builtins/console-logging/index.mjs +1 -1
  11. package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
  12. package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
  13. package/dist/builtins/device-manager/device-manager.addon.js +1 -1
  14. package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
  15. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  16. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  17. package/dist/builtins/hub-forwarder/index.js +1 -1
  18. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  19. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  20. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  21. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  22. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  23. package/dist/builtins/local-network/local-network.addon.js +1 -1
  24. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  25. package/dist/builtins/loki-logging/index.js +1 -1
  26. package/dist/builtins/loki-logging/index.mjs +1 -1
  27. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  28. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  29. package/dist/builtins/platform-probe/index.js +1 -1
  30. package/dist/builtins/platform-probe/index.mjs +1 -1
  31. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  32. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  33. package/dist/builtins/snapshot/index.js +33 -4
  34. package/dist/builtins/snapshot/index.mjs +33 -4
  35. package/dist/builtins/snapshot/snapshot-grab-pick.d.ts +20 -0
  36. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  37. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  38. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +1 -1
  39. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +1 -1
  40. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  41. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  42. package/dist/builtins/system-config/system-config.addon.js +1 -1
  43. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  44. package/dist/builtins/winston-logging/index.js +1 -1
  45. package/dist/builtins/winston-logging/index.mjs +1 -1
  46. package/dist/{dist-RbFV8cX7.mjs → dist-3wh5LCad.mjs} +58 -12
  47. package/dist/{dist-tMrPAfpF.js → dist-9sC0wZw6.js} +58 -12
  48. package/dist/index.js +1 -1
  49. package/dist/index.mjs +1 -1
  50. package/package.json +1 -1
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
8
  let node_crypto = require("node:crypto");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { Gt as EventCategory, v as addonPagesCapability, vt as errMsg, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
1
+ import { Gt as EventCategory, v as addonPagesCapability, vt as errMsg, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
8
  let node_crypto = require("node:crypto");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { Gt as EventCategory, b as addonWidgetsCapability, vt as errMsg, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
1
+ import { Gt as EventCategory, b as addonWidgetsCapability, vt as errMsg, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  //#region src/builtins/alerts/prune-policy.ts
8
8
  /**
9
9
  * Ids older than `cutoffMs`, oldest first.
@@ -1,4 +1,4 @@
1
- import { Gt as EventCategory, Mt as createEvent, n as AlertSchema, vt as errMsg, x as alertsCapability, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
1
+ import { Gt as EventCategory, Mt as createEvent, n as AlertSchema, vt as errMsg, x as alertsCapability, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
2
2
  //#region src/builtins/alerts/prune-policy.ts
3
3
  /**
4
4
  * Ids older than `cutoffMs`, oldest first.
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let buffer = require("buffer");
9
9
  let node_fs_promises = require("node:fs/promises");
@@ -1,4 +1,4 @@
1
- import { C as backupCapability, Gt as EventCategory, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
1
+ import { C as backupCapability, Gt as EventCategory, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
2
2
  import { randomBytes, randomUUID } from "node:crypto";
3
3
  import { Buffer as Buffer$1 } from "buffer";
4
4
  import * as fsp from "node:fs/promises";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  const require_formatter = require("../../formatter-DqAKDlvN.js");
8
8
  //#region src/builtins/console-logging/console-destination.ts
9
9
  var LEVEL_RANK = {
@@ -1,4 +1,4 @@
1
- import { X as logDestinationCapability, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
1
+ import { X as logDestinationCapability, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
2
2
  import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
3
3
  //#region src/builtins/console-logging/console-destination.ts
4
4
  var LEVEL_RANK = {
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("../../chunk-Cek0wNdY.js");
3
- const require_dist = require("../../dist-tMrPAfpF.js");
3
+ const require_dist = require("../../dist-9sC0wZw6.js");
4
4
  let node_crypto = require("node:crypto");
5
5
  let node_fs_promises = require("node:fs/promises");
6
6
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -1,4 +1,4 @@
1
- import { D as coreBlockAddonId, O as coreBlockIdFromAddonId, c as CoreBlockSchema, k as coreBlocksCapability, l as DeclaredDevices, o as CORE_BLOCKS_ADDON_ID, s as CORE_BLOCK_ADDON_PREFIX, vt as errMsg, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
1
+ import { D as coreBlockAddonId, O as coreBlockIdFromAddonId, c as CoreBlockSchema, k as coreBlocksCapability, l as DeclaredDevices, o as CORE_BLOCKS_ADDON_ID, s as CORE_BLOCK_ADDON_PREFIX, vt as errMsg, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import * as fs from "node:fs/promises";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let _camstack_types_node = require("@camstack/types/node");
9
9
  //#region src/builtins/device-manager/adoption-job-engine.ts
@@ -1,4 +1,4 @@
1
- import { Ct as DeviceFeature, E as buildStreamParamsConfigSchema, F as deviceStatusCapability, Gt as EventCategory, Lt as isDeviceConfigCap, N as deviceManagerCapability, Ot as WELL_KNOWN_TAB_MAP, P as deviceStateCapability, R as enumerateItemArrayFields, Tt as DeviceType, Wt as sleep, a as CAP_NAMES_WITH_STATUS, at as runtimeStatePolicyFor, et as normalizeUnit, nt as parseStreamParamsFormPatch, p as STREAM_PROFILE_META, t as ALL_CAPABILITY_DEFINITIONS, u as DeviceStatusSchema, vt as errMsg, wt as DeviceRole, yt as BaseAddon, z as enumerateSchemaFields } from "../../dist-RbFV8cX7.mjs";
1
+ import { Ct as DeviceFeature, E as buildStreamParamsConfigSchema, F as deviceStatusCapability, Gt as EventCategory, Lt as isDeviceConfigCap, N as deviceManagerCapability, Ot as WELL_KNOWN_TAB_MAP, P as deviceStateCapability, R as enumerateItemArrayFields, Tt as DeviceType, Wt as sleep, a as CAP_NAMES_WITH_STATUS, at as runtimeStatePolicyFor, et as normalizeUnit, nt as parseStreamParamsFormPatch, p as STREAM_PROFILE_META, t as ALL_CAPABILITY_DEFINITIONS, u as DeviceStatusSchema, vt as errMsg, wt as DeviceRole, yt as BaseAddon, z as enumerateSchemaFields } from "../../dist-3wh5LCad.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { canonicalDeviceFingerprint } from "@camstack/types/node";
4
4
  //#region src/builtins/device-manager/adoption-job-engine.ts
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  //#region src/builtins/doorbell/trigger-engine.ts
8
8
  /**
9
9
  * Pure trigger logic for the virtual-doorbell builtin — edge detection over
@@ -1,4 +1,4 @@
1
- import { G as isSameAddonId, Gt as EventCategory, I as doorbellCapability, Mt as createEvent, Tt as DeviceType, vt as errMsg, w as bareAddonId, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
1
+ import { G as isSameAddonId, Gt as EventCategory, I as doorbellCapability, Mt as createEvent, Tt as DeviceType, vt as errMsg, w as bareAddonId, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
2
2
  //#region src/builtins/doorbell/trigger-engine.ts
3
3
  /**
4
4
  * Pure trigger logic for the virtual-doorbell builtin — edge detection over
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  const require_formatter = require("../../formatter-DqAKDlvN.js");
8
8
  //#region src/builtins/hub-forwarder/hub-forwarder-destination.ts
9
9
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
@@ -1,4 +1,4 @@
1
- import { X as logDestinationCapability, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
1
+ import { X as logDestinationCapability, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
2
2
  import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
3
3
  //#region src/builtins/hub-forwarder/hub-forwarder-destination.ts
4
4
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("../../chunk-Cek0wNdY.js");
3
- const require_dist = require("../../dist-tMrPAfpF.js");
3
+ const require_dist = require("../../dist-9sC0wZw6.js");
4
4
  //#region src/builtins/liveness-monitor/liveness-checks.ts
5
5
  var NO_DEVICES = "liveness:no-devices";
6
6
  var ALL_OFFLINE = "liveness:all-devices-offline";
@@ -1,4 +1,4 @@
1
- import { Gt as EventCategory, Mt as createEvent, vt as errMsg, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
1
+ import { Gt as EventCategory, Mt as createEvent, vt as errMsg, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
2
2
  //#region src/builtins/liveness-monitor/liveness-checks.ts
3
3
  var NO_DEVICES = "liveness:no-devices";
4
4
  var ALL_OFFLINE = "liveness:all-devices-offline";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  node_crypto = require_chunk.__toESM(node_crypto);
9
9
  let crypto$1 = require("crypto");
@@ -1,5 +1,5 @@
1
1
  import { i as __require, o as __toESM, t as __commonJSMin } from "../../chunk-CNf5ZN-e.mjs";
2
- import { S as authProviderCapability, _ as UserRecordSchema, ht as userManagementCapability, m as ScopedTokenSchema, r as ApiKeyRecordSchema, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
2
+ import { S as authProviderCapability, _ as UserRecordSchema, ht as userManagementCapability, m as ScopedTokenSchema, r as ApiKeyRecordSchema, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
3
3
  import * as crypto$2 from "node:crypto";
4
4
  import { createHash, randomUUID, timingSafeEqual } from "node:crypto";
5
5
  import nodeCrypto from "crypto";
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("../../chunk-Cek0wNdY.js");
3
- const require_dist = require("../../dist-tMrPAfpF.js");
3
+ const require_dist = require("../../dist-9sC0wZw6.js");
4
4
  let node_os = require("node:os");
5
5
  node_os = require_chunk.__toESM(node_os);
6
6
  //#region src/builtins/local-network/local-network.addon.ts
@@ -1,4 +1,4 @@
1
- import { Gt as EventCategory, Y as localNetworkCapability, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
1
+ import { Gt as EventCategory, Y as localNetworkCapability, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
2
2
  import * as os from "node:os";
3
3
  //#region src/builtins/local-network/local-network.addon.ts
4
4
  /**
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  //#region src/builtins/loki-logging/loki-payload.ts
8
8
  /**
9
9
  * Loki rejects a label name that is not a valid Prometheus label
@@ -1,4 +1,4 @@
1
- import { X as logDestinationCapability, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
1
+ import { X as logDestinationCapability, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
2
2
  //#region src/builtins/loki-logging/loki-payload.ts
3
3
  /**
4
4
  * Loki rejects a label name that is not a valid Prometheus label
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  let node_child_process = require("node:child_process");
8
8
  let node_util = require("node:util");
9
9
  let node_os = require("node:os");
@@ -1,4 +1,4 @@
1
- import { $ as metricsProviderCapability, Gt as EventCategory, Mt as createEvent, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
1
+ import { $ as metricsProviderCapability, Gt as EventCategory, Mt as createEvent, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
2
2
  import { execFile, execFileSync } from "node:child_process";
3
3
  import { promisify } from "node:util";
4
4
  import * as os from "node:os";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  let node_child_process = require("node:child_process");
8
8
  let node_util = require("node:util");
9
9
  let node_os = require("node:os");
@@ -1,5 +1,5 @@
1
1
  import { o as __toESM } from "../../chunk-CNf5ZN-e.mjs";
2
- import { Gt as EventCategory, L as enumerateInferenceDevices, Pt as emitReadiness, ct as scoreRuntimes, rt as platformProbeCapability, vt as errMsg, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
2
+ import { Gt as EventCategory, L as enumerateInferenceDevices, Pt as emitReadiness, ct as scoreRuntimes, rt as platformProbeCapability, vt as errMsg, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
3
3
  import { execFile } from "node:child_process";
4
4
  import { promisify } from "node:util";
5
5
  import * as os from "node:os";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  //#region src/builtins/remote-access-orchestrator/enabled-providers-reconcile.ts
8
8
  /**
9
9
  * Reconcile the durable `enabledProviders` set against authoritative
@@ -1,4 +1,4 @@
1
- import { Gt as EventCategory, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
1
+ import { Gt as EventCategory, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
2
2
  //#region src/builtins/remote-access-orchestrator/enabled-providers-reconcile.ts
3
3
  /**
4
4
  * Reconcile the durable `enabledProviders` set against authoritative
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  let zod = require("zod");
8
8
  let node_crypto = require("node:crypto");
9
9
  let _camstack_types_node = require("@camstack/types/node");
@@ -801,6 +801,28 @@ var SnapshotVariantCache = class SnapshotVariantCache {
801
801
  }
802
802
  };
803
803
  //#endregion
804
+ //#region src/builtins/snapshot/snapshot-grab-pick.ts
805
+ /**
806
+ * Which restream ffmpeg should grab a snapshot JPEG from.
807
+ *
808
+ * `status: 'streaming'` is not enough. A derived whose source profile is
809
+ * unassigned sits in that state with zero packets (618, 2026-08-16: `derived:Mid
810
+ * to low` had four subscribers and never a frame). Preferring it as "warm"
811
+ * parked every grab on a 15 s ffmpeg timeout, so the connecting poster never
812
+ * moved.
813
+ *
814
+ * Derived brokers are never the warm shortcut. A native that is actually
815
+ * streaming still wins; otherwise the caller walks the ranked list and will
816
+ * wake an idle source.
817
+ */
818
+ function isDerivedBrokerId(brokerId, devicePrefix) {
819
+ return (brokerId.startsWith(devicePrefix) ? brokerId.slice(devicePrefix.length) : brokerId).startsWith("derived:");
820
+ }
821
+ /** Highest-quality currently-streaming NON-derived broker, or undefined. */
822
+ function pickWarmSnapshotBroker(ranked, devicePrefix) {
823
+ return ranked.find((c) => c.status === "streaming" && !isDerivedBrokerId(c.brokerId, devicePrefix));
824
+ }
825
+ //#endregion
804
826
  //#region src/builtins/snapshot/snapshot.addon.ts
805
827
  /**
806
828
  * How long `getSnapshotLinks` waits for the capture it triggered before minting
@@ -1799,12 +1821,19 @@ var SnapshotAddon = class SnapshotAddon extends require_dist.BaseAddon {
1799
1821
  entry: e,
1800
1822
  status: statusByBrokerId.get(e.brokerId) ?? "idle"
1801
1823
  }));
1802
- const warm = statuses.find((s) => s.status === "streaming");
1824
+ const warm = pickWarmSnapshotBroker(statuses.map((s) => ({
1825
+ brokerId: s.entry.brokerId,
1826
+ status: s.status
1827
+ })), prefix);
1803
1828
  if (warm) {
1804
- const grabbed = await this.runGrabWithResumeRetry(warm.entry.url, deviceId);
1805
- if (grabbed) return grabbed;
1829
+ const match = statuses.find((s) => s.entry.brokerId === warm.brokerId);
1830
+ if (match) {
1831
+ const grabbed = await this.runGrabWithResumeRetry(match.entry.url, deviceId);
1832
+ if (grabbed) return grabbed;
1833
+ }
1806
1834
  }
1807
1835
  for (const { entry } of statuses) {
1836
+ if (isDerivedBrokerId(entry.brokerId, prefix)) continue;
1808
1837
  const grabbed = await this.runGrabWithResumeRetry(entry.url, deviceId).catch(() => null);
1809
1838
  if (grabbed) return grabbed;
1810
1839
  }
@@ -1,4 +1,4 @@
1
- import { Ct as DeviceFeature, Gt as EventCategory, M as deriveBatteryPresence, Rt as nodePin, T as batteryCapability, Tt as DeviceType, i as BatteryStatusSchema, mt as streamQualityLabel, ut as snapshotCapability, vt as errMsg, w as bareAddonId, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
1
+ import { Ct as DeviceFeature, Gt as EventCategory, M as deriveBatteryPresence, Rt as nodePin, T as batteryCapability, Tt as DeviceType, i as BatteryStatusSchema, mt as streamQualityLabel, ut as snapshotCapability, vt as errMsg, w as bareAddonId, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
2
2
  import { z } from "zod";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { signExpiringUrl, verifyExpiringUrl } from "@camstack/types/node";
@@ -795,6 +795,28 @@ var SnapshotVariantCache = class SnapshotVariantCache {
795
795
  }
796
796
  };
797
797
  //#endregion
798
+ //#region src/builtins/snapshot/snapshot-grab-pick.ts
799
+ /**
800
+ * Which restream ffmpeg should grab a snapshot JPEG from.
801
+ *
802
+ * `status: 'streaming'` is not enough. A derived whose source profile is
803
+ * unassigned sits in that state with zero packets (618, 2026-08-16: `derived:Mid
804
+ * to low` had four subscribers and never a frame). Preferring it as "warm"
805
+ * parked every grab on a 15 s ffmpeg timeout, so the connecting poster never
806
+ * moved.
807
+ *
808
+ * Derived brokers are never the warm shortcut. A native that is actually
809
+ * streaming still wins; otherwise the caller walks the ranked list and will
810
+ * wake an idle source.
811
+ */
812
+ function isDerivedBrokerId(brokerId, devicePrefix) {
813
+ return (brokerId.startsWith(devicePrefix) ? brokerId.slice(devicePrefix.length) : brokerId).startsWith("derived:");
814
+ }
815
+ /** Highest-quality currently-streaming NON-derived broker, or undefined. */
816
+ function pickWarmSnapshotBroker(ranked, devicePrefix) {
817
+ return ranked.find((c) => c.status === "streaming" && !isDerivedBrokerId(c.brokerId, devicePrefix));
818
+ }
819
+ //#endregion
798
820
  //#region src/builtins/snapshot/snapshot.addon.ts
799
821
  /**
800
822
  * How long `getSnapshotLinks` waits for the capture it triggered before minting
@@ -1793,12 +1815,19 @@ var SnapshotAddon = class SnapshotAddon extends BaseAddon {
1793
1815
  entry: e,
1794
1816
  status: statusByBrokerId.get(e.brokerId) ?? "idle"
1795
1817
  }));
1796
- const warm = statuses.find((s) => s.status === "streaming");
1818
+ const warm = pickWarmSnapshotBroker(statuses.map((s) => ({
1819
+ brokerId: s.entry.brokerId,
1820
+ status: s.status
1821
+ })), prefix);
1797
1822
  if (warm) {
1798
- const grabbed = await this.runGrabWithResumeRetry(warm.entry.url, deviceId);
1799
- if (grabbed) return grabbed;
1823
+ const match = statuses.find((s) => s.entry.brokerId === warm.brokerId);
1824
+ if (match) {
1825
+ const grabbed = await this.runGrabWithResumeRetry(match.entry.url, deviceId);
1826
+ if (grabbed) return grabbed;
1827
+ }
1800
1828
  }
1801
1829
  for (const { entry } of statuses) {
1830
+ if (isDerivedBrokerId(entry.brokerId, prefix)) continue;
1802
1831
  const grabbed = await this.runGrabWithResumeRetry(entry.url, deviceId).catch(() => null);
1803
1832
  if (grabbed) return grabbed;
1804
1833
  }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Which restream ffmpeg should grab a snapshot JPEG from.
3
+ *
4
+ * `status: 'streaming'` is not enough. A derived whose source profile is
5
+ * unassigned sits in that state with zero packets (618, 2026-08-16: `derived:Mid
6
+ * to low` had four subscribers and never a frame). Preferring it as "warm"
7
+ * parked every grab on a 15 s ffmpeg timeout, so the connecting poster never
8
+ * moved.
9
+ *
10
+ * Derived brokers are never the warm shortcut. A native that is actually
11
+ * streaming still wins; otherwise the caller walks the ranked list and will
12
+ * wake an idle source.
13
+ */
14
+ export declare function isDerivedBrokerId(brokerId: string, devicePrefix: string): boolean;
15
+ export interface SnapshotGrabCandidate {
16
+ readonly brokerId: string;
17
+ readonly status: string;
18
+ }
19
+ /** Highest-quality currently-streaming NON-derived broker, or undefined. */
20
+ export declare function pickWarmSnapshotBroker(ranked: readonly SnapshotGrabCandidate[], devicePrefix: string): SnapshotGrabCandidate | undefined;
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let node_fs_promises = require("node:fs/promises");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { V as filesystemBrowseCapability, pt as storageProviderCapability, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
1
+ import { V as filesystemBrowseCapability, pt as storageProviderCapability, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { mkdir, readdir, realpath, statfs } from "node:fs/promises";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let node_fs = require("node:fs");
9
9
  let node_module = require("node:module");
@@ -1,4 +1,4 @@
1
- import { A as dataStoreProviderCapability, Bt as parseJsonUnknown, _t as vectorStoreCapability, f as RUNTIME_DEFAULTS, gt as vectorDimFromBase64, j as decodeVectorBase64, kt as asJsonObject, vt as errMsg, w as bareAddonId, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
1
+ import { A as dataStoreProviderCapability, Bt as parseJsonUnknown, _t as vectorStoreCapability, f as RUNTIME_DEFAULTS, gt as vectorDimFromBase64, j as decodeVectorBase64, kt as asJsonObject, vt as errMsg, w as bareAddonId, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { statSync } from "node:fs";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let node_fs_promises = require("node:fs/promises");
9
9
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -1,4 +1,4 @@
1
- import { dt as storageCapability, ft as storageMigrationCapability, g as StorageMigrationJobSchema, h as StorageLocationTypeSchema, lt as settingsStoreCapability, yt as BaseAddon, zt as parseJsonObject } from "../../dist-RbFV8cX7.mjs";
1
+ import { dt as storageCapability, ft as storageMigrationCapability, g as StorageMigrationJobSchema, h as StorageLocationTypeSchema, lt as settingsStoreCapability, yt as BaseAddon, zt as parseJsonObject } from "../../dist-3wh5LCad.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import * as fs from "node:fs/promises";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  //#region src/builtins/system-config/system-config.addon.ts
8
8
  /**
9
9
  * Built-in `system-config` addon — Phase 4 of the settings redesign.
@@ -1,4 +1,4 @@
1
- import { It as hydrateSchema, vt as errMsg, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
1
+ import { It as hydrateSchema, vt as errMsg, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
2
2
  //#region src/builtins/system-config/system-config.addon.ts
3
3
  /**
4
4
  * Built-in `system-config` addon — Phase 4 of the settings redesign.
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-tMrPAfpF.js");
6
+ const require_dist = require("../../dist-9sC0wZw6.js");
7
7
  const require_formatter = require("../../formatter-DqAKDlvN.js");
8
8
  let node_path = require("node:path");
9
9
  node_path = require_chunk.__toESM(node_path);
@@ -1,4 +1,4 @@
1
- import { X as logDestinationCapability, yt as BaseAddon } from "../../dist-RbFV8cX7.mjs";
1
+ import { X as logDestinationCapability, yt as BaseAddon } from "../../dist-3wh5LCad.mjs";
2
2
  import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
3
3
  import * as path$1 from "node:path";
4
4
  import path from "node:path";
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- //#region ../types/dist/event-category-Bxo5yJjt.mjs
2
+ //#region ../types/dist/event-category-C0lyLd5U.mjs
3
3
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4
4
  EventCategory["SystemBoot"] = "system.boot";
5
5
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -16,9 +16,10 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
16
16
  EventCategory["SystemRestartCompleted"] = "system.restart-completed";
17
17
  /**
18
18
  * A newer addon or server-root package version was found by the
19
- * authoritative registry check. Emitted once per
20
- * `(target, packageName, currentVersion, latestVersion)` transition; repeated
21
- * polling of the same result is deduplicated by the checker.
19
+ * authoritative registry check. Emitted once when any observed
20
+ * `latestVersion` changes (or a package/node first appears behind);
21
+ * the payload carries the full currently-available list. Repeated
22
+ * polling of the same latests is silent.
22
23
  */
23
24
  EventCategory["UpdateAvailable"] = "update.available";
24
25
  /**
@@ -3651,6 +3652,10 @@ var RecordingBandSchema = z.object({
3651
3652
  preBufferSec: z.number().min(0).optional(),
3652
3653
  postBufferSec: z.number().min(0).optional()
3653
3654
  });
3655
+ ({
3656
+ preBufferSec: 10,
3657
+ postBufferSec: 30
3658
+ }).postBufferSec * 1e3;
3654
3659
  /**
3655
3660
  * Per-device retention overrides. Every field is optional; an unset or `0`
3656
3661
  * value inherits the node-wide recorder default. Only footage-lifetime limits
@@ -12433,6 +12438,9 @@ var NcSystemEventKindSchema = z.enum([
12433
12438
  "alarm-disarmed",
12434
12439
  "alarm-arming",
12435
12440
  "alarm-arm-refused",
12441
+ "addon-updated",
12442
+ "server-updated",
12443
+ "export-completed",
12436
12444
  "camera-online",
12437
12445
  "camera-offline",
12438
12446
  "camera-disabled",
@@ -14436,13 +14444,19 @@ var RetrainStatusSchema = z.enum([
14436
14444
  * "never marked" from "already trained" must read `retrainStatus`.
14437
14445
  *
14438
14446
  * `debug` does NOT pin; it is attention, not durability.
14447
+ *
14448
+ * `favourited` IS a BOOLEAN pin (durability bit), not a retrain lifecycle.
14449
+ * A favourited track is skipped by retention the same way `staging` is, but
14450
+ * it does not enter `none|staging|trained` and has no staging budget.
14439
14451
  */
14440
14452
  var TrackFlagFields = {
14441
14453
  /** Operator marked this track as training material — i.e. `retrainStatus` is
14442
14454
  * `'staging'`. */
14443
14455
  markForTrain: z.boolean().optional(),
14444
14456
  /** Operator marked this track for diagnostic attention. */
14445
- debug: z.boolean().optional()
14457
+ debug: z.boolean().optional(),
14458
+ /** Operator favourited this track. Pins it against pruning. */
14459
+ favourited: z.boolean().optional()
14446
14460
  };
14447
14461
  /**
14448
14462
  * The lifecycle field itself, on the READ surfaces only (`Track`, `KeyEvent`).
@@ -14467,6 +14481,7 @@ var TrackFlagsSchema = z.object({
14467
14481
  trackId: z.string(),
14468
14482
  markForTrain: z.boolean(),
14469
14483
  debug: z.boolean(),
14484
+ favourited: z.boolean(),
14470
14485
  /** The lifecycle state the boolean was derived from. Required here (unlike on
14471
14486
  * a track row) because this shape is only ever produced by the write body,
14472
14487
  * which always knows it — and a surface that has just written needs to render
@@ -15410,7 +15425,7 @@ var pipelineAnalyticsCapability = {
15410
15425
  auth: "admin"
15411
15426
  }),
15412
15427
  /**
15413
- * Set the per-track operator flags (`markForTrain`, `debug`) on ONE track.
15428
+ * Set the per-track operator flags (`markForTrain`, `debug`, `favourited`) on ONE track.
15414
15429
  * The patch is PARTIAL — an omitted key is left untouched — because the
15415
15430
  * three surfaces that write it (admin Events grid, viewer track detail,
15416
15431
  * viewer cluster detail) each own one toggle and must not clobber the other.
@@ -19587,8 +19602,28 @@ var ClipSchema = z.object({
19587
19602
  startMs: z.number(),
19588
19603
  endMs: z.number()
19589
19604
  }),
19590
- /** Thumbnail URL (lazy; e.g. analytics `getEventMedia`). Never inlined. */
19591
- thumbnail: z.string().optional()
19605
+ /**
19606
+ * Lazy thumbnail URL, never inlined.
19607
+ *
19608
+ * Recording-derived clips (events-mode keep-window, and the prepared
19609
+ * continuous event+fragment visit) MUST use the snapshot of the **main
19610
+ * event of the interval** — `getEventMedia({ eventId, kind: 'snapshot' })`
19611
+ * of the event that owns `kind` (object > motion > audio). Do not extract
19612
+ * a keyframe from the recorded segments. Other providers (onboard, HKSV)
19613
+ * mint their own stills.
19614
+ */
19615
+ thumbnail: z.string().optional(),
19616
+ /** Analytics event ids that overlap this visit. Empty on footage-only clips.
19617
+ * The default provider's visit grain puts many motion heartbeats on one clip
19618
+ * instead of minting one clip per marker. */
19619
+ eventIds: z.array(z.string()).optional(),
19620
+ /** Intra-visit footage holes (GOP rolls, discarded segments) still shorter
19621
+ * than `VISIT_MERGE_GAP_MS`. Playback concatenates around them; the timeline
19622
+ * bar keeps showing them via `recording.getAvailability`. */
19623
+ holes: z.array(z.object({
19624
+ startMs: z.number(),
19625
+ endMs: z.number()
19626
+ })).optional()
19592
19627
  });
19593
19628
  var ClipPlaybackSchema = z.object({
19594
19629
  /** HLS master URL through the hub data-plane (Range + token in path). */
@@ -26912,7 +26947,9 @@ var ExportOptionsSchema = z.object({
26912
26947
  includeAudio: z.boolean(),
26913
26948
  maxLifeMs: z.number().int().positive(),
26914
26949
  deleteAfterDownload: z.boolean(),
26915
- title: z.string().max(200).optional()
26950
+ title: z.string().max(200).optional(),
26951
+ /** Notification-output target ids to ping when this export becomes ready. */
26952
+ notifyTargetIds: z.array(z.string().min(1)).max(20).optional()
26916
26953
  }).superRefine((v, ctx) => {
26917
26954
  if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
26918
26955
  code: z.ZodIssueCode.custom,
@@ -26974,14 +27011,23 @@ var recordingExportCapability = {
26974
27011
  scope: "system",
26975
27012
  mode: "singleton",
26976
27013
  methods: {
26977
- /** Queue a render of `[fromMs,toMs)` for `deviceId`/`profile`. Fails fast
26978
- * when no footage covers the range. Returns the queued record. */
27014
+ /** Queue a render of `[fromMs,toMs)` for `deviceId`/`profiles` (legacy
27015
+ * singular `profile` still accepted). Fails fast when no footage covers
27016
+ * the range. One job per profile; returns the first queued record. */
26979
27017
  createExport: method(z.object({
26980
27018
  deviceId: z.number(),
26981
- profile: z.string(),
27019
+ /** @deprecated Prefer `profiles`. Kept so timelapse/notifiers keep working. */
27020
+ profile: z.string().optional(),
27021
+ profiles: z.array(z.string()).min(1).optional(),
26982
27022
  fromMs: z.number(),
26983
27023
  toMs: z.number(),
26984
27024
  options: ExportOptionsSchema
27025
+ }).superRefine((v, ctx) => {
27026
+ if ((v.profiles !== void 0 && v.profiles.length > 0 ? v.profiles : v.profile !== void 0 ? [v.profile] : []).length < 1) ctx.addIssue({
27027
+ code: z.ZodIssueCode.custom,
27028
+ message: "pass profiles[] (min 1) or legacy profile",
27029
+ path: ["profiles"]
27030
+ });
26985
27031
  }), ExportRecordSchema, {
26986
27032
  kind: "mutation",
26987
27033
  auth: "protected"
@@ -1,5 +1,5 @@
1
1
  let zod = require("zod");
2
- //#region ../types/dist/event-category-Bxo5yJjt.mjs
2
+ //#region ../types/dist/event-category-C0lyLd5U.mjs
3
3
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4
4
  EventCategory["SystemBoot"] = "system.boot";
5
5
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -16,9 +16,10 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
16
16
  EventCategory["SystemRestartCompleted"] = "system.restart-completed";
17
17
  /**
18
18
  * A newer addon or server-root package version was found by the
19
- * authoritative registry check. Emitted once per
20
- * `(target, packageName, currentVersion, latestVersion)` transition; repeated
21
- * polling of the same result is deduplicated by the checker.
19
+ * authoritative registry check. Emitted once when any observed
20
+ * `latestVersion` changes (or a package/node first appears behind);
21
+ * the payload carries the full currently-available list. Repeated
22
+ * polling of the same latests is silent.
22
23
  */
23
24
  EventCategory["UpdateAvailable"] = "update.available";
24
25
  /**
@@ -3651,6 +3652,10 @@ var RecordingBandSchema = zod.z.object({
3651
3652
  preBufferSec: zod.z.number().min(0).optional(),
3652
3653
  postBufferSec: zod.z.number().min(0).optional()
3653
3654
  });
3655
+ ({
3656
+ preBufferSec: 10,
3657
+ postBufferSec: 30
3658
+ }).postBufferSec * 1e3;
3654
3659
  /**
3655
3660
  * Per-device retention overrides. Every field is optional; an unset or `0`
3656
3661
  * value inherits the node-wide recorder default. Only footage-lifetime limits
@@ -12433,6 +12438,9 @@ var NcSystemEventKindSchema = zod.z.enum([
12433
12438
  "alarm-disarmed",
12434
12439
  "alarm-arming",
12435
12440
  "alarm-arm-refused",
12441
+ "addon-updated",
12442
+ "server-updated",
12443
+ "export-completed",
12436
12444
  "camera-online",
12437
12445
  "camera-offline",
12438
12446
  "camera-disabled",
@@ -14436,13 +14444,19 @@ var RetrainStatusSchema = zod.z.enum([
14436
14444
  * "never marked" from "already trained" must read `retrainStatus`.
14437
14445
  *
14438
14446
  * `debug` does NOT pin; it is attention, not durability.
14447
+ *
14448
+ * `favourited` IS a BOOLEAN pin (durability bit), not a retrain lifecycle.
14449
+ * A favourited track is skipped by retention the same way `staging` is, but
14450
+ * it does not enter `none|staging|trained` and has no staging budget.
14439
14451
  */
14440
14452
  var TrackFlagFields = {
14441
14453
  /** Operator marked this track as training material — i.e. `retrainStatus` is
14442
14454
  * `'staging'`. */
14443
14455
  markForTrain: zod.z.boolean().optional(),
14444
14456
  /** Operator marked this track for diagnostic attention. */
14445
- debug: zod.z.boolean().optional()
14457
+ debug: zod.z.boolean().optional(),
14458
+ /** Operator favourited this track. Pins it against pruning. */
14459
+ favourited: zod.z.boolean().optional()
14446
14460
  };
14447
14461
  /**
14448
14462
  * The lifecycle field itself, on the READ surfaces only (`Track`, `KeyEvent`).
@@ -14467,6 +14481,7 @@ var TrackFlagsSchema = zod.z.object({
14467
14481
  trackId: zod.z.string(),
14468
14482
  markForTrain: zod.z.boolean(),
14469
14483
  debug: zod.z.boolean(),
14484
+ favourited: zod.z.boolean(),
14470
14485
  /** The lifecycle state the boolean was derived from. Required here (unlike on
14471
14486
  * a track row) because this shape is only ever produced by the write body,
14472
14487
  * which always knows it — and a surface that has just written needs to render
@@ -15410,7 +15425,7 @@ var pipelineAnalyticsCapability = {
15410
15425
  auth: "admin"
15411
15426
  }),
15412
15427
  /**
15413
- * Set the per-track operator flags (`markForTrain`, `debug`) on ONE track.
15428
+ * Set the per-track operator flags (`markForTrain`, `debug`, `favourited`) on ONE track.
15414
15429
  * The patch is PARTIAL — an omitted key is left untouched — because the
15415
15430
  * three surfaces that write it (admin Events grid, viewer track detail,
15416
15431
  * viewer cluster detail) each own one toggle and must not clobber the other.
@@ -19587,8 +19602,28 @@ var ClipSchema = zod.z.object({
19587
19602
  startMs: zod.z.number(),
19588
19603
  endMs: zod.z.number()
19589
19604
  }),
19590
- /** Thumbnail URL (lazy; e.g. analytics `getEventMedia`). Never inlined. */
19591
- thumbnail: zod.z.string().optional()
19605
+ /**
19606
+ * Lazy thumbnail URL, never inlined.
19607
+ *
19608
+ * Recording-derived clips (events-mode keep-window, and the prepared
19609
+ * continuous event+fragment visit) MUST use the snapshot of the **main
19610
+ * event of the interval** — `getEventMedia({ eventId, kind: 'snapshot' })`
19611
+ * of the event that owns `kind` (object > motion > audio). Do not extract
19612
+ * a keyframe from the recorded segments. Other providers (onboard, HKSV)
19613
+ * mint their own stills.
19614
+ */
19615
+ thumbnail: zod.z.string().optional(),
19616
+ /** Analytics event ids that overlap this visit. Empty on footage-only clips.
19617
+ * The default provider's visit grain puts many motion heartbeats on one clip
19618
+ * instead of minting one clip per marker. */
19619
+ eventIds: zod.z.array(zod.z.string()).optional(),
19620
+ /** Intra-visit footage holes (GOP rolls, discarded segments) still shorter
19621
+ * than `VISIT_MERGE_GAP_MS`. Playback concatenates around them; the timeline
19622
+ * bar keeps showing them via `recording.getAvailability`. */
19623
+ holes: zod.z.array(zod.z.object({
19624
+ startMs: zod.z.number(),
19625
+ endMs: zod.z.number()
19626
+ })).optional()
19592
19627
  });
19593
19628
  var ClipPlaybackSchema = zod.z.object({
19594
19629
  /** HLS master URL through the hub data-plane (Range + token in path). */
@@ -26912,7 +26947,9 @@ var ExportOptionsSchema = zod.z.object({
26912
26947
  includeAudio: zod.z.boolean(),
26913
26948
  maxLifeMs: zod.z.number().int().positive(),
26914
26949
  deleteAfterDownload: zod.z.boolean(),
26915
- title: zod.z.string().max(200).optional()
26950
+ title: zod.z.string().max(200).optional(),
26951
+ /** Notification-output target ids to ping when this export becomes ready. */
26952
+ notifyTargetIds: zod.z.array(zod.z.string().min(1)).max(20).optional()
26916
26953
  }).superRefine((v, ctx) => {
26917
26954
  if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
26918
26955
  code: zod.z.ZodIssueCode.custom,
@@ -26974,14 +27011,23 @@ var recordingExportCapability = {
26974
27011
  scope: "system",
26975
27012
  mode: "singleton",
26976
27013
  methods: {
26977
- /** Queue a render of `[fromMs,toMs)` for `deviceId`/`profile`. Fails fast
26978
- * when no footage covers the range. Returns the queued record. */
27014
+ /** Queue a render of `[fromMs,toMs)` for `deviceId`/`profiles` (legacy
27015
+ * singular `profile` still accepted). Fails fast when no footage covers
27016
+ * the range. One job per profile; returns the first queued record. */
26979
27017
  createExport: method(zod.z.object({
26980
27018
  deviceId: zod.z.number(),
26981
- profile: zod.z.string(),
27019
+ /** @deprecated Prefer `profiles`. Kept so timelapse/notifiers keep working. */
27020
+ profile: zod.z.string().optional(),
27021
+ profiles: zod.z.array(zod.z.string()).min(1).optional(),
26982
27022
  fromMs: zod.z.number(),
26983
27023
  toMs: zod.z.number(),
26984
27024
  options: ExportOptionsSchema
27025
+ }).superRefine((v, ctx) => {
27026
+ if ((v.profiles !== void 0 && v.profiles.length > 0 ? v.profiles : v.profile !== void 0 ? [v.profile] : []).length < 1) ctx.addIssue({
27027
+ code: zod.z.ZodIssueCode.custom,
27028
+ message: "pass profiles[] (min 1) or legacy profile",
27029
+ path: ["profiles"]
27030
+ });
26985
27031
  }), ExportRecordSchema, {
26986
27032
  kind: "mutation",
26987
27033
  auth: "protected"
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("./chunk-Cek0wNdY.js");
3
- const require_dist = require("./dist-tMrPAfpF.js");
3
+ const require_dist = require("./dist-9sC0wZw6.js");
4
4
  const require_builtins_alerts_alerts_addon = require("./builtins/alerts/alerts.addon.js");
5
5
  require("./builtins/alerts/index.js");
6
6
  const require_formatter = require("./formatter-DqAKDlvN.js");
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM$1, r as __exportAll, t as __commonJSMin$1 } from "./chunk-CNf5ZN-e.mjs";
2
- import { At as asNumber, B as extractNestedAddonId, Bt as parseJsonUnknown$1, Dt as ReadinessTimeoutError, Et as ReadinessRegistry, Ft as expandCapMethods, Gt as EventCategory$1, H as isArrayOutputSchema, Ht as resolveCapMount, J as lifecycleJobSchema, K as isVoidInput, Mt as createEvent, Nt as emitDownForOwnedCaps, Q as looseSchema, St as DEVICE_STATUS_METHOD, U as isCollectionArrayMethod, Ut as scopeKey, Vt as readinessKey, W as isObjectInput, Z as logLevelAtMost, bt as DATAPLANE_SECRET_HEADER$1, d as METHOD_ACCESS_MAP, f as RUNTIME_DEFAULTS, it as procedureAuthKey, jt as asString$1, kt as asJsonObject$1, ot as scopesAllowAddon, q as kebabToCamel, st as scopesAllowDeviceCap, t as ALL_CAPABILITY_DEFINITIONS, tt as objectInputDeclaresAddonId, vt as errMsg$1, xt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, y as addonSettingsCapability, zt as parseJsonObject } from "./dist-RbFV8cX7.mjs";
2
+ import { At as asNumber, B as extractNestedAddonId, Bt as parseJsonUnknown$1, Dt as ReadinessTimeoutError, Et as ReadinessRegistry, Ft as expandCapMethods, Gt as EventCategory$1, H as isArrayOutputSchema, Ht as resolveCapMount, J as lifecycleJobSchema, K as isVoidInput, Mt as createEvent, Nt as emitDownForOwnedCaps, Q as looseSchema, St as DEVICE_STATUS_METHOD, U as isCollectionArrayMethod, Ut as scopeKey, Vt as readinessKey, W as isObjectInput, Z as logLevelAtMost, bt as DATAPLANE_SECRET_HEADER$1, d as METHOD_ACCESS_MAP, f as RUNTIME_DEFAULTS, it as procedureAuthKey, jt as asString$1, kt as asJsonObject$1, ot as scopesAllowAddon, q as kebabToCamel, st as scopesAllowDeviceCap, t as ALL_CAPABILITY_DEFINITIONS, tt as objectInputDeclaresAddonId, vt as errMsg$1, xt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, y as addonSettingsCapability, zt as parseJsonObject } from "./dist-3wh5LCad.mjs";
3
3
  import { AlertCenterAddon } from "./builtins/alerts/alerts.addon.mjs";
4
4
  import "./builtins/alerts/index.mjs";
5
5
  import { t as formatLogLine } from "./formatter-B7qW8bPJ.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.2.101",
3
+ "version": "1.2.102",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",