@camstack/addon-pipeline-orchestrator 1.2.206 → 1.2.208

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -5363,7 +5363,7 @@ var ZodIssueCode = {
5363
5363
  var ZodFirstPartyTypeKind;
5364
5364
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5365
5365
  //#endregion
5366
- //#region ../types/dist/sleep-BfJ2k1jm.mjs
5366
+ //#region ../types/dist/sleep-BDR76Ykr.mjs
5367
5367
  /**
5368
5368
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5369
5369
  * window to float samples (D455).
@@ -7901,7 +7901,7 @@ import { errMsg } from '@camstack/types'
7901
7901
  * Extract a human-readable message from an unknown error value.
7902
7902
  * Replaces the ubiquitous `errMsg(err)` pattern.
7903
7903
  */
7904
- function errMsg(err) {
7904
+ function errMsg$1(err) {
7905
7905
  if (err instanceof Error) return err.message;
7906
7906
  if (typeof err === "string") return err;
7907
7907
  return String(err);
@@ -18761,6 +18761,48 @@ var NcAlarmConfigSchema = object({
18761
18761
  settings: NcAlarmSettingsSchema,
18762
18762
  coverage: array(NcAlarmModeCoverageSchema)
18763
18763
  });
18764
+ /**
18765
+ * ONE rule's demand on ONE camera's clip ring.
18766
+ *
18767
+ * A rule, not a camera: the broker takes the MAX over the asks that reach a
18768
+ * camera, so the answer stays a faithful description of the rules and the
18769
+ * bounding (the byte budget, the broker's own ceiling) stays where the cost
18770
+ * lives. A camera that appears in no ask is being told **nothing** — which is
18771
+ * a different thing from never having been told, and only the envelope
18772
+ * (`rulesLoaded`) can tell those apart.
18773
+ */
18774
+ var NcClipRetentionAskSchema = object({
18775
+ /**
18776
+ * The camera this ask is about. **Absent = every camera**, which is what a
18777
+ * rule with no `conditions.devices` means: it can fire anywhere, so it is
18778
+ * asking everywhere.
18779
+ */
18780
+ deviceId: number().int().nonnegative().optional(),
18781
+ /** Seconds of history the rule needs held for it. Never zero — a rule that
18782
+ * needs nothing produces no ask at all. */
18783
+ seconds: number().min(0).max(60),
18784
+ /** The profile the rule cuts from, when it named one. Absent = the cheapest
18785
+ * assigned, which is what the cut defaults to. */
18786
+ profile: CamProfileSchema.optional(),
18787
+ /** Who is asking — so a retention the operator did not expect names a rule. */
18788
+ ruleId: string(),
18789
+ ruleName: string(),
18790
+ /** Why this many seconds: the rule's own window, or the occupancy ceiling. */
18791
+ reason: _enum(["window", "occupancy"])
18792
+ });
18793
+ /**
18794
+ * The whole answer, with the one bit that keeps absence from reading as zero.
18795
+ *
18796
+ * `rulesLoaded` is false until the rule ledger has completed a load at least
18797
+ * once. A centre that is up but has not read its rules yet answers with an
18798
+ * empty ask list that means nothing at all — applying it would drop every
18799
+ * camera's ring to zero for the first events after a restart, which is the
18800
+ * footage this mechanism exists to keep.
18801
+ */
18802
+ var NcClipRetentionPlanSchema = object({
18803
+ rulesLoaded: boolean(),
18804
+ asks: array(NcClipRetentionAskSchema).readonly()
18805
+ });
18764
18806
  method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), method(object({ ruleId: string() }), object({ rule: NcRuleSchema.nullable() }), { auth: "admin" }), method(object({ rule: NcRuleInputSchema }), object({ rule: NcRuleSchema }), {
18765
18807
  kind: "mutation",
18766
18808
  auth: "admin",
@@ -18781,7 +18823,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
18781
18823
  }), object({ success: literal(true) }), {
18782
18824
  kind: "mutation",
18783
18825
  auth: "admin"
18784
- }), method(object({}), object({ mutedDeviceIds: array(number().int()).readonly() }), { auth: "admin" }), method(object({
18826
+ }), method(object({}), NcClipRetentionPlanSchema, { auth: "admin" }), method(object({}), object({ mutedDeviceIds: array(number().int()).readonly() }), { auth: "admin" }), method(object({
18785
18827
  deviceId: number().int(),
18786
18828
  muted: boolean()
18787
18829
  }), object({ success: literal(true) }), {
@@ -22807,7 +22849,47 @@ var RunnerLocalMetricsSchema = object({
22807
22849
  queueDepth: number(),
22808
22850
  frameLazy: FrameLazyMetricsSchema.optional()
22809
22851
  });
22852
+ /**
22853
+ * Pipeline Runner capability — runtime detection workhorse.
22854
+ *
22855
+ * One instance per node. Receives camera assignments from
22856
+ * `addon-pipeline-orchestrator`, subscribes to the local stream-broker for
22857
+ * decoded frames, drains motion + detection queues, calls the local
22858
+ * `motion-detection` and `pipeline-executor` capabilities, and emits typed
22859
+ * `pipeline.inference-result` and `detection.motion-analysis` events on
22860
+ * the bus.
22861
+ *
22862
+ * Distinct from `pipeline-orchestrator` (the hub-side load balancer) — the
22863
+ * runner has zero knowledge of other agents, no global state, and never
22864
+ * makes assignment decisions itself.
22865
+ */
22866
+ /**
22867
+ * Why a runner declined to look at a camera out of band. Named rather than a
22868
+ * bare `false`: a camera asleep on battery (D173), one attached elsewhere, one
22869
+ * already mid-session and one already bursting are four different facts, and a
22870
+ * caller told only "no" cannot tell a protection from a bug.
22871
+ */
22872
+ var OccupancyBurstRefusalSchema = _enum([
22873
+ "not-attached",
22874
+ "battery-asleep",
22875
+ "not-watching",
22876
+ "already-bursting"
22877
+ ]);
22810
22878
  method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mutation" }), method(object({ deviceId: number() }), object({ success: literal(true) }), { kind: "mutation" }), method(ReportMotionInputSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), RunnerLocalLoadSchema), method(_void(), RunnerLocalMetricsSchema), method(object({ deviceId: number() }), CameraMetricsSchema.nullable()), method(_void(), array(CameraMetricsWithDeviceIdSchema).readonly()), method(_void(), array(number()).readonly()), method(object({
22879
+ deviceId: number(),
22880
+ /** How many frames to collect. The caller sizes this against what its
22881
+ * own confirmation needs; the runner clamps it to the field's range. */
22882
+ frames: number().int().positive().optional(),
22883
+ /** Why, for the log. A burst nobody can attribute is a cost nobody can
22884
+ * defend — the periodic one at least has a timer to point at. */
22885
+ reason: string()
22886
+ }), object({
22887
+ started: boolean(),
22888
+ refusedBecause: OccupancyBurstRefusalSchema.optional()
22889
+ }), {
22890
+ auth: "admin",
22891
+ kind: "mutation"
22892
+ }), method(object({
22811
22893
  handle: FrameHandleSchema,
22812
22894
  bbox: NativeCropBboxSchema,
22813
22895
  maxWidth: number().int().positive().optional(),
@@ -35827,6 +35909,12 @@ Object.freeze({
35827
35909
  addonId: null,
35828
35910
  access: "view"
35829
35911
  },
35912
+ "notificationRules.getClipRetentionAsks": {
35913
+ capName: "notification-rules",
35914
+ capScope: "system",
35915
+ addonId: null,
35916
+ access: "view"
35917
+ },
35830
35918
  "notificationRules.getConditionCatalog": {
35831
35919
  capName: "notification-rules",
35832
35920
  capScope: "system",
@@ -37015,6 +37103,12 @@ Object.freeze({
37015
37103
  addonId: null,
37016
37104
  access: "create"
37017
37105
  },
37106
+ "pipelineRunner.requestOccupancyBurst": {
37107
+ capName: "pipeline-runner",
37108
+ capScope: "system",
37109
+ addonId: null,
37110
+ access: "create"
37111
+ },
37018
37112
  "pipelineRunner.runDetailSubtree": {
37019
37113
  capName: "pipeline-runner",
37020
37114
  capScope: "system",
@@ -40354,6 +40448,11 @@ Object.freeze({
40354
40448
  form: "single",
40355
40449
  optional: false
40356
40450
  }],
40451
+ "pipelineRunner.requestOccupancyBurst": [{
40452
+ name: "deviceId",
40453
+ form: "single",
40454
+ optional: false
40455
+ }],
40357
40456
  "pipelineRunner.runDetailSubtree": [{
40358
40457
  name: "deviceId",
40359
40458
  form: "single",
@@ -41975,7 +42074,7 @@ var AudioSubscriptionController = class {
41975
42074
  } catch (err) {
41976
42075
  this.deps.logger.error("audio re-attach failed", {
41977
42076
  tags: { deviceId },
41978
- meta: { error: errMsg(err) }
42077
+ meta: { error: errMsg$1(err) }
41979
42078
  });
41980
42079
  }
41981
42080
  }
@@ -42086,7 +42185,7 @@ var AudioSubscriptionController = class {
42086
42185
  this.closeMotionAudioWindow(deviceId, "motion-cooldown-elapsed").catch((err) => {
42087
42186
  this.deps.logger.warn("lazy audio: cooldown teardown failed", {
42088
42187
  tags: { deviceId },
42089
- meta: { error: errMsg(err) }
42188
+ meta: { error: errMsg$1(err) }
42090
42189
  });
42091
42190
  });
42092
42191
  }, cooldownMs);
@@ -42105,7 +42204,7 @@ var AudioSubscriptionController = class {
42105
42204
  this.closeMotionAudioWindow(deviceId, "quiet-window-elapsed").catch((err) => {
42106
42205
  this.deps.logger.warn("lazy audio: quiet-window teardown failed", {
42107
42206
  tags: { deviceId },
42108
- meta: { error: errMsg(err) }
42207
+ meta: { error: errMsg$1(err) }
42109
42208
  });
42110
42209
  });
42111
42210
  }, windowMs);
@@ -42276,7 +42375,7 @@ var AudioSubscriptionController = class {
42276
42375
  meta: {
42277
42376
  audioNodeId,
42278
42377
  brokerId: audioBrokerId,
42279
- error: errMsg(err)
42378
+ error: errMsg$1(err)
42280
42379
  }
42281
42380
  });
42282
42381
  });
@@ -43296,7 +43395,7 @@ var LoadShedController = class LoadShedController {
43296
43395
  if (await this.tryClusterRelocate(deviceId).catch((err) => {
43297
43396
  this.deps.logger.warn("Load management: cluster relocate failed", {
43298
43397
  tags: { deviceId },
43299
- meta: { error: errMsg(err) }
43398
+ meta: { error: errMsg$1(err) }
43300
43399
  });
43301
43400
  return false;
43302
43401
  })) {
@@ -43310,7 +43409,7 @@ var LoadShedController = class LoadShedController {
43310
43409
  this.deps.api()?.pipelineRunner.detachCamera.mutate({ deviceId }).catch((err) => {
43311
43410
  this.deps.logger.warn("Load management: detachCamera failed", {
43312
43411
  tags: { deviceId },
43313
- meta: { error: errMsg(err) }
43412
+ meta: { error: errMsg$1(err) }
43314
43413
  });
43315
43414
  });
43316
43415
  this.ensureLoadShedResumeTimer();
@@ -43342,7 +43441,7 @@ var LoadShedController = class LoadShedController {
43342
43441
  tags: { deviceId },
43343
43442
  meta: {
43344
43443
  from: currentNode,
43345
- error: errMsg(err)
43444
+ error: errMsg$1(err)
43346
43445
  }
43347
43446
  });
43348
43447
  });
@@ -43385,7 +43484,7 @@ var LoadShedController = class LoadShedController {
43385
43484
  this.deps.redispatchSingleCamera(deviceId).catch((err) => {
43386
43485
  this.deps.logger.warn("Load management: auto-resume dispatch failed", {
43387
43486
  tags: { deviceId },
43388
- meta: { error: errMsg(err) }
43487
+ meta: { error: errMsg$1(err) }
43389
43488
  });
43390
43489
  });
43391
43490
  }
@@ -43546,7 +43645,7 @@ var AgentLoadService = class AgentLoadService {
43546
43645
  ms,
43547
43646
  outcome: "failed",
43548
43647
  load: null,
43549
- error: errMsg(outcome.error)
43648
+ error: errMsg$1(outcome.error)
43550
43649
  };
43551
43650
  return {
43552
43651
  nodeId,
@@ -44550,7 +44649,7 @@ function warnSampled(deps, deviceId, source, message, meta) {
44550
44649
  function warnUnreachable(deps, deviceId, source, err) {
44551
44650
  warnSampled(deps, deviceId, source, UNREACHABLE_MESSAGE, {
44552
44651
  source,
44553
- error: errMsg(err)
44652
+ error: errMsg$1(err)
44554
44653
  });
44555
44654
  }
44556
44655
  /**
@@ -45795,6 +45894,89 @@ function sameFeatures(a, b) {
45795
45894
  return b.every((f) => held.has(f));
45796
45895
  }
45797
45896
  //#endregion
45897
+ //#region src/onboard-forwarding-reconcile.ts
45898
+ /** The `detectionSources` member that means "this camera's own firmware". */
45899
+ var ONBOARD_DETECTION_SOURCE = "onboard";
45900
+ /**
45901
+ * What an ABSENT `detectionSources` means. `CameraDetectionConfig` declares the
45902
+ * field optional and its own contract as "absent is `['pipeline']` all the way
45903
+ * down" — the resolver always fills it, so this only covers the hand-built
45904
+ * configs, and it reads them the same way the runner does.
45905
+ */
45906
+ var DETECTION_SOURCES_WHEN_ABSENT = ["pipeline"];
45907
+ function errMsg(err) {
45908
+ return err instanceof Error ? err.message : String(err);
45909
+ }
45910
+ /**
45911
+ * Put the vendor forwarding flag back where `detectionSources` says it belongs.
45912
+ * Never throws — a camera's attach is not failed by a mechanism that could not
45913
+ * be reached, it is reported.
45914
+ */
45915
+ async function reconcileOnboardForwarding(input, deps) {
45916
+ const { deviceId, detectionSources } = input;
45917
+ const wantsOnboard = detectionSources.includes(ONBOARD_DETECTION_SOURCE);
45918
+ const log = deps.logger.withTags({ deviceId });
45919
+ let hasCap;
45920
+ try {
45921
+ hasCap = await deps.hasNativeObjectDetectionCap(deviceId);
45922
+ } catch (err) {
45923
+ log.warn("onboard forwarding not reconciled — could not tell whether the camera has the cap", { meta: {
45924
+ wantsOnboard,
45925
+ detectionSources: [...detectionSources],
45926
+ error: errMsg(err)
45927
+ } });
45928
+ return {
45929
+ kind: "read-failed",
45930
+ wantsOnboard
45931
+ };
45932
+ }
45933
+ if (!hasCap) return {
45934
+ kind: "no-cap",
45935
+ wantsOnboard
45936
+ };
45937
+ let current;
45938
+ try {
45939
+ current = await deps.readForwardingEnabled(deviceId);
45940
+ } catch (err) {
45941
+ log.warn("onboard forwarding not reconciled — the vendor flag could not be read", { meta: {
45942
+ wantsOnboard,
45943
+ detectionSources: [...detectionSources],
45944
+ error: errMsg(err)
45945
+ } });
45946
+ return {
45947
+ kind: "read-failed",
45948
+ wantsOnboard
45949
+ };
45950
+ }
45951
+ if (current === wantsOnboard) return {
45952
+ kind: "aligned",
45953
+ wantsOnboard
45954
+ };
45955
+ try {
45956
+ await deps.writeForwardingEnabled(deviceId, wantsOnboard);
45957
+ } catch (err) {
45958
+ log.warn("onboard forwarding drifted and the repair failed", { meta: {
45959
+ was: current,
45960
+ wanted: wantsOnboard,
45961
+ detectionSources: [...detectionSources],
45962
+ error: errMsg(err)
45963
+ } });
45964
+ return {
45965
+ kind: "write-failed",
45966
+ wantsOnboard
45967
+ };
45968
+ }
45969
+ log.info("onboard forwarding flag put back to match the camera pick", { meta: {
45970
+ was: current,
45971
+ now: wantsOnboard,
45972
+ detectionSources: [...detectionSources]
45973
+ } });
45974
+ return {
45975
+ kind: "repaired",
45976
+ wantsOnboard
45977
+ };
45978
+ }
45979
+ //#endregion
45798
45980
  //#region src/watchdog-camera.ts
45799
45981
  /**
45800
45982
  * Derive the watchdog camera descriptor from a runner config. Captures which
@@ -45964,7 +46146,7 @@ var DetectionWiringController = class {
45964
46146
  try {
45965
46147
  raw = await this.deps.ctx().settings.readDeviceStore(deviceId);
45966
46148
  } catch (err) {
45967
- const msg = errMsg(err);
46149
+ const msg = errMsg$1(err);
45968
46150
  this.deps.logger.error("resolveDeviceDetectionSettings failed", {
45969
46151
  tags: { deviceId },
45970
46152
  meta: { error: msg }
@@ -45995,7 +46177,7 @@ var DetectionWiringController = class {
45995
46177
  motionDetectionEnabled
45996
46178
  });
45997
46179
  } catch (err) {
45998
- const msg = errMsg(err);
46180
+ const msg = errMsg$1(err);
45999
46181
  this.deps.logger.error("resolveDeviceDetectionSettings narrowing failed", {
46000
46182
  tags: { deviceId },
46001
46183
  meta: { error: msg }
@@ -46025,7 +46207,7 @@ var DetectionWiringController = class {
46025
46207
  } catch (err) {
46026
46208
  this.deps.logger.debug("fetchAssignedProfiles: slot read failed (transient) — treating as unknown", {
46027
46209
  tags: { deviceId },
46028
- meta: { error: errMsg(err) }
46210
+ meta: { error: errMsg$1(err) }
46029
46211
  });
46030
46212
  return null;
46031
46213
  }
@@ -46045,6 +46227,41 @@ var DetectionWiringController = class {
46045
46227
  return buildDetectionConfigFromInputs(resolved, assigned);
46046
46228
  }
46047
46229
  /**
46230
+ * Make the vendor's onboard-AI forwarding flag agree with this camera's
46231
+ * `detectionSources` pick — in both directions. See
46232
+ * `onboard-forwarding-reconcile.ts` for why the save-time write is not
46233
+ * enough (the flag is device state and a provider restart re-seeds it OFF,
46234
+ * measured on all seven Reolink cameras of the live hub).
46235
+ *
46236
+ * Never throws: a mechanism that could not be reached is reported, it does
46237
+ * not fail the camera's attach.
46238
+ */
46239
+ async reconcileOnboardForwarding(deviceId, detectionSources) {
46240
+ return reconcileOnboardForwarding({
46241
+ deviceId,
46242
+ detectionSources
46243
+ }, {
46244
+ hasNativeObjectDetectionCap: (id) => this.deps.deviceHasNativeObjectDetectionCap(id),
46245
+ readForwardingEnabled: async (id) => {
46246
+ const api = this.deps.api();
46247
+ if (!api) throw new Error("orchestrator: no api — cannot read the onboard forwarding flag");
46248
+ const raw = await api.nativeObjectDetection.getStatus.query({ deviceId: id });
46249
+ const parsed = NativeObjectDetectionStatusSchema.safeParse(raw);
46250
+ if (!parsed.success) throw new Error(`orchestrator: nativeObjectDetection.getStatus returned an unusable status — ${parsed.error.message}`);
46251
+ return parsed.data.enabled;
46252
+ },
46253
+ writeForwardingEnabled: async (id, enabled) => {
46254
+ const api = this.deps.api();
46255
+ if (!api) throw new Error("orchestrator: no api — cannot write the onboard forwarding flag");
46256
+ await api.nativeObjectDetection.setEnabled.mutate({
46257
+ deviceId: id,
46258
+ enabled
46259
+ });
46260
+ },
46261
+ logger: this.deps.logger
46262
+ });
46263
+ }
46264
+ /**
46048
46265
  * Start detection for a camera: dispatch to runner via the orchestrator
46049
46266
  * local path and subscribe to the audio broker if audio is enabled.
46050
46267
  */
@@ -46056,6 +46273,7 @@ var DetectionWiringController = class {
46056
46273
  await this.stopDetection(deviceId);
46057
46274
  }
46058
46275
  this.activeDetections.set(deviceId, config);
46276
+ await this.reconcileOnboardForwarding(deviceId, config.detectionSources ?? DETECTION_SOURCES_WHEN_ABSENT);
46059
46277
  if (!config.pipelineEnabled || config.detectionMode === "disabled") if (!config.pipelineEnabled) log.info("object detection switched off — no attach, no decode session", { meta: { detectionMode: config.detectionMode } });
46060
46278
  else log.info("detection mode disabled — no standing attach, no decode session", { meta: {
46061
46279
  detectionMode: config.detectionMode,
@@ -46065,7 +46283,7 @@ var DetectionWiringController = class {
46065
46283
  if (config.motionSources.includes("analyzer")) try {
46066
46284
  await this.deps.session.ensureMotionWatch(deviceId, config);
46067
46285
  } catch (err) {
46068
- log.error("ensureMotionWatch failed", { meta: { error: errMsg(err) } });
46286
+ log.error("ensureMotionWatch failed", { meta: { error: errMsg$1(err) } });
46069
46287
  }
46070
46288
  log.info("detection armed (session-time) — watching for motion", { meta: { motion: config.motionSources.join("+") } });
46071
46289
  } else {
@@ -46084,7 +46302,7 @@ var DetectionWiringController = class {
46084
46302
  const result = await this.deps.placement.dispatchCamera(runnerConfig);
46085
46303
  if (result.kind === "assigned") dispatchedNodeId = result.agentNodeId;
46086
46304
  } catch (err) {
46087
- const msg = errMsg(err);
46305
+ const msg = errMsg$1(err);
46088
46306
  log.error("dispatchCamera failed", { meta: { error: msg } });
46089
46307
  }
46090
46308
  if (dispatchedNodeId && (dispatchedNodeId !== hydrateNodeId || (runnerConfig.steps?.length ?? 0) === 0)) try {
@@ -46113,13 +46331,13 @@ var DetectionWiringController = class {
46113
46331
  });
46114
46332
  }
46115
46333
  } catch (err) {
46116
- log.warn("startDetection: post-dispatch re-resolve failed", { meta: { error: errMsg(err) } });
46334
+ log.warn("startDetection: post-dispatch re-resolve failed", { meta: { error: errMsg$1(err) } });
46117
46335
  }
46118
46336
  }
46119
46337
  try {
46120
46338
  await this.deps.audio.resubscribe(deviceId, config);
46121
46339
  } catch (err) {
46122
- const msg = errMsg(err);
46340
+ const msg = errMsg$1(err);
46123
46341
  log.error("subscribeAudioStream failed", { meta: { error: msg } });
46124
46342
  }
46125
46343
  if (config.detectionMode !== "on-motion") log.info("Detection dispatched", { meta: {
@@ -46135,7 +46353,7 @@ var DetectionWiringController = class {
46135
46353
  try {
46136
46354
  await this.deps.placement.releaseCamera({ deviceId });
46137
46355
  } catch (err) {
46138
- const msg = errMsg(err);
46356
+ const msg = errMsg$1(err);
46139
46357
  this.deps.logger.error("releaseCamera failed", {
46140
46358
  tags: { deviceId },
46141
46359
  meta: { error: msg }
@@ -46161,7 +46379,7 @@ var DetectionWiringController = class {
46161
46379
  } catch (err) {
46162
46380
  this.deps.logger.warn("failed to clear per-device orchestrator settings on removal", {
46163
46381
  tags: { deviceId },
46164
- meta: { error: errMsg(err) }
46382
+ meta: { error: errMsg$1(err) }
46165
46383
  });
46166
46384
  }
46167
46385
  this.deps.logger.info("Purged pipeline config for removed device", { tags: { deviceId } });
@@ -46185,7 +46403,7 @@ var DetectionWiringController = class {
46185
46403
  } catch (err) {
46186
46404
  this.deps.logger.debug("device existence check failed — proceeding as before", {
46187
46405
  tags: { deviceId },
46188
- meta: { error: errMsg(err) }
46406
+ meta: { error: errMsg$1(err) }
46189
46407
  });
46190
46408
  return false;
46191
46409
  }
@@ -46302,7 +46520,7 @@ var DetectionWiringController = class {
46302
46520
  await this.deps.attachOn(assignment.agentNodeId, nextConfig);
46303
46521
  log.info("pipeline.camera-updated: hot-reloaded", { tags: { nodeId: assignment.agentNodeId } });
46304
46522
  } catch (err) {
46305
- const msg = errMsg(err);
46523
+ const msg = errMsg$1(err);
46306
46524
  log.error("pipeline.camera-updated: attachOn failed", {
46307
46525
  tags: { nodeId: assignment.agentNodeId },
46308
46526
  meta: { error: msg }
@@ -46378,7 +46596,7 @@ var DetectionWiringController = class {
46378
46596
  this.deps.audio.resubscribe(deviceId, audioCfg).catch((err) => {
46379
46597
  this.deps.logger.warn("watchdog audio re-subscribe failed", {
46380
46598
  tags: { deviceId },
46381
- meta: { error: errMsg(err) }
46599
+ meta: { error: errMsg$1(err) }
46382
46600
  });
46383
46601
  });
46384
46602
  }
@@ -46577,7 +46795,7 @@ var DeviceConfigContributions = class {
46577
46795
  issue: configIssue
46578
46796
  } });
46579
46797
  this.deps.topology.refreshNodeCapabilities().then(() => this.deps.redispatchAllActiveCameras("ingest-owner-changed")).catch((err) => {
46580
- this.deps.ctx().logger.warn("ingest-owner-changed re-dispatch failed", { meta: { error: errMsg(err) } });
46798
+ this.deps.ctx().logger.warn("ingest-owner-changed re-dispatch failed", { meta: { error: errMsg$1(err) } });
46581
46799
  });
46582
46800
  }
46583
46801
  this.deps.clearOnSettingsChange();
@@ -47317,7 +47535,7 @@ var PlacementService = class {
47317
47535
  async releaseCamera(input) {
47318
47536
  const current = this.deps.ledger.getAssignment(input.deviceId);
47319
47537
  if (current) await this.detachOn(current.agentNodeId, input.deviceId).catch((err) => {
47320
- const msg = errMsg(err);
47538
+ const msg = errMsg$1(err);
47321
47539
  this.deps.ctx().logger.debug("releaseCamera detach failed", {
47322
47540
  tags: { deviceId: input.deviceId },
47323
47541
  meta: { error: msg }
@@ -47345,7 +47563,7 @@ var PlacementService = class {
47345
47563
  pipelineNodeId: input.agentNodeId,
47346
47564
  [PREFERRED_AGENT_SETTING]: null
47347
47565
  }).catch((err) => {
47348
- const msg = errMsg(err);
47566
+ const msg = errMsg$1(err);
47349
47567
  ctx.logger.warn("assignPipeline: failed to persist pin", {
47350
47568
  tags: { deviceId: input.deviceId },
47351
47569
  meta: { error: msg }
@@ -47377,7 +47595,7 @@ var PlacementService = class {
47377
47595
  }
47378
47596
  const current = this.deps.ledger.getAssignment(input.deviceId);
47379
47597
  if (current && current.agentNodeId !== input.agentNodeId) await this.detachOn(current.agentNodeId, input.deviceId).catch((err) => {
47380
- const msg = errMsg(err);
47598
+ const msg = errMsg$1(err);
47381
47599
  ctx.logger.debug("assignPipeline detach-old failed", {
47382
47600
  tags: { deviceId: input.deviceId },
47383
47601
  meta: { error: msg }
@@ -47402,7 +47620,7 @@ var PlacementService = class {
47402
47620
  await ctx.settings?.writeDeviceStore(input.deviceId, { pipelineDeviceKey: clearing ? "auto" : input.deviceKey }).catch((err) => {
47403
47621
  ctx.logger.warn("setPipelineDevicePin: failed to persist device pin", {
47404
47622
  tags: { deviceId: input.deviceId },
47405
- meta: { error: errMsg(err) }
47623
+ meta: { error: errMsg$1(err) }
47406
47624
  });
47407
47625
  });
47408
47626
  const sessionNode = this.deps.activeSessionNode(input.deviceId);
@@ -47425,7 +47643,7 @@ var PlacementService = class {
47425
47643
  [PREFERRED_AGENT_SETTING]: null,
47426
47644
  pipelineNodeId: "auto"
47427
47645
  }).catch((err) => {
47428
- const msg = errMsg(err);
47646
+ const msg = errMsg$1(err);
47429
47647
  ctx.logger.warn("unassignPipeline: failed to clear pin", {
47430
47648
  tags: { deviceId: input.deviceId },
47431
47649
  meta: { error: msg }
@@ -47446,7 +47664,7 @@ var PlacementService = class {
47446
47664
  else {
47447
47665
  const targetNodeId = decision.agentNodeId;
47448
47666
  if (current && current.agentNodeId !== targetNodeId) await this.detachOn(current.agentNodeId, input.deviceId).catch((err) => {
47449
- const msg = errMsg(err);
47667
+ const msg = errMsg$1(err);
47450
47668
  ctx.logger.debug("unassignPipeline detach-old failed", {
47451
47669
  tags: { deviceId: input.deviceId },
47452
47670
  meta: { error: msg }
@@ -47466,7 +47684,7 @@ var PlacementService = class {
47466
47684
  }
47467
47685
  }
47468
47686
  if (current) await this.detachOn(current.agentNodeId, input.deviceId).catch((err) => {
47469
- const msg = errMsg(err);
47687
+ const msg = errMsg$1(err);
47470
47688
  ctx.logger.debug("unassignPipeline detach failed", {
47471
47689
  tags: { deviceId: input.deviceId },
47472
47690
  meta: { error: msg }
@@ -47485,7 +47703,7 @@ var PlacementService = class {
47485
47703
  async runAutoRebalance() {
47486
47704
  if (!this.deps.ctxIfReady()) return;
47487
47705
  await this.deps.reconcilePlacementFromRunners().catch((err) => {
47488
- this.deps.ctx().logger.debug("auto-rebalance: attachment reconcile failed", { meta: { error: errMsg(err) } });
47706
+ this.deps.ctx().logger.debug("auto-rebalance: attachment reconcile failed", { meta: { error: errMsg$1(err) } });
47489
47707
  });
47490
47708
  if (this.autoRebalanceInFlight) return;
47491
47709
  if (this.deps.topology.enabledNodes.length < 2) return;
@@ -47494,7 +47712,7 @@ var PlacementService = class {
47494
47712
  const { migrated } = await this.rebalance({ minImprovement: AUTO_REBALANCE_MIN_IMPROVEMENT });
47495
47713
  if (migrated > 0) this.deps.ctx().logger.info("auto-rebalance: corrected placement drift", { meta: { migrated } });
47496
47714
  } catch (err) {
47497
- this.deps.ctx().logger.debug("auto-rebalance pass failed", { meta: { error: errMsg(err) } });
47715
+ this.deps.ctx().logger.debug("auto-rebalance pass failed", { meta: { error: errMsg$1(err) } });
47498
47716
  } finally {
47499
47717
  this.autoRebalanceInFlight = false;
47500
47718
  }
@@ -47545,7 +47763,7 @@ var PlacementService = class {
47545
47763
  }
47546
47764
  if (current) {
47547
47765
  await this.detachOn(current.agentNodeId, deviceId).catch((err) => {
47548
- const msg = errMsg(err);
47766
+ const msg = errMsg$1(err);
47549
47767
  ctx.logger.debug("rebalance detach-old failed", {
47550
47768
  tags: { deviceId },
47551
47769
  meta: { error: msg }
@@ -47872,7 +48090,7 @@ var NodeLifecycleHandler = class {
47872
48090
  nodeId: decision.agentNodeId
47873
48091
  } });
47874
48092
  } catch (err) {
47875
- const msg = errMsg(err);
48093
+ const msg = errMsg$1(err);
47876
48094
  this.deps.logger.error("Failover: attach failed", {
47877
48095
  tags: {
47878
48096
  deviceId,
@@ -47902,7 +48120,7 @@ var NodeLifecycleHandler = class {
47902
48120
  this.deps.schedulePendingRetry();
47903
48121
  if (failoverPolicy.onReconnect === "rebalance") {
47904
48122
  await this.deps.rebalance().catch((err) => {
47905
- const msg = errMsg(err);
48123
+ const msg = errMsg$1(err);
47906
48124
  this.deps.logger.error("rebalance after reconnect failed", { meta: { error: msg } });
47907
48125
  });
47908
48126
  return;
@@ -47928,7 +48146,7 @@ var NodeLifecycleHandler = class {
47928
48146
  this.deps.ledger.recordAssignment(deviceId, nodeId, "failover", false);
47929
48147
  restored++;
47930
48148
  } catch (err) {
47931
- const msg = errMsg(err);
48149
+ const msg = errMsg$1(err);
47932
48150
  this.deps.logger.error("restore attach failed", {
47933
48151
  tags: {
47934
48152
  deviceId,
@@ -48018,7 +48236,7 @@ var NodeLifecycleHandler = class {
48018
48236
  deviceId,
48019
48237
  nodeId
48020
48238
  },
48021
- meta: { error: errMsg(err) }
48239
+ meta: { error: errMsg$1(err) }
48022
48240
  });
48023
48241
  }
48024
48242
  this.deps.logger.info("readiness: detection-pipeline reseeded agent defaults + redispatched cameras", {
@@ -48032,7 +48250,7 @@ var NodeLifecycleHandler = class {
48032
48250
  this.reattachStaleEmpties(nodeId).catch((err) => {
48033
48251
  this.deps.logger.debug("readiness deferred sweep failed", {
48034
48252
  tags: { nodeId },
48035
- meta: { error: errMsg(err) }
48253
+ meta: { error: errMsg$1(err) }
48036
48254
  });
48037
48255
  });
48038
48256
  }, 3e3);
@@ -48043,7 +48261,7 @@ var NodeLifecycleHandler = class {
48043
48261
  tags: { nodeId },
48044
48262
  meta: {
48045
48263
  epoch: t.epoch,
48046
- error: errMsg(err)
48264
+ error: errMsg$1(err)
48047
48265
  }
48048
48266
  });
48049
48267
  }
@@ -48082,7 +48300,7 @@ var NodeLifecycleHandler = class {
48082
48300
  deviceId,
48083
48301
  nodeId
48084
48302
  },
48085
- meta: { error: errMsg(err) }
48303
+ meta: { error: errMsg$1(err) }
48086
48304
  });
48087
48305
  }
48088
48306
  }
@@ -48404,7 +48622,7 @@ var NodeStressController = class NodeStressController {
48404
48622
  if (this.timer) return;
48405
48623
  this.timer = setInterval(() => {
48406
48624
  this.sweep().catch((err) => {
48407
- this.deps.logger.warn("node-stress sweep failed", { meta: { error: errMsg(err) } });
48625
+ this.deps.logger.warn("node-stress sweep failed", { meta: { error: errMsg$1(err) } });
48408
48626
  });
48409
48627
  }, NodeStressController.SWEEP_INTERVAL_MS);
48410
48628
  }
@@ -48577,7 +48795,7 @@ var NodeStressController = class NodeStressController {
48577
48795
  meta: {
48578
48796
  from: plan.fromNodeId,
48579
48797
  to: plan.toNodeId,
48580
- error: errMsg(err)
48798
+ error: errMsg$1(err)
48581
48799
  }
48582
48800
  });
48583
48801
  } finally {
@@ -49274,7 +49492,7 @@ var NodeTopologyService = class {
49274
49492
  try {
49275
49493
  blob = await this.deps.readAgentSettingsMap();
49276
49494
  } catch (err) {
49277
- this.deps.logger.warn("refreshNodeCapabilities: agent settings read failed", { meta: { error: errMsg(err) } });
49495
+ this.deps.logger.warn("refreshNodeCapabilities: agent settings read failed", { meta: { error: errMsg$1(err) } });
49278
49496
  }
49279
49497
  const nodeIds = new Set(["hub"]);
49280
49498
  for (const nodeId of Object.keys(blob)) if (typeof nodeId === "string" && nodeId.length > 0 && !nodeId.includes("/")) nodeIds.add(nodeId);
@@ -49332,7 +49550,7 @@ function wireOrchestratorSubscriptions(deps) {
49332
49550
  const unsubInferenceResult = deps.eventBus.subscribe({ category: EventCategory.PipelineInferenceResult }, (event) => {
49333
49551
  if (!isEvent(event, EventCategory.PipelineInferenceResult)) return;
49334
49552
  deps.handleInferenceResult(event.data).catch((err) => {
49335
- const msg = errMsg(err);
49553
+ const msg = errMsg$1(err);
49336
49554
  deps.logger.error("PipelineInferenceResult post-processing failed", {
49337
49555
  tags: { deviceId: event.data.deviceId },
49338
49556
  meta: { error: msg }
@@ -49351,7 +49569,7 @@ function wireOrchestratorSubscriptions(deps) {
49351
49569
  deps.logger.info("received onProfileSlotsChanged", { tags: { deviceId } });
49352
49570
  deps.handleDeviceRegistered(deviceId).catch((err) => {
49353
49571
  if (isTornDown) return;
49354
- const msg = errMsg(err);
49572
+ const msg = errMsg$1(err);
49355
49573
  deps.logger.error("handleDeviceRegistered failed", {
49356
49574
  tags: { deviceId },
49357
49575
  meta: { error: msg }
@@ -49363,7 +49581,7 @@ function wireOrchestratorSubscriptions(deps) {
49363
49581
  const unsubDeviceUnregistered = deps.eventBus.subscribe({ category: EventCategory.DeviceUnregistered }, (event) => {
49364
49582
  const { deviceId } = event.data;
49365
49583
  deps.handleDeviceUnregistered(deviceId).catch((err) => {
49366
- const msg = errMsg(err);
49584
+ const msg = errMsg$1(err);
49367
49585
  deps.logger.error("handleDeviceUnregistered failed", {
49368
49586
  tags: { deviceId },
49369
49587
  meta: { error: msg }
@@ -49375,7 +49593,7 @@ function wireOrchestratorSubscriptions(deps) {
49375
49593
  const { deviceId } = event.data;
49376
49594
  deps.handleSettingsChanged(deviceId).catch((err) => {
49377
49595
  if (isTornDown) return;
49378
- const msg = errMsg(err);
49596
+ const msg = errMsg$1(err);
49379
49597
  deps.logger.error("handleSettingsChanged failed", {
49380
49598
  tags: { deviceId },
49381
49599
  meta: { error: msg }
@@ -49385,7 +49603,7 @@ function wireOrchestratorSubscriptions(deps) {
49385
49603
  const unsubCameraUpdated = deps.eventBus.subscribe({ category: EventCategory.PipelineCameraUpdated }, (event) => {
49386
49604
  if (!isEvent(event, EventCategory.PipelineCameraUpdated)) return;
49387
49605
  deps.handlePipelineCameraUpdated(event.data.deviceId, event.data.config).catch((err) => {
49388
- const msg = errMsg(err);
49606
+ const msg = errMsg$1(err);
49389
49607
  deps.logger.error("handlePipelineCameraUpdated failed", {
49390
49608
  tags: { deviceId: event.data.deviceId },
49391
49609
  meta: { error: msg }
@@ -49398,7 +49616,7 @@ function wireOrchestratorSubscriptions(deps) {
49398
49616
  if (!(reason === "wrapper-activated" || reason === "wrapper-deactivated") || !(capName === "detection-pipeline" || capName === "audio-analysis" || capName === "motion-detection")) return;
49399
49617
  deps.handleSettingsChanged(deviceId).catch((err) => {
49400
49618
  if (isTornDown) return;
49401
- const msg = errMsg(err);
49619
+ const msg = errMsg$1(err);
49402
49620
  deps.logger.error("binding-changed re-dispatch failed", {
49403
49621
  tags: { deviceId },
49404
49622
  meta: {
@@ -49426,7 +49644,7 @@ function wireOrchestratorSubscriptions(deps) {
49426
49644
  tags: { deviceId },
49427
49645
  meta: {
49428
49646
  detected,
49429
- error: errMsg(err)
49647
+ error: errMsg$1(err)
49430
49648
  }
49431
49649
  });
49432
49650
  });
@@ -49441,7 +49659,7 @@ function wireOrchestratorSubscriptions(deps) {
49441
49659
  tags: { deviceId },
49442
49660
  meta: {
49443
49661
  detected,
49444
- error: errMsg(err)
49662
+ error: errMsg$1(err)
49445
49663
  }
49446
49664
  });
49447
49665
  });
@@ -50435,7 +50653,7 @@ var PipelineSettingsStore = class PipelineSettingsStore {
50435
50653
  } catch (err) {
50436
50654
  this.deps.logger.debug("getCatalogForAgent failed", {
50437
50655
  tags: { nodeId },
50438
- meta: { error: errMsg(err) }
50656
+ meta: { error: errMsg$1(err) }
50439
50657
  });
50440
50658
  return null;
50441
50659
  }
@@ -50498,7 +50716,7 @@ var PipelineSettingsStore = class PipelineSettingsStore {
50498
50716
  tags: { deviceId },
50499
50717
  meta: {
50500
50718
  capName: "detection-pipeline",
50501
- error: errMsg(err)
50719
+ error: errMsg$1(err)
50502
50720
  }
50503
50721
  });
50504
50722
  return true;
@@ -51221,7 +51439,7 @@ var ReconcileController = class ReconcileController {
51221
51439
  try {
51222
51440
  slots = await api.streamBroker.listAllProfileSlots.query();
51223
51441
  } catch (err) {
51224
- this.deps.logger.debug("dispatch reconcile skipped — stream-broker not ready", { meta: { error: errMsg(err) } });
51442
+ this.deps.logger.debug("dispatch reconcile skipped — stream-broker not ready", { meta: { error: errMsg$1(err) } });
51225
51443
  return;
51226
51444
  }
51227
51445
  const desired = desiredDeviceIdsFromSlots(slots);
@@ -51248,7 +51466,7 @@ var ReconcileController = class ReconcileController {
51248
51466
  } catch (err) {
51249
51467
  this.deps.logger.warn("dispatch reconcile: handleDeviceRegistered failed", {
51250
51468
  tags: { deviceId },
51251
- meta: { error: errMsg(err) }
51469
+ meta: { error: errMsg$1(err) }
51252
51470
  });
51253
51471
  }
51254
51472
  await this.reconcilePlacementFromRunners();
@@ -51276,7 +51494,7 @@ var ReconcileController = class ReconcileController {
51276
51494
  const devices = await api.deviceManager.listAll.query({ projection: "slim" });
51277
51495
  return new Set(devices.map((device) => device.id));
51278
51496
  } catch (err) {
51279
- this.deps.logger.debug("dispatch reconcile: deviceManager.listAll failed", { meta: { error: errMsg(err) } });
51497
+ this.deps.logger.debug("dispatch reconcile: deviceManager.listAll failed", { meta: { error: errMsg$1(err) } });
51280
51498
  return null;
51281
51499
  }
51282
51500
  }
@@ -51302,7 +51520,7 @@ var ReconcileController = class ReconcileController {
51302
51520
  } catch (err) {
51303
51521
  this.deps.logger.warn("dispatch reconcile: teardown of vanished device failed", {
51304
51522
  tags: { deviceId },
51305
- meta: { error: errMsg(err) }
51523
+ meta: { error: errMsg$1(err) }
51306
51524
  });
51307
51525
  }
51308
51526
  }
@@ -51359,7 +51577,7 @@ var ReconcileController = class ReconcileController {
51359
51577
  this.deps.logger.debug("placement reconcile skipped node — getLocalCameras failed", {
51360
51578
  tags: { nodeId },
51361
51579
  meta: {
51362
- error: outcome.kind === "rejected" ? errMsg(outcome.error) : "budget exceeded",
51580
+ error: outcome.kind === "rejected" ? errMsg$1(outcome.error) : "budget exceeded",
51363
51581
  ms
51364
51582
  }
51365
51583
  });
@@ -51389,7 +51607,7 @@ var ReconcileController = class ReconcileController {
51389
51607
  nodeId,
51390
51608
  deviceId
51391
51609
  },
51392
- meta: { error: errMsg(err) }
51610
+ meta: { error: errMsg$1(err) }
51393
51611
  });
51394
51612
  })));
51395
51613
  }
@@ -51431,7 +51649,7 @@ var ReconcileController = class ReconcileController {
51431
51649
  this.deps.handleDeviceRegistered(deviceId).catch((err) => {
51432
51650
  this.deps.logger.debug("slot-read retry: handleDeviceRegistered failed", {
51433
51651
  tags: { deviceId },
51434
- meta: { error: errMsg(err) }
51652
+ meta: { error: errMsg$1(err) }
51435
51653
  });
51436
51654
  });
51437
51655
  }, delay);
@@ -51509,7 +51727,7 @@ var ReconcileController = class ReconcileController {
51509
51727
  } catch (err) {
51510
51728
  this.deps.logger.warn("pending retry: dispatchCamera failed", {
51511
51729
  tags: { deviceId },
51512
- meta: { error: errMsg(err) }
51730
+ meta: { error: errMsg$1(err) }
51513
51731
  });
51514
51732
  stillPending++;
51515
51733
  }
@@ -51587,7 +51805,7 @@ var ReconcileController = class ReconcileController {
51587
51805
  await this.deps.detachOn(assignment.agentNodeId, deviceId).catch((err) => {
51588
51806
  this.deps.logger.debug("remote-health exhausted-detach failed", {
51589
51807
  tags: { deviceId },
51590
- meta: { error: errMsg(err) }
51808
+ meta: { error: errMsg$1(err) }
51591
51809
  });
51592
51810
  });
51593
51811
  return;
@@ -51610,14 +51828,14 @@ var ReconcileController = class ReconcileController {
51610
51828
  await this.deps.detachOn(assignment.agentNodeId, deviceId).catch((err) => {
51611
51829
  this.deps.logger.warn("remote-health detach failed", {
51612
51830
  tags: { deviceId },
51613
- meta: { error: errMsg(err) }
51831
+ meta: { error: errMsg$1(err) }
51614
51832
  });
51615
51833
  });
51616
51834
  this.deps.ledger.dropAssignment(deviceId, "silent");
51617
51835
  await this.deps.dispatchCamera(cfg).catch((err) => {
51618
51836
  this.deps.logger.warn("remote-health re-dispatch failed", {
51619
51837
  tags: { deviceId },
51620
- meta: { error: errMsg(err) }
51838
+ meta: { error: errMsg$1(err) }
51621
51839
  });
51622
51840
  });
51623
51841
  }
@@ -52266,7 +52484,7 @@ var SessionDispatchController = class {
52266
52484
  deviceId,
52267
52485
  nodeId: session.nodeId
52268
52486
  },
52269
- meta: { error: errMsg(err) }
52487
+ meta: { error: errMsg$1(err) }
52270
52488
  });
52271
52489
  });
52272
52490
  this.deps.dropAssignment(deviceId, "silent");
@@ -52329,7 +52547,8 @@ var SessionDispatchController = class {
52329
52547
  occupancyRecheckSec: config.occupancyRecheckSec,
52330
52548
  occupancyRecheckFrames: config.occupancyRecheckFrames,
52331
52549
  preRollInferenceEnabled: config.preRollInferenceEnabled,
52332
- preRollInferenceFrames: config.preRollInferenceFrames
52550
+ preRollInferenceFrames: config.preRollInferenceFrames,
52551
+ detectionSources: config.detectionSources
52333
52552
  };
52334
52553
  await this.deps.attachOn(nodeId, watchConfig);
52335
52554
  this.motionWatchByDevice.set(deviceId, nodeId);
@@ -52450,7 +52669,7 @@ var SessionDispatchController = class {
52450
52669
  };
52451
52670
  if (reconcileBudgetExceeded) log.warn("detection session: placement census overran its budget — placing without it", { meta: { budgetMs: 500 } });
52452
52671
  else if (censusOutcome.kind === "rejected") log.warn("detection session: placement census failed — placing on the ledger as it is", { meta: {
52453
- error: errMsg(censusOutcome.error),
52672
+ error: errMsg$1(censusOutcome.error),
52454
52673
  reconcileMs
52455
52674
  } });
52456
52675
  const balanceStartedAt = Date.now();
@@ -52542,7 +52761,8 @@ var SessionDispatchController = class {
52542
52761
  occupancyRecheckSec: config.occupancyRecheckSec,
52543
52762
  occupancyRecheckFrames: config.occupancyRecheckFrames,
52544
52763
  preRollInferenceEnabled: config.preRollInferenceEnabled,
52545
- preRollInferenceFrames: config.preRollInferenceFrames
52764
+ preRollInferenceFrames: config.preRollInferenceFrames,
52765
+ detectionSources: config.detectionSources
52546
52766
  };
52547
52767
  const configuredAt = Date.now();
52548
52768
  let attachedAt = configuredAt;
@@ -52611,7 +52831,7 @@ var SessionDispatchController = class {
52611
52831
  await this.resolveSessionLifecycleLocked(deviceId, reason);
52612
52832
  }).catch((err) => {
52613
52833
  log.warn("detection session: lifecycle re-check failed", { meta: {
52614
- error: errMsg(err),
52834
+ error: errMsg$1(err),
52615
52835
  reason
52616
52836
  } });
52617
52837
  });
@@ -52716,7 +52936,7 @@ var SessionDispatchController = class {
52716
52936
  log.warn("detection session: teardown detach failed", {
52717
52937
  tags: { nodeId: session.nodeId },
52718
52938
  meta: {
52719
- error: errMsg(err),
52939
+ error: errMsg$1(err),
52720
52940
  reason
52721
52941
  }
52722
52942
  });
@@ -52799,7 +53019,7 @@ var SessionDispatchController = class {
52799
53019
  deviceId,
52800
53020
  nodeId: session.nodeId
52801
53021
  },
52802
- meta: { error: errMsg(err) }
53022
+ meta: { error: errMsg$1(err) }
52803
53023
  });
52804
53024
  });
52805
53025
  this.sessionRegistry.deregister(deviceId);
@@ -52817,7 +53037,7 @@ var SessionDispatchController = class {
52817
53037
  deviceId,
52818
53038
  nodeId: watchNodeId
52819
53039
  },
52820
- meta: { error: errMsg(err) }
53040
+ meta: { error: errMsg$1(err) }
52821
53041
  });
52822
53042
  });
52823
53043
  this.motionWatchByDevice.delete(deviceId);
@@ -52997,7 +53217,7 @@ async function sweepMirror(deps, hydrator, cameraIds) {
52997
53217
  tags: { deviceId },
52998
53218
  meta: {
52999
53219
  mirror: hydrator.mirror,
53000
- error: errMsg(err)
53220
+ error: errMsg$1(err)
53001
53221
  }
53002
53222
  });
53003
53223
  return "threw";
@@ -53037,7 +53257,7 @@ async function readCameraIds(deps) {
53037
53257
  lastError = err;
53038
53258
  }
53039
53259
  if (Date.now() >= deadline) {
53040
- deps.logger.warn("zones mirror boot hydration SKIPPED — camera list never became readable; mirror-only consumers keep whatever the last write left", { meta: { error: lastError === null ? "ctx.api unavailable" : errMsg(lastError) } });
53260
+ deps.logger.warn("zones mirror boot hydration SKIPPED — camera list never became readable; mirror-only consumers keep whatever the last write left", { meta: { error: lastError === null ? "ctx.api unavailable" : errMsg$1(lastError) } });
53041
53261
  return null;
53042
53262
  }
53043
53263
  await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
@@ -53678,7 +53898,7 @@ async function buildOrchestratorControllers(deps) {
53678
53898
  } catch (err) {
53679
53899
  return {
53680
53900
  kind: "unknown",
53681
- reason: errMsg(err)
53901
+ reason: errMsg$1(err)
53682
53902
  };
53683
53903
  }
53684
53904
  };
@@ -53762,14 +53982,14 @@ async function buildOrchestratorControllers(deps) {
53762
53982
  readGlobalSettings: () => globalSettings
53763
53983
  });
53764
53984
  await NodeStressMoveLedger.declare(deps.ctx().api.settingsStore).then(() => nodeStress.hydrate()).catch((err) => {
53765
- deps.ctx().logger.warn("node-stress move history unavailable — this boot starts cold", { meta: { error: errMsg(err) } });
53985
+ deps.ctx().logger.warn("node-stress move history unavailable — this boot starts cold", { meta: { error: errMsg$1(err) } });
53766
53986
  });
53767
53987
  await NodeStressLts.declare(deps.ctx().api.settingsStore).catch((err) => {
53768
- deps.ctx().logger.warn("node-stress statistics unavailable — no baseline this boot", { meta: { error: errMsg(err) } });
53988
+ deps.ctx().logger.warn("node-stress statistics unavailable — no baseline this boot", { meta: { error: errMsg$1(err) } });
53769
53989
  });
53770
53990
  const nodeStressLtsTimer = setInterval(() => {
53771
53991
  nodeStressLts.flushDue().catch((err) => {
53772
- deps.ctx().logger.warn("node-stress statistics flush failed", { meta: { error: errMsg(err) } });
53992
+ deps.ctx().logger.warn("node-stress statistics flush failed", { meta: { error: errMsg$1(err) } });
53773
53993
  });
53774
53994
  }, 6e4);
53775
53995
  nodeStress.start();
@@ -53906,7 +54126,7 @@ async function buildOrchestratorControllers(deps) {
53906
54126
  deps.applyRuntimeSettings(globalSettings);
53907
54127
  await topology.refreshNodeCapabilities();
53908
54128
  } catch (err) {
53909
- const msg = errMsg(err);
54129
+ const msg = errMsg$1(err);
53910
54130
  deps.ctx().logger.warn("orchestrator settings load failed — using defaults", { meta: { error: msg } });
53911
54131
  }
53912
54132
  const rawNodeId = deps.ctx().kernel.localNodeId ?? "hub";
@@ -53939,7 +54159,7 @@ async function buildOrchestratorControllers(deps) {
53939
54159
  nodeLifecycle.unsubscribeDetectionPipelineReadiness(nodeId);
53940
54160
  audio.markNodeOffline(nodeId);
53941
54161
  nodeLifecycle.handleNodeDisconnect(nodeId).catch((err) => {
53942
- const msg = errMsg(err);
54162
+ const msg = errMsg$1(err);
53943
54163
  deps.ctx().logger.error("failover after disconnect failed", {
53944
54164
  tags: { nodeId },
53945
54165
  meta: { error: msg }
@@ -53954,7 +54174,7 @@ async function buildOrchestratorControllers(deps) {
53954
54174
  deps.subscribeToAudioAnalyzerReadiness(nodeId);
53955
54175
  }
53956
54176
  nodeLifecycle.handleNodeConnect(nodeId).catch((err) => {
53957
- const msg = errMsg(err);
54177
+ const msg = errMsg$1(err);
53958
54178
  deps.ctx().logger.error("reconnect handling failed", {
53959
54179
  tags: { nodeId },
53960
54180
  meta: { error: msg }
@@ -53968,7 +54188,7 @@ async function buildOrchestratorControllers(deps) {
53968
54188
  meta: { capName }
53969
54189
  });
53970
54190
  nodeLifecycle.handleNodeDisconnect(nodeId).catch((err) => {
53971
- const msg = errMsg(err);
54191
+ const msg = errMsg$1(err);
53972
54192
  deps.ctx().logger.error("failover after cap-down failed", {
53973
54193
  tags: { nodeId },
53974
54194
  meta: {
@@ -54031,7 +54251,7 @@ async function buildOrchestratorControllers(deps) {
54031
54251
  doneFlag: settingsStore.bindingsMigrationDoneState,
54032
54252
  logger: deps.ctx().logger
54033
54253
  }).catch((err) => {
54034
- deps.ctxIfReady()?.logger.warn("bindings migration failed — will retry on next boot", { meta: { error: errMsg(err) } });
54254
+ deps.ctxIfReady()?.logger.warn("bindings migration failed — will retry on next boot", { meta: { error: errMsg$1(err) } });
54035
54255
  });
54036
54256
  migrateStepGating({
54037
54257
  readCameraSettings: () => settingsStore.readCameraSettingsMap(),
@@ -54042,7 +54262,7 @@ async function buildOrchestratorControllers(deps) {
54042
54262
  }).then(async () => {
54043
54263
  if (await settingsStore.applyPerNodeDeviceMigration()) deps.ctxIfReady()?.logger.info("per-(node,device) config migration applied");
54044
54264
  }).catch((err) => {
54045
- deps.ctxIfReady()?.logger.warn("step-gating / per-node-device migration failed — retry next boot", { meta: { error: errMsg(err) } });
54265
+ deps.ctxIfReady()?.logger.warn("step-gating / per-node-device migration failed — retry next boot", { meta: { error: errMsg$1(err) } });
54046
54266
  });
54047
54267
  const zoneRulesProvider = new ZoneRulesProvider({
54048
54268
  logger: deps.ctx().logger.child("zone-rules"),
@@ -54070,7 +54290,7 @@ async function buildOrchestratorControllers(deps) {
54070
54290
  deviceId,
54071
54291
  nodeId: assignment.agentNodeId
54072
54292
  },
54073
- meta: { error: errMsg(err) }
54293
+ meta: { error: errMsg$1(err) }
54074
54294
  });
54075
54295
  });
54076
54296
  }
@@ -54098,7 +54318,7 @@ async function buildOrchestratorControllers(deps) {
54098
54318
  deviceId,
54099
54319
  nodeId: assignment.agentNodeId
54100
54320
  },
54101
- meta: { error: errMsg(err) }
54321
+ meta: { error: errMsg$1(err) }
54102
54322
  });
54103
54323
  });
54104
54324
  }
@@ -54114,7 +54334,7 @@ async function buildOrchestratorControllers(deps) {
54114
54334
  }],
54115
54335
  logger: deps.ctx().logger.child("zones")
54116
54336
  }).catch((err) => {
54117
- deps.ctxIfReady()?.logger.warn("zones mirror boot hydration failed", { meta: { error: errMsg(err) } });
54337
+ deps.ctxIfReady()?.logger.warn("zones mirror boot hydration failed", { meta: { error: errMsg$1(err) } });
54118
54338
  });
54119
54339
  const unsubOrchestratorSubscriptions = wireOrchestratorSubscriptions({
54120
54340
  eventBus: deps.ctx().eventBus,
@@ -54163,10 +54383,11 @@ async function buildOrchestratorControllers(deps) {
54163
54383
  isCapActiveForDevice: (deviceId, capName) => deps.isCapActiveForDevice(deviceId, capName),
54164
54384
  deviceHasOnboardMotionCap: (deviceId) => deps.deviceHasOnboardMotionCap(deviceId),
54165
54385
  deviceHasActivitySignalCap: (deviceId) => deps.deviceHasActivitySignalCap(deviceId),
54386
+ deviceHasNativeObjectDetectionCap: (deviceId) => deps.deviceHasNativeObjectDetectionCap(deviceId),
54166
54387
  deviceSettingsSchema: () => deps.deviceSettingsSchema()
54167
54388
  });
54168
54389
  await detectionWiring.hydrateFeaturesMirror().catch((err) => {
54169
- deps.ctx().logger.warn("device-features mirror not restored — this boot starts cold", { meta: { error: errMsg(err) } });
54390
+ deps.ctx().logger.warn("device-features mirror not restored — this boot starts cold", { meta: { error: errMsg$1(err) } });
54170
54391
  });
54171
54392
  return {
54172
54393
  ledger,
@@ -55239,7 +55460,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
55239
55460
  for (const deviceId of this.detectionWiring.activeDetectionDeviceIds()) try {
55240
55461
  await this.releaseCamera({ deviceId });
55241
55462
  } catch (err) {
55242
- const msg = errMsg(err);
55463
+ const msg = errMsg$1(err);
55243
55464
  this.ctx.logger.debug("releaseCamera failed during shutdown", {
55244
55465
  tags: { deviceId },
55245
55466
  meta: { error: msg }
@@ -55865,7 +56086,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
55865
56086
  tags: { nodeId },
55866
56087
  meta: {
55867
56088
  nodeId,
55868
- error: errMsg(err)
56089
+ error: errMsg$1(err)
55869
56090
  }
55870
56091
  });
55871
56092
  return null;
@@ -55971,7 +56192,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
55971
56192
  tags: { nodeId },
55972
56193
  meta: {
55973
56194
  nodeId,
55974
- error: errMsg(err)
56195
+ error: errMsg$1(err)
55975
56196
  }
55976
56197
  });
55977
56198
  return {
@@ -56018,7 +56239,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
56018
56239
  } catch (err) {
56019
56240
  this.ctx.logger.warn("resetNodePipelineDefaults: executor clearDeviceOverrides failed (node offline?)", {
56020
56241
  tags: { nodeId: node },
56021
- meta: { error: errMsg(err) }
56242
+ meta: { error: errMsg$1(err) }
56022
56243
  });
56023
56244
  }
56024
56245
  this.settingsStore.invalidateCatalog();
@@ -56029,7 +56250,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
56029
56250
  } catch (err) {
56030
56251
  this.ctx.logger.warn("resetNodePipelineDefaults: effective-model probe failed (node offline?)", {
56031
56252
  tags: { nodeId: node },
56032
- meta: { error: errMsg(err) }
56253
+ meta: { error: errMsg$1(err) }
56033
56254
  });
56034
56255
  }
56035
56256
  this.ctx.logger.info("node pipeline reset to hardware-aware defaults", {
@@ -56246,7 +56467,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
56246
56467
  tags: { deviceId },
56247
56468
  meta: {
56248
56469
  capName,
56249
- error: errMsg(err)
56470
+ error: errMsg$1(err)
56250
56471
  }
56251
56472
  });
56252
56473
  return true;