@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.js CHANGED
@@ -5391,7 +5391,7 @@ var ZodIssueCode = {
5391
5391
  var ZodFirstPartyTypeKind;
5392
5392
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5393
5393
  //#endregion
5394
- //#region ../types/dist/sleep-BfJ2k1jm.mjs
5394
+ //#region ../types/dist/sleep-BDR76Ykr.mjs
5395
5395
  /**
5396
5396
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5397
5397
  * window to float samples (D455).
@@ -7929,7 +7929,7 @@ import { errMsg } from '@camstack/types'
7929
7929
  * Extract a human-readable message from an unknown error value.
7930
7930
  * Replaces the ubiquitous `errMsg(err)` pattern.
7931
7931
  */
7932
- function errMsg(err) {
7932
+ function errMsg$1(err) {
7933
7933
  if (err instanceof Error) return err.message;
7934
7934
  if (typeof err === "string") return err;
7935
7935
  return String(err);
@@ -18789,6 +18789,48 @@ var NcAlarmConfigSchema = object({
18789
18789
  settings: NcAlarmSettingsSchema,
18790
18790
  coverage: array(NcAlarmModeCoverageSchema)
18791
18791
  });
18792
+ /**
18793
+ * ONE rule's demand on ONE camera's clip ring.
18794
+ *
18795
+ * A rule, not a camera: the broker takes the MAX over the asks that reach a
18796
+ * camera, so the answer stays a faithful description of the rules and the
18797
+ * bounding (the byte budget, the broker's own ceiling) stays where the cost
18798
+ * lives. A camera that appears in no ask is being told **nothing** — which is
18799
+ * a different thing from never having been told, and only the envelope
18800
+ * (`rulesLoaded`) can tell those apart.
18801
+ */
18802
+ var NcClipRetentionAskSchema = object({
18803
+ /**
18804
+ * The camera this ask is about. **Absent = every camera**, which is what a
18805
+ * rule with no `conditions.devices` means: it can fire anywhere, so it is
18806
+ * asking everywhere.
18807
+ */
18808
+ deviceId: number().int().nonnegative().optional(),
18809
+ /** Seconds of history the rule needs held for it. Never zero — a rule that
18810
+ * needs nothing produces no ask at all. */
18811
+ seconds: number().min(0).max(60),
18812
+ /** The profile the rule cuts from, when it named one. Absent = the cheapest
18813
+ * assigned, which is what the cut defaults to. */
18814
+ profile: CamProfileSchema.optional(),
18815
+ /** Who is asking — so a retention the operator did not expect names a rule. */
18816
+ ruleId: string(),
18817
+ ruleName: string(),
18818
+ /** Why this many seconds: the rule's own window, or the occupancy ceiling. */
18819
+ reason: _enum(["window", "occupancy"])
18820
+ });
18821
+ /**
18822
+ * The whole answer, with the one bit that keeps absence from reading as zero.
18823
+ *
18824
+ * `rulesLoaded` is false until the rule ledger has completed a load at least
18825
+ * once. A centre that is up but has not read its rules yet answers with an
18826
+ * empty ask list that means nothing at all — applying it would drop every
18827
+ * camera's ring to zero for the first events after a restart, which is the
18828
+ * footage this mechanism exists to keep.
18829
+ */
18830
+ var NcClipRetentionPlanSchema = object({
18831
+ rulesLoaded: boolean(),
18832
+ asks: array(NcClipRetentionAskSchema).readonly()
18833
+ });
18792
18834
  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 }), {
18793
18835
  kind: "mutation",
18794
18836
  auth: "admin",
@@ -18809,7 +18851,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
18809
18851
  }), object({ success: literal(true) }), {
18810
18852
  kind: "mutation",
18811
18853
  auth: "admin"
18812
- }), method(object({}), object({ mutedDeviceIds: array(number().int()).readonly() }), { auth: "admin" }), method(object({
18854
+ }), method(object({}), NcClipRetentionPlanSchema, { auth: "admin" }), method(object({}), object({ mutedDeviceIds: array(number().int()).readonly() }), { auth: "admin" }), method(object({
18813
18855
  deviceId: number().int(),
18814
18856
  muted: boolean()
18815
18857
  }), object({ success: literal(true) }), {
@@ -22835,7 +22877,47 @@ var RunnerLocalMetricsSchema = object({
22835
22877
  queueDepth: number(),
22836
22878
  frameLazy: FrameLazyMetricsSchema.optional()
22837
22879
  });
22880
+ /**
22881
+ * Pipeline Runner capability — runtime detection workhorse.
22882
+ *
22883
+ * One instance per node. Receives camera assignments from
22884
+ * `addon-pipeline-orchestrator`, subscribes to the local stream-broker for
22885
+ * decoded frames, drains motion + detection queues, calls the local
22886
+ * `motion-detection` and `pipeline-executor` capabilities, and emits typed
22887
+ * `pipeline.inference-result` and `detection.motion-analysis` events on
22888
+ * the bus.
22889
+ *
22890
+ * Distinct from `pipeline-orchestrator` (the hub-side load balancer) — the
22891
+ * runner has zero knowledge of other agents, no global state, and never
22892
+ * makes assignment decisions itself.
22893
+ */
22894
+ /**
22895
+ * Why a runner declined to look at a camera out of band. Named rather than a
22896
+ * bare `false`: a camera asleep on battery (D173), one attached elsewhere, one
22897
+ * already mid-session and one already bursting are four different facts, and a
22898
+ * caller told only "no" cannot tell a protection from a bug.
22899
+ */
22900
+ var OccupancyBurstRefusalSchema = _enum([
22901
+ "not-attached",
22902
+ "battery-asleep",
22903
+ "not-watching",
22904
+ "already-bursting"
22905
+ ]);
22838
22906
  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({
22907
+ deviceId: number(),
22908
+ /** How many frames to collect. The caller sizes this against what its
22909
+ * own confirmation needs; the runner clamps it to the field's range. */
22910
+ frames: number().int().positive().optional(),
22911
+ /** Why, for the log. A burst nobody can attribute is a cost nobody can
22912
+ * defend — the periodic one at least has a timer to point at. */
22913
+ reason: string()
22914
+ }), object({
22915
+ started: boolean(),
22916
+ refusedBecause: OccupancyBurstRefusalSchema.optional()
22917
+ }), {
22918
+ auth: "admin",
22919
+ kind: "mutation"
22920
+ }), method(object({
22839
22921
  handle: FrameHandleSchema,
22840
22922
  bbox: NativeCropBboxSchema,
22841
22923
  maxWidth: number().int().positive().optional(),
@@ -35855,6 +35937,12 @@ Object.freeze({
35855
35937
  addonId: null,
35856
35938
  access: "view"
35857
35939
  },
35940
+ "notificationRules.getClipRetentionAsks": {
35941
+ capName: "notification-rules",
35942
+ capScope: "system",
35943
+ addonId: null,
35944
+ access: "view"
35945
+ },
35858
35946
  "notificationRules.getConditionCatalog": {
35859
35947
  capName: "notification-rules",
35860
35948
  capScope: "system",
@@ -37043,6 +37131,12 @@ Object.freeze({
37043
37131
  addonId: null,
37044
37132
  access: "create"
37045
37133
  },
37134
+ "pipelineRunner.requestOccupancyBurst": {
37135
+ capName: "pipeline-runner",
37136
+ capScope: "system",
37137
+ addonId: null,
37138
+ access: "create"
37139
+ },
37046
37140
  "pipelineRunner.runDetailSubtree": {
37047
37141
  capName: "pipeline-runner",
37048
37142
  capScope: "system",
@@ -40382,6 +40476,11 @@ Object.freeze({
40382
40476
  form: "single",
40383
40477
  optional: false
40384
40478
  }],
40479
+ "pipelineRunner.requestOccupancyBurst": [{
40480
+ name: "deviceId",
40481
+ form: "single",
40482
+ optional: false
40483
+ }],
40385
40484
  "pipelineRunner.runDetailSubtree": [{
40386
40485
  name: "deviceId",
40387
40486
  form: "single",
@@ -42003,7 +42102,7 @@ var AudioSubscriptionController = class {
42003
42102
  } catch (err) {
42004
42103
  this.deps.logger.error("audio re-attach failed", {
42005
42104
  tags: { deviceId },
42006
- meta: { error: errMsg(err) }
42105
+ meta: { error: errMsg$1(err) }
42007
42106
  });
42008
42107
  }
42009
42108
  }
@@ -42114,7 +42213,7 @@ var AudioSubscriptionController = class {
42114
42213
  this.closeMotionAudioWindow(deviceId, "motion-cooldown-elapsed").catch((err) => {
42115
42214
  this.deps.logger.warn("lazy audio: cooldown teardown failed", {
42116
42215
  tags: { deviceId },
42117
- meta: { error: errMsg(err) }
42216
+ meta: { error: errMsg$1(err) }
42118
42217
  });
42119
42218
  });
42120
42219
  }, cooldownMs);
@@ -42133,7 +42232,7 @@ var AudioSubscriptionController = class {
42133
42232
  this.closeMotionAudioWindow(deviceId, "quiet-window-elapsed").catch((err) => {
42134
42233
  this.deps.logger.warn("lazy audio: quiet-window teardown failed", {
42135
42234
  tags: { deviceId },
42136
- meta: { error: errMsg(err) }
42235
+ meta: { error: errMsg$1(err) }
42137
42236
  });
42138
42237
  });
42139
42238
  }, windowMs);
@@ -42304,7 +42403,7 @@ var AudioSubscriptionController = class {
42304
42403
  meta: {
42305
42404
  audioNodeId,
42306
42405
  brokerId: audioBrokerId,
42307
- error: errMsg(err)
42406
+ error: errMsg$1(err)
42308
42407
  }
42309
42408
  });
42310
42409
  });
@@ -43324,7 +43423,7 @@ var LoadShedController = class LoadShedController {
43324
43423
  if (await this.tryClusterRelocate(deviceId).catch((err) => {
43325
43424
  this.deps.logger.warn("Load management: cluster relocate failed", {
43326
43425
  tags: { deviceId },
43327
- meta: { error: errMsg(err) }
43426
+ meta: { error: errMsg$1(err) }
43328
43427
  });
43329
43428
  return false;
43330
43429
  })) {
@@ -43338,7 +43437,7 @@ var LoadShedController = class LoadShedController {
43338
43437
  this.deps.api()?.pipelineRunner.detachCamera.mutate({ deviceId }).catch((err) => {
43339
43438
  this.deps.logger.warn("Load management: detachCamera failed", {
43340
43439
  tags: { deviceId },
43341
- meta: { error: errMsg(err) }
43440
+ meta: { error: errMsg$1(err) }
43342
43441
  });
43343
43442
  });
43344
43443
  this.ensureLoadShedResumeTimer();
@@ -43370,7 +43469,7 @@ var LoadShedController = class LoadShedController {
43370
43469
  tags: { deviceId },
43371
43470
  meta: {
43372
43471
  from: currentNode,
43373
- error: errMsg(err)
43472
+ error: errMsg$1(err)
43374
43473
  }
43375
43474
  });
43376
43475
  });
@@ -43413,7 +43512,7 @@ var LoadShedController = class LoadShedController {
43413
43512
  this.deps.redispatchSingleCamera(deviceId).catch((err) => {
43414
43513
  this.deps.logger.warn("Load management: auto-resume dispatch failed", {
43415
43514
  tags: { deviceId },
43416
- meta: { error: errMsg(err) }
43515
+ meta: { error: errMsg$1(err) }
43417
43516
  });
43418
43517
  });
43419
43518
  }
@@ -43574,7 +43673,7 @@ var AgentLoadService = class AgentLoadService {
43574
43673
  ms,
43575
43674
  outcome: "failed",
43576
43675
  load: null,
43577
- error: errMsg(outcome.error)
43676
+ error: errMsg$1(outcome.error)
43578
43677
  };
43579
43678
  return {
43580
43679
  nodeId,
@@ -44578,7 +44677,7 @@ function warnSampled(deps, deviceId, source, message, meta) {
44578
44677
  function warnUnreachable(deps, deviceId, source, err) {
44579
44678
  warnSampled(deps, deviceId, source, UNREACHABLE_MESSAGE, {
44580
44679
  source,
44581
- error: errMsg(err)
44680
+ error: errMsg$1(err)
44582
44681
  });
44583
44682
  }
44584
44683
  /**
@@ -45823,6 +45922,89 @@ function sameFeatures(a, b) {
45823
45922
  return b.every((f) => held.has(f));
45824
45923
  }
45825
45924
  //#endregion
45925
+ //#region src/onboard-forwarding-reconcile.ts
45926
+ /** The `detectionSources` member that means "this camera's own firmware". */
45927
+ var ONBOARD_DETECTION_SOURCE = "onboard";
45928
+ /**
45929
+ * What an ABSENT `detectionSources` means. `CameraDetectionConfig` declares the
45930
+ * field optional and its own contract as "absent is `['pipeline']` all the way
45931
+ * down" — the resolver always fills it, so this only covers the hand-built
45932
+ * configs, and it reads them the same way the runner does.
45933
+ */
45934
+ var DETECTION_SOURCES_WHEN_ABSENT = ["pipeline"];
45935
+ function errMsg(err) {
45936
+ return err instanceof Error ? err.message : String(err);
45937
+ }
45938
+ /**
45939
+ * Put the vendor forwarding flag back where `detectionSources` says it belongs.
45940
+ * Never throws — a camera's attach is not failed by a mechanism that could not
45941
+ * be reached, it is reported.
45942
+ */
45943
+ async function reconcileOnboardForwarding(input, deps) {
45944
+ const { deviceId, detectionSources } = input;
45945
+ const wantsOnboard = detectionSources.includes(ONBOARD_DETECTION_SOURCE);
45946
+ const log = deps.logger.withTags({ deviceId });
45947
+ let hasCap;
45948
+ try {
45949
+ hasCap = await deps.hasNativeObjectDetectionCap(deviceId);
45950
+ } catch (err) {
45951
+ log.warn("onboard forwarding not reconciled — could not tell whether the camera has the cap", { meta: {
45952
+ wantsOnboard,
45953
+ detectionSources: [...detectionSources],
45954
+ error: errMsg(err)
45955
+ } });
45956
+ return {
45957
+ kind: "read-failed",
45958
+ wantsOnboard
45959
+ };
45960
+ }
45961
+ if (!hasCap) return {
45962
+ kind: "no-cap",
45963
+ wantsOnboard
45964
+ };
45965
+ let current;
45966
+ try {
45967
+ current = await deps.readForwardingEnabled(deviceId);
45968
+ } catch (err) {
45969
+ log.warn("onboard forwarding not reconciled — the vendor flag could not be read", { meta: {
45970
+ wantsOnboard,
45971
+ detectionSources: [...detectionSources],
45972
+ error: errMsg(err)
45973
+ } });
45974
+ return {
45975
+ kind: "read-failed",
45976
+ wantsOnboard
45977
+ };
45978
+ }
45979
+ if (current === wantsOnboard) return {
45980
+ kind: "aligned",
45981
+ wantsOnboard
45982
+ };
45983
+ try {
45984
+ await deps.writeForwardingEnabled(deviceId, wantsOnboard);
45985
+ } catch (err) {
45986
+ log.warn("onboard forwarding drifted and the repair failed", { meta: {
45987
+ was: current,
45988
+ wanted: wantsOnboard,
45989
+ detectionSources: [...detectionSources],
45990
+ error: errMsg(err)
45991
+ } });
45992
+ return {
45993
+ kind: "write-failed",
45994
+ wantsOnboard
45995
+ };
45996
+ }
45997
+ log.info("onboard forwarding flag put back to match the camera pick", { meta: {
45998
+ was: current,
45999
+ now: wantsOnboard,
46000
+ detectionSources: [...detectionSources]
46001
+ } });
46002
+ return {
46003
+ kind: "repaired",
46004
+ wantsOnboard
46005
+ };
46006
+ }
46007
+ //#endregion
45826
46008
  //#region src/watchdog-camera.ts
45827
46009
  /**
45828
46010
  * Derive the watchdog camera descriptor from a runner config. Captures which
@@ -45992,7 +46174,7 @@ var DetectionWiringController = class {
45992
46174
  try {
45993
46175
  raw = await this.deps.ctx().settings.readDeviceStore(deviceId);
45994
46176
  } catch (err) {
45995
- const msg = errMsg(err);
46177
+ const msg = errMsg$1(err);
45996
46178
  this.deps.logger.error("resolveDeviceDetectionSettings failed", {
45997
46179
  tags: { deviceId },
45998
46180
  meta: { error: msg }
@@ -46023,7 +46205,7 @@ var DetectionWiringController = class {
46023
46205
  motionDetectionEnabled
46024
46206
  });
46025
46207
  } catch (err) {
46026
- const msg = errMsg(err);
46208
+ const msg = errMsg$1(err);
46027
46209
  this.deps.logger.error("resolveDeviceDetectionSettings narrowing failed", {
46028
46210
  tags: { deviceId },
46029
46211
  meta: { error: msg }
@@ -46053,7 +46235,7 @@ var DetectionWiringController = class {
46053
46235
  } catch (err) {
46054
46236
  this.deps.logger.debug("fetchAssignedProfiles: slot read failed (transient) — treating as unknown", {
46055
46237
  tags: { deviceId },
46056
- meta: { error: errMsg(err) }
46238
+ meta: { error: errMsg$1(err) }
46057
46239
  });
46058
46240
  return null;
46059
46241
  }
@@ -46073,6 +46255,41 @@ var DetectionWiringController = class {
46073
46255
  return buildDetectionConfigFromInputs(resolved, assigned);
46074
46256
  }
46075
46257
  /**
46258
+ * Make the vendor's onboard-AI forwarding flag agree with this camera's
46259
+ * `detectionSources` pick — in both directions. See
46260
+ * `onboard-forwarding-reconcile.ts` for why the save-time write is not
46261
+ * enough (the flag is device state and a provider restart re-seeds it OFF,
46262
+ * measured on all seven Reolink cameras of the live hub).
46263
+ *
46264
+ * Never throws: a mechanism that could not be reached is reported, it does
46265
+ * not fail the camera's attach.
46266
+ */
46267
+ async reconcileOnboardForwarding(deviceId, detectionSources) {
46268
+ return reconcileOnboardForwarding({
46269
+ deviceId,
46270
+ detectionSources
46271
+ }, {
46272
+ hasNativeObjectDetectionCap: (id) => this.deps.deviceHasNativeObjectDetectionCap(id),
46273
+ readForwardingEnabled: async (id) => {
46274
+ const api = this.deps.api();
46275
+ if (!api) throw new Error("orchestrator: no api — cannot read the onboard forwarding flag");
46276
+ const raw = await api.nativeObjectDetection.getStatus.query({ deviceId: id });
46277
+ const parsed = NativeObjectDetectionStatusSchema.safeParse(raw);
46278
+ if (!parsed.success) throw new Error(`orchestrator: nativeObjectDetection.getStatus returned an unusable status — ${parsed.error.message}`);
46279
+ return parsed.data.enabled;
46280
+ },
46281
+ writeForwardingEnabled: async (id, enabled) => {
46282
+ const api = this.deps.api();
46283
+ if (!api) throw new Error("orchestrator: no api — cannot write the onboard forwarding flag");
46284
+ await api.nativeObjectDetection.setEnabled.mutate({
46285
+ deviceId: id,
46286
+ enabled
46287
+ });
46288
+ },
46289
+ logger: this.deps.logger
46290
+ });
46291
+ }
46292
+ /**
46076
46293
  * Start detection for a camera: dispatch to runner via the orchestrator
46077
46294
  * local path and subscribe to the audio broker if audio is enabled.
46078
46295
  */
@@ -46084,6 +46301,7 @@ var DetectionWiringController = class {
46084
46301
  await this.stopDetection(deviceId);
46085
46302
  }
46086
46303
  this.activeDetections.set(deviceId, config);
46304
+ await this.reconcileOnboardForwarding(deviceId, config.detectionSources ?? DETECTION_SOURCES_WHEN_ABSENT);
46087
46305
  if (!config.pipelineEnabled || config.detectionMode === "disabled") if (!config.pipelineEnabled) log.info("object detection switched off — no attach, no decode session", { meta: { detectionMode: config.detectionMode } });
46088
46306
  else log.info("detection mode disabled — no standing attach, no decode session", { meta: {
46089
46307
  detectionMode: config.detectionMode,
@@ -46093,7 +46311,7 @@ var DetectionWiringController = class {
46093
46311
  if (config.motionSources.includes("analyzer")) try {
46094
46312
  await this.deps.session.ensureMotionWatch(deviceId, config);
46095
46313
  } catch (err) {
46096
- log.error("ensureMotionWatch failed", { meta: { error: errMsg(err) } });
46314
+ log.error("ensureMotionWatch failed", { meta: { error: errMsg$1(err) } });
46097
46315
  }
46098
46316
  log.info("detection armed (session-time) — watching for motion", { meta: { motion: config.motionSources.join("+") } });
46099
46317
  } else {
@@ -46112,7 +46330,7 @@ var DetectionWiringController = class {
46112
46330
  const result = await this.deps.placement.dispatchCamera(runnerConfig);
46113
46331
  if (result.kind === "assigned") dispatchedNodeId = result.agentNodeId;
46114
46332
  } catch (err) {
46115
- const msg = errMsg(err);
46333
+ const msg = errMsg$1(err);
46116
46334
  log.error("dispatchCamera failed", { meta: { error: msg } });
46117
46335
  }
46118
46336
  if (dispatchedNodeId && (dispatchedNodeId !== hydrateNodeId || (runnerConfig.steps?.length ?? 0) === 0)) try {
@@ -46141,13 +46359,13 @@ var DetectionWiringController = class {
46141
46359
  });
46142
46360
  }
46143
46361
  } catch (err) {
46144
- log.warn("startDetection: post-dispatch re-resolve failed", { meta: { error: errMsg(err) } });
46362
+ log.warn("startDetection: post-dispatch re-resolve failed", { meta: { error: errMsg$1(err) } });
46145
46363
  }
46146
46364
  }
46147
46365
  try {
46148
46366
  await this.deps.audio.resubscribe(deviceId, config);
46149
46367
  } catch (err) {
46150
- const msg = errMsg(err);
46368
+ const msg = errMsg$1(err);
46151
46369
  log.error("subscribeAudioStream failed", { meta: { error: msg } });
46152
46370
  }
46153
46371
  if (config.detectionMode !== "on-motion") log.info("Detection dispatched", { meta: {
@@ -46163,7 +46381,7 @@ var DetectionWiringController = class {
46163
46381
  try {
46164
46382
  await this.deps.placement.releaseCamera({ deviceId });
46165
46383
  } catch (err) {
46166
- const msg = errMsg(err);
46384
+ const msg = errMsg$1(err);
46167
46385
  this.deps.logger.error("releaseCamera failed", {
46168
46386
  tags: { deviceId },
46169
46387
  meta: { error: msg }
@@ -46189,7 +46407,7 @@ var DetectionWiringController = class {
46189
46407
  } catch (err) {
46190
46408
  this.deps.logger.warn("failed to clear per-device orchestrator settings on removal", {
46191
46409
  tags: { deviceId },
46192
- meta: { error: errMsg(err) }
46410
+ meta: { error: errMsg$1(err) }
46193
46411
  });
46194
46412
  }
46195
46413
  this.deps.logger.info("Purged pipeline config for removed device", { tags: { deviceId } });
@@ -46213,7 +46431,7 @@ var DetectionWiringController = class {
46213
46431
  } catch (err) {
46214
46432
  this.deps.logger.debug("device existence check failed — proceeding as before", {
46215
46433
  tags: { deviceId },
46216
- meta: { error: errMsg(err) }
46434
+ meta: { error: errMsg$1(err) }
46217
46435
  });
46218
46436
  return false;
46219
46437
  }
@@ -46330,7 +46548,7 @@ var DetectionWiringController = class {
46330
46548
  await this.deps.attachOn(assignment.agentNodeId, nextConfig);
46331
46549
  log.info("pipeline.camera-updated: hot-reloaded", { tags: { nodeId: assignment.agentNodeId } });
46332
46550
  } catch (err) {
46333
- const msg = errMsg(err);
46551
+ const msg = errMsg$1(err);
46334
46552
  log.error("pipeline.camera-updated: attachOn failed", {
46335
46553
  tags: { nodeId: assignment.agentNodeId },
46336
46554
  meta: { error: msg }
@@ -46406,7 +46624,7 @@ var DetectionWiringController = class {
46406
46624
  this.deps.audio.resubscribe(deviceId, audioCfg).catch((err) => {
46407
46625
  this.deps.logger.warn("watchdog audio re-subscribe failed", {
46408
46626
  tags: { deviceId },
46409
- meta: { error: errMsg(err) }
46627
+ meta: { error: errMsg$1(err) }
46410
46628
  });
46411
46629
  });
46412
46630
  }
@@ -46605,7 +46823,7 @@ var DeviceConfigContributions = class {
46605
46823
  issue: configIssue
46606
46824
  } });
46607
46825
  this.deps.topology.refreshNodeCapabilities().then(() => this.deps.redispatchAllActiveCameras("ingest-owner-changed")).catch((err) => {
46608
- this.deps.ctx().logger.warn("ingest-owner-changed re-dispatch failed", { meta: { error: errMsg(err) } });
46826
+ this.deps.ctx().logger.warn("ingest-owner-changed re-dispatch failed", { meta: { error: errMsg$1(err) } });
46609
46827
  });
46610
46828
  }
46611
46829
  this.deps.clearOnSettingsChange();
@@ -47345,7 +47563,7 @@ var PlacementService = class {
47345
47563
  async releaseCamera(input) {
47346
47564
  const current = this.deps.ledger.getAssignment(input.deviceId);
47347
47565
  if (current) await this.detachOn(current.agentNodeId, input.deviceId).catch((err) => {
47348
- const msg = errMsg(err);
47566
+ const msg = errMsg$1(err);
47349
47567
  this.deps.ctx().logger.debug("releaseCamera detach failed", {
47350
47568
  tags: { deviceId: input.deviceId },
47351
47569
  meta: { error: msg }
@@ -47373,7 +47591,7 @@ var PlacementService = class {
47373
47591
  pipelineNodeId: input.agentNodeId,
47374
47592
  [PREFERRED_AGENT_SETTING]: null
47375
47593
  }).catch((err) => {
47376
- const msg = errMsg(err);
47594
+ const msg = errMsg$1(err);
47377
47595
  ctx.logger.warn("assignPipeline: failed to persist pin", {
47378
47596
  tags: { deviceId: input.deviceId },
47379
47597
  meta: { error: msg }
@@ -47405,7 +47623,7 @@ var PlacementService = class {
47405
47623
  }
47406
47624
  const current = this.deps.ledger.getAssignment(input.deviceId);
47407
47625
  if (current && current.agentNodeId !== input.agentNodeId) await this.detachOn(current.agentNodeId, input.deviceId).catch((err) => {
47408
- const msg = errMsg(err);
47626
+ const msg = errMsg$1(err);
47409
47627
  ctx.logger.debug("assignPipeline detach-old failed", {
47410
47628
  tags: { deviceId: input.deviceId },
47411
47629
  meta: { error: msg }
@@ -47430,7 +47648,7 @@ var PlacementService = class {
47430
47648
  await ctx.settings?.writeDeviceStore(input.deviceId, { pipelineDeviceKey: clearing ? "auto" : input.deviceKey }).catch((err) => {
47431
47649
  ctx.logger.warn("setPipelineDevicePin: failed to persist device pin", {
47432
47650
  tags: { deviceId: input.deviceId },
47433
- meta: { error: errMsg(err) }
47651
+ meta: { error: errMsg$1(err) }
47434
47652
  });
47435
47653
  });
47436
47654
  const sessionNode = this.deps.activeSessionNode(input.deviceId);
@@ -47453,7 +47671,7 @@ var PlacementService = class {
47453
47671
  [PREFERRED_AGENT_SETTING]: null,
47454
47672
  pipelineNodeId: "auto"
47455
47673
  }).catch((err) => {
47456
- const msg = errMsg(err);
47674
+ const msg = errMsg$1(err);
47457
47675
  ctx.logger.warn("unassignPipeline: failed to clear pin", {
47458
47676
  tags: { deviceId: input.deviceId },
47459
47677
  meta: { error: msg }
@@ -47474,7 +47692,7 @@ var PlacementService = class {
47474
47692
  else {
47475
47693
  const targetNodeId = decision.agentNodeId;
47476
47694
  if (current && current.agentNodeId !== targetNodeId) await this.detachOn(current.agentNodeId, input.deviceId).catch((err) => {
47477
- const msg = errMsg(err);
47695
+ const msg = errMsg$1(err);
47478
47696
  ctx.logger.debug("unassignPipeline detach-old failed", {
47479
47697
  tags: { deviceId: input.deviceId },
47480
47698
  meta: { error: msg }
@@ -47494,7 +47712,7 @@ var PlacementService = class {
47494
47712
  }
47495
47713
  }
47496
47714
  if (current) await this.detachOn(current.agentNodeId, input.deviceId).catch((err) => {
47497
- const msg = errMsg(err);
47715
+ const msg = errMsg$1(err);
47498
47716
  ctx.logger.debug("unassignPipeline detach failed", {
47499
47717
  tags: { deviceId: input.deviceId },
47500
47718
  meta: { error: msg }
@@ -47513,7 +47731,7 @@ var PlacementService = class {
47513
47731
  async runAutoRebalance() {
47514
47732
  if (!this.deps.ctxIfReady()) return;
47515
47733
  await this.deps.reconcilePlacementFromRunners().catch((err) => {
47516
- this.deps.ctx().logger.debug("auto-rebalance: attachment reconcile failed", { meta: { error: errMsg(err) } });
47734
+ this.deps.ctx().logger.debug("auto-rebalance: attachment reconcile failed", { meta: { error: errMsg$1(err) } });
47517
47735
  });
47518
47736
  if (this.autoRebalanceInFlight) return;
47519
47737
  if (this.deps.topology.enabledNodes.length < 2) return;
@@ -47522,7 +47740,7 @@ var PlacementService = class {
47522
47740
  const { migrated } = await this.rebalance({ minImprovement: AUTO_REBALANCE_MIN_IMPROVEMENT });
47523
47741
  if (migrated > 0) this.deps.ctx().logger.info("auto-rebalance: corrected placement drift", { meta: { migrated } });
47524
47742
  } catch (err) {
47525
- this.deps.ctx().logger.debug("auto-rebalance pass failed", { meta: { error: errMsg(err) } });
47743
+ this.deps.ctx().logger.debug("auto-rebalance pass failed", { meta: { error: errMsg$1(err) } });
47526
47744
  } finally {
47527
47745
  this.autoRebalanceInFlight = false;
47528
47746
  }
@@ -47573,7 +47791,7 @@ var PlacementService = class {
47573
47791
  }
47574
47792
  if (current) {
47575
47793
  await this.detachOn(current.agentNodeId, deviceId).catch((err) => {
47576
- const msg = errMsg(err);
47794
+ const msg = errMsg$1(err);
47577
47795
  ctx.logger.debug("rebalance detach-old failed", {
47578
47796
  tags: { deviceId },
47579
47797
  meta: { error: msg }
@@ -47900,7 +48118,7 @@ var NodeLifecycleHandler = class {
47900
48118
  nodeId: decision.agentNodeId
47901
48119
  } });
47902
48120
  } catch (err) {
47903
- const msg = errMsg(err);
48121
+ const msg = errMsg$1(err);
47904
48122
  this.deps.logger.error("Failover: attach failed", {
47905
48123
  tags: {
47906
48124
  deviceId,
@@ -47930,7 +48148,7 @@ var NodeLifecycleHandler = class {
47930
48148
  this.deps.schedulePendingRetry();
47931
48149
  if (failoverPolicy.onReconnect === "rebalance") {
47932
48150
  await this.deps.rebalance().catch((err) => {
47933
- const msg = errMsg(err);
48151
+ const msg = errMsg$1(err);
47934
48152
  this.deps.logger.error("rebalance after reconnect failed", { meta: { error: msg } });
47935
48153
  });
47936
48154
  return;
@@ -47956,7 +48174,7 @@ var NodeLifecycleHandler = class {
47956
48174
  this.deps.ledger.recordAssignment(deviceId, nodeId, "failover", false);
47957
48175
  restored++;
47958
48176
  } catch (err) {
47959
- const msg = errMsg(err);
48177
+ const msg = errMsg$1(err);
47960
48178
  this.deps.logger.error("restore attach failed", {
47961
48179
  tags: {
47962
48180
  deviceId,
@@ -48046,7 +48264,7 @@ var NodeLifecycleHandler = class {
48046
48264
  deviceId,
48047
48265
  nodeId
48048
48266
  },
48049
- meta: { error: errMsg(err) }
48267
+ meta: { error: errMsg$1(err) }
48050
48268
  });
48051
48269
  }
48052
48270
  this.deps.logger.info("readiness: detection-pipeline reseeded agent defaults + redispatched cameras", {
@@ -48060,7 +48278,7 @@ var NodeLifecycleHandler = class {
48060
48278
  this.reattachStaleEmpties(nodeId).catch((err) => {
48061
48279
  this.deps.logger.debug("readiness deferred sweep failed", {
48062
48280
  tags: { nodeId },
48063
- meta: { error: errMsg(err) }
48281
+ meta: { error: errMsg$1(err) }
48064
48282
  });
48065
48283
  });
48066
48284
  }, 3e3);
@@ -48071,7 +48289,7 @@ var NodeLifecycleHandler = class {
48071
48289
  tags: { nodeId },
48072
48290
  meta: {
48073
48291
  epoch: t.epoch,
48074
- error: errMsg(err)
48292
+ error: errMsg$1(err)
48075
48293
  }
48076
48294
  });
48077
48295
  }
@@ -48110,7 +48328,7 @@ var NodeLifecycleHandler = class {
48110
48328
  deviceId,
48111
48329
  nodeId
48112
48330
  },
48113
- meta: { error: errMsg(err) }
48331
+ meta: { error: errMsg$1(err) }
48114
48332
  });
48115
48333
  }
48116
48334
  }
@@ -48432,7 +48650,7 @@ var NodeStressController = class NodeStressController {
48432
48650
  if (this.timer) return;
48433
48651
  this.timer = setInterval(() => {
48434
48652
  this.sweep().catch((err) => {
48435
- this.deps.logger.warn("node-stress sweep failed", { meta: { error: errMsg(err) } });
48653
+ this.deps.logger.warn("node-stress sweep failed", { meta: { error: errMsg$1(err) } });
48436
48654
  });
48437
48655
  }, NodeStressController.SWEEP_INTERVAL_MS);
48438
48656
  }
@@ -48605,7 +48823,7 @@ var NodeStressController = class NodeStressController {
48605
48823
  meta: {
48606
48824
  from: plan.fromNodeId,
48607
48825
  to: plan.toNodeId,
48608
- error: errMsg(err)
48826
+ error: errMsg$1(err)
48609
48827
  }
48610
48828
  });
48611
48829
  } finally {
@@ -49302,7 +49520,7 @@ var NodeTopologyService = class {
49302
49520
  try {
49303
49521
  blob = await this.deps.readAgentSettingsMap();
49304
49522
  } catch (err) {
49305
- this.deps.logger.warn("refreshNodeCapabilities: agent settings read failed", { meta: { error: errMsg(err) } });
49523
+ this.deps.logger.warn("refreshNodeCapabilities: agent settings read failed", { meta: { error: errMsg$1(err) } });
49306
49524
  }
49307
49525
  const nodeIds = new Set(["hub"]);
49308
49526
  for (const nodeId of Object.keys(blob)) if (typeof nodeId === "string" && nodeId.length > 0 && !nodeId.includes("/")) nodeIds.add(nodeId);
@@ -49360,7 +49578,7 @@ function wireOrchestratorSubscriptions(deps) {
49360
49578
  const unsubInferenceResult = deps.eventBus.subscribe({ category: EventCategory.PipelineInferenceResult }, (event) => {
49361
49579
  if (!isEvent(event, EventCategory.PipelineInferenceResult)) return;
49362
49580
  deps.handleInferenceResult(event.data).catch((err) => {
49363
- const msg = errMsg(err);
49581
+ const msg = errMsg$1(err);
49364
49582
  deps.logger.error("PipelineInferenceResult post-processing failed", {
49365
49583
  tags: { deviceId: event.data.deviceId },
49366
49584
  meta: { error: msg }
@@ -49379,7 +49597,7 @@ function wireOrchestratorSubscriptions(deps) {
49379
49597
  deps.logger.info("received onProfileSlotsChanged", { tags: { deviceId } });
49380
49598
  deps.handleDeviceRegistered(deviceId).catch((err) => {
49381
49599
  if (isTornDown) return;
49382
- const msg = errMsg(err);
49600
+ const msg = errMsg$1(err);
49383
49601
  deps.logger.error("handleDeviceRegistered failed", {
49384
49602
  tags: { deviceId },
49385
49603
  meta: { error: msg }
@@ -49391,7 +49609,7 @@ function wireOrchestratorSubscriptions(deps) {
49391
49609
  const unsubDeviceUnregistered = deps.eventBus.subscribe({ category: EventCategory.DeviceUnregistered }, (event) => {
49392
49610
  const { deviceId } = event.data;
49393
49611
  deps.handleDeviceUnregistered(deviceId).catch((err) => {
49394
- const msg = errMsg(err);
49612
+ const msg = errMsg$1(err);
49395
49613
  deps.logger.error("handleDeviceUnregistered failed", {
49396
49614
  tags: { deviceId },
49397
49615
  meta: { error: msg }
@@ -49403,7 +49621,7 @@ function wireOrchestratorSubscriptions(deps) {
49403
49621
  const { deviceId } = event.data;
49404
49622
  deps.handleSettingsChanged(deviceId).catch((err) => {
49405
49623
  if (isTornDown) return;
49406
- const msg = errMsg(err);
49624
+ const msg = errMsg$1(err);
49407
49625
  deps.logger.error("handleSettingsChanged failed", {
49408
49626
  tags: { deviceId },
49409
49627
  meta: { error: msg }
@@ -49413,7 +49631,7 @@ function wireOrchestratorSubscriptions(deps) {
49413
49631
  const unsubCameraUpdated = deps.eventBus.subscribe({ category: EventCategory.PipelineCameraUpdated }, (event) => {
49414
49632
  if (!isEvent(event, EventCategory.PipelineCameraUpdated)) return;
49415
49633
  deps.handlePipelineCameraUpdated(event.data.deviceId, event.data.config).catch((err) => {
49416
- const msg = errMsg(err);
49634
+ const msg = errMsg$1(err);
49417
49635
  deps.logger.error("handlePipelineCameraUpdated failed", {
49418
49636
  tags: { deviceId: event.data.deviceId },
49419
49637
  meta: { error: msg }
@@ -49426,7 +49644,7 @@ function wireOrchestratorSubscriptions(deps) {
49426
49644
  if (!(reason === "wrapper-activated" || reason === "wrapper-deactivated") || !(capName === "detection-pipeline" || capName === "audio-analysis" || capName === "motion-detection")) return;
49427
49645
  deps.handleSettingsChanged(deviceId).catch((err) => {
49428
49646
  if (isTornDown) return;
49429
- const msg = errMsg(err);
49647
+ const msg = errMsg$1(err);
49430
49648
  deps.logger.error("binding-changed re-dispatch failed", {
49431
49649
  tags: { deviceId },
49432
49650
  meta: {
@@ -49454,7 +49672,7 @@ function wireOrchestratorSubscriptions(deps) {
49454
49672
  tags: { deviceId },
49455
49673
  meta: {
49456
49674
  detected,
49457
- error: errMsg(err)
49675
+ error: errMsg$1(err)
49458
49676
  }
49459
49677
  });
49460
49678
  });
@@ -49469,7 +49687,7 @@ function wireOrchestratorSubscriptions(deps) {
49469
49687
  tags: { deviceId },
49470
49688
  meta: {
49471
49689
  detected,
49472
- error: errMsg(err)
49690
+ error: errMsg$1(err)
49473
49691
  }
49474
49692
  });
49475
49693
  });
@@ -50463,7 +50681,7 @@ var PipelineSettingsStore = class PipelineSettingsStore {
50463
50681
  } catch (err) {
50464
50682
  this.deps.logger.debug("getCatalogForAgent failed", {
50465
50683
  tags: { nodeId },
50466
- meta: { error: errMsg(err) }
50684
+ meta: { error: errMsg$1(err) }
50467
50685
  });
50468
50686
  return null;
50469
50687
  }
@@ -50526,7 +50744,7 @@ var PipelineSettingsStore = class PipelineSettingsStore {
50526
50744
  tags: { deviceId },
50527
50745
  meta: {
50528
50746
  capName: "detection-pipeline",
50529
- error: errMsg(err)
50747
+ error: errMsg$1(err)
50530
50748
  }
50531
50749
  });
50532
50750
  return true;
@@ -51249,7 +51467,7 @@ var ReconcileController = class ReconcileController {
51249
51467
  try {
51250
51468
  slots = await api.streamBroker.listAllProfileSlots.query();
51251
51469
  } catch (err) {
51252
- this.deps.logger.debug("dispatch reconcile skipped — stream-broker not ready", { meta: { error: errMsg(err) } });
51470
+ this.deps.logger.debug("dispatch reconcile skipped — stream-broker not ready", { meta: { error: errMsg$1(err) } });
51253
51471
  return;
51254
51472
  }
51255
51473
  const desired = desiredDeviceIdsFromSlots(slots);
@@ -51276,7 +51494,7 @@ var ReconcileController = class ReconcileController {
51276
51494
  } catch (err) {
51277
51495
  this.deps.logger.warn("dispatch reconcile: handleDeviceRegistered failed", {
51278
51496
  tags: { deviceId },
51279
- meta: { error: errMsg(err) }
51497
+ meta: { error: errMsg$1(err) }
51280
51498
  });
51281
51499
  }
51282
51500
  await this.reconcilePlacementFromRunners();
@@ -51304,7 +51522,7 @@ var ReconcileController = class ReconcileController {
51304
51522
  const devices = await api.deviceManager.listAll.query({ projection: "slim" });
51305
51523
  return new Set(devices.map((device) => device.id));
51306
51524
  } catch (err) {
51307
- this.deps.logger.debug("dispatch reconcile: deviceManager.listAll failed", { meta: { error: errMsg(err) } });
51525
+ this.deps.logger.debug("dispatch reconcile: deviceManager.listAll failed", { meta: { error: errMsg$1(err) } });
51308
51526
  return null;
51309
51527
  }
51310
51528
  }
@@ -51330,7 +51548,7 @@ var ReconcileController = class ReconcileController {
51330
51548
  } catch (err) {
51331
51549
  this.deps.logger.warn("dispatch reconcile: teardown of vanished device failed", {
51332
51550
  tags: { deviceId },
51333
- meta: { error: errMsg(err) }
51551
+ meta: { error: errMsg$1(err) }
51334
51552
  });
51335
51553
  }
51336
51554
  }
@@ -51387,7 +51605,7 @@ var ReconcileController = class ReconcileController {
51387
51605
  this.deps.logger.debug("placement reconcile skipped node — getLocalCameras failed", {
51388
51606
  tags: { nodeId },
51389
51607
  meta: {
51390
- error: outcome.kind === "rejected" ? errMsg(outcome.error) : "budget exceeded",
51608
+ error: outcome.kind === "rejected" ? errMsg$1(outcome.error) : "budget exceeded",
51391
51609
  ms
51392
51610
  }
51393
51611
  });
@@ -51417,7 +51635,7 @@ var ReconcileController = class ReconcileController {
51417
51635
  nodeId,
51418
51636
  deviceId
51419
51637
  },
51420
- meta: { error: errMsg(err) }
51638
+ meta: { error: errMsg$1(err) }
51421
51639
  });
51422
51640
  })));
51423
51641
  }
@@ -51459,7 +51677,7 @@ var ReconcileController = class ReconcileController {
51459
51677
  this.deps.handleDeviceRegistered(deviceId).catch((err) => {
51460
51678
  this.deps.logger.debug("slot-read retry: handleDeviceRegistered failed", {
51461
51679
  tags: { deviceId },
51462
- meta: { error: errMsg(err) }
51680
+ meta: { error: errMsg$1(err) }
51463
51681
  });
51464
51682
  });
51465
51683
  }, delay);
@@ -51537,7 +51755,7 @@ var ReconcileController = class ReconcileController {
51537
51755
  } catch (err) {
51538
51756
  this.deps.logger.warn("pending retry: dispatchCamera failed", {
51539
51757
  tags: { deviceId },
51540
- meta: { error: errMsg(err) }
51758
+ meta: { error: errMsg$1(err) }
51541
51759
  });
51542
51760
  stillPending++;
51543
51761
  }
@@ -51615,7 +51833,7 @@ var ReconcileController = class ReconcileController {
51615
51833
  await this.deps.detachOn(assignment.agentNodeId, deviceId).catch((err) => {
51616
51834
  this.deps.logger.debug("remote-health exhausted-detach failed", {
51617
51835
  tags: { deviceId },
51618
- meta: { error: errMsg(err) }
51836
+ meta: { error: errMsg$1(err) }
51619
51837
  });
51620
51838
  });
51621
51839
  return;
@@ -51638,14 +51856,14 @@ var ReconcileController = class ReconcileController {
51638
51856
  await this.deps.detachOn(assignment.agentNodeId, deviceId).catch((err) => {
51639
51857
  this.deps.logger.warn("remote-health detach failed", {
51640
51858
  tags: { deviceId },
51641
- meta: { error: errMsg(err) }
51859
+ meta: { error: errMsg$1(err) }
51642
51860
  });
51643
51861
  });
51644
51862
  this.deps.ledger.dropAssignment(deviceId, "silent");
51645
51863
  await this.deps.dispatchCamera(cfg).catch((err) => {
51646
51864
  this.deps.logger.warn("remote-health re-dispatch failed", {
51647
51865
  tags: { deviceId },
51648
- meta: { error: errMsg(err) }
51866
+ meta: { error: errMsg$1(err) }
51649
51867
  });
51650
51868
  });
51651
51869
  }
@@ -52294,7 +52512,7 @@ var SessionDispatchController = class {
52294
52512
  deviceId,
52295
52513
  nodeId: session.nodeId
52296
52514
  },
52297
- meta: { error: errMsg(err) }
52515
+ meta: { error: errMsg$1(err) }
52298
52516
  });
52299
52517
  });
52300
52518
  this.deps.dropAssignment(deviceId, "silent");
@@ -52357,7 +52575,8 @@ var SessionDispatchController = class {
52357
52575
  occupancyRecheckSec: config.occupancyRecheckSec,
52358
52576
  occupancyRecheckFrames: config.occupancyRecheckFrames,
52359
52577
  preRollInferenceEnabled: config.preRollInferenceEnabled,
52360
- preRollInferenceFrames: config.preRollInferenceFrames
52578
+ preRollInferenceFrames: config.preRollInferenceFrames,
52579
+ detectionSources: config.detectionSources
52361
52580
  };
52362
52581
  await this.deps.attachOn(nodeId, watchConfig);
52363
52582
  this.motionWatchByDevice.set(deviceId, nodeId);
@@ -52478,7 +52697,7 @@ var SessionDispatchController = class {
52478
52697
  };
52479
52698
  if (reconcileBudgetExceeded) log.warn("detection session: placement census overran its budget — placing without it", { meta: { budgetMs: 500 } });
52480
52699
  else if (censusOutcome.kind === "rejected") log.warn("detection session: placement census failed — placing on the ledger as it is", { meta: {
52481
- error: errMsg(censusOutcome.error),
52700
+ error: errMsg$1(censusOutcome.error),
52482
52701
  reconcileMs
52483
52702
  } });
52484
52703
  const balanceStartedAt = Date.now();
@@ -52570,7 +52789,8 @@ var SessionDispatchController = class {
52570
52789
  occupancyRecheckSec: config.occupancyRecheckSec,
52571
52790
  occupancyRecheckFrames: config.occupancyRecheckFrames,
52572
52791
  preRollInferenceEnabled: config.preRollInferenceEnabled,
52573
- preRollInferenceFrames: config.preRollInferenceFrames
52792
+ preRollInferenceFrames: config.preRollInferenceFrames,
52793
+ detectionSources: config.detectionSources
52574
52794
  };
52575
52795
  const configuredAt = Date.now();
52576
52796
  let attachedAt = configuredAt;
@@ -52639,7 +52859,7 @@ var SessionDispatchController = class {
52639
52859
  await this.resolveSessionLifecycleLocked(deviceId, reason);
52640
52860
  }).catch((err) => {
52641
52861
  log.warn("detection session: lifecycle re-check failed", { meta: {
52642
- error: errMsg(err),
52862
+ error: errMsg$1(err),
52643
52863
  reason
52644
52864
  } });
52645
52865
  });
@@ -52744,7 +52964,7 @@ var SessionDispatchController = class {
52744
52964
  log.warn("detection session: teardown detach failed", {
52745
52965
  tags: { nodeId: session.nodeId },
52746
52966
  meta: {
52747
- error: errMsg(err),
52967
+ error: errMsg$1(err),
52748
52968
  reason
52749
52969
  }
52750
52970
  });
@@ -52827,7 +53047,7 @@ var SessionDispatchController = class {
52827
53047
  deviceId,
52828
53048
  nodeId: session.nodeId
52829
53049
  },
52830
- meta: { error: errMsg(err) }
53050
+ meta: { error: errMsg$1(err) }
52831
53051
  });
52832
53052
  });
52833
53053
  this.sessionRegistry.deregister(deviceId);
@@ -52845,7 +53065,7 @@ var SessionDispatchController = class {
52845
53065
  deviceId,
52846
53066
  nodeId: watchNodeId
52847
53067
  },
52848
- meta: { error: errMsg(err) }
53068
+ meta: { error: errMsg$1(err) }
52849
53069
  });
52850
53070
  });
52851
53071
  this.motionWatchByDevice.delete(deviceId);
@@ -53025,7 +53245,7 @@ async function sweepMirror(deps, hydrator, cameraIds) {
53025
53245
  tags: { deviceId },
53026
53246
  meta: {
53027
53247
  mirror: hydrator.mirror,
53028
- error: errMsg(err)
53248
+ error: errMsg$1(err)
53029
53249
  }
53030
53250
  });
53031
53251
  return "threw";
@@ -53065,7 +53285,7 @@ async function readCameraIds(deps) {
53065
53285
  lastError = err;
53066
53286
  }
53067
53287
  if (Date.now() >= deadline) {
53068
- 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) } });
53288
+ 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) } });
53069
53289
  return null;
53070
53290
  }
53071
53291
  await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
@@ -53706,7 +53926,7 @@ async function buildOrchestratorControllers(deps) {
53706
53926
  } catch (err) {
53707
53927
  return {
53708
53928
  kind: "unknown",
53709
- reason: errMsg(err)
53929
+ reason: errMsg$1(err)
53710
53930
  };
53711
53931
  }
53712
53932
  };
@@ -53790,14 +54010,14 @@ async function buildOrchestratorControllers(deps) {
53790
54010
  readGlobalSettings: () => globalSettings
53791
54011
  });
53792
54012
  await NodeStressMoveLedger.declare(deps.ctx().api.settingsStore).then(() => nodeStress.hydrate()).catch((err) => {
53793
- deps.ctx().logger.warn("node-stress move history unavailable — this boot starts cold", { meta: { error: errMsg(err) } });
54013
+ deps.ctx().logger.warn("node-stress move history unavailable — this boot starts cold", { meta: { error: errMsg$1(err) } });
53794
54014
  });
53795
54015
  await NodeStressLts.declare(deps.ctx().api.settingsStore).catch((err) => {
53796
- deps.ctx().logger.warn("node-stress statistics unavailable — no baseline this boot", { meta: { error: errMsg(err) } });
54016
+ deps.ctx().logger.warn("node-stress statistics unavailable — no baseline this boot", { meta: { error: errMsg$1(err) } });
53797
54017
  });
53798
54018
  const nodeStressLtsTimer = setInterval(() => {
53799
54019
  nodeStressLts.flushDue().catch((err) => {
53800
- deps.ctx().logger.warn("node-stress statistics flush failed", { meta: { error: errMsg(err) } });
54020
+ deps.ctx().logger.warn("node-stress statistics flush failed", { meta: { error: errMsg$1(err) } });
53801
54021
  });
53802
54022
  }, 6e4);
53803
54023
  nodeStress.start();
@@ -53934,7 +54154,7 @@ async function buildOrchestratorControllers(deps) {
53934
54154
  deps.applyRuntimeSettings(globalSettings);
53935
54155
  await topology.refreshNodeCapabilities();
53936
54156
  } catch (err) {
53937
- const msg = errMsg(err);
54157
+ const msg = errMsg$1(err);
53938
54158
  deps.ctx().logger.warn("orchestrator settings load failed — using defaults", { meta: { error: msg } });
53939
54159
  }
53940
54160
  const rawNodeId = deps.ctx().kernel.localNodeId ?? "hub";
@@ -53967,7 +54187,7 @@ async function buildOrchestratorControllers(deps) {
53967
54187
  nodeLifecycle.unsubscribeDetectionPipelineReadiness(nodeId);
53968
54188
  audio.markNodeOffline(nodeId);
53969
54189
  nodeLifecycle.handleNodeDisconnect(nodeId).catch((err) => {
53970
- const msg = errMsg(err);
54190
+ const msg = errMsg$1(err);
53971
54191
  deps.ctx().logger.error("failover after disconnect failed", {
53972
54192
  tags: { nodeId },
53973
54193
  meta: { error: msg }
@@ -53982,7 +54202,7 @@ async function buildOrchestratorControllers(deps) {
53982
54202
  deps.subscribeToAudioAnalyzerReadiness(nodeId);
53983
54203
  }
53984
54204
  nodeLifecycle.handleNodeConnect(nodeId).catch((err) => {
53985
- const msg = errMsg(err);
54205
+ const msg = errMsg$1(err);
53986
54206
  deps.ctx().logger.error("reconnect handling failed", {
53987
54207
  tags: { nodeId },
53988
54208
  meta: { error: msg }
@@ -53996,7 +54216,7 @@ async function buildOrchestratorControllers(deps) {
53996
54216
  meta: { capName }
53997
54217
  });
53998
54218
  nodeLifecycle.handleNodeDisconnect(nodeId).catch((err) => {
53999
- const msg = errMsg(err);
54219
+ const msg = errMsg$1(err);
54000
54220
  deps.ctx().logger.error("failover after cap-down failed", {
54001
54221
  tags: { nodeId },
54002
54222
  meta: {
@@ -54059,7 +54279,7 @@ async function buildOrchestratorControllers(deps) {
54059
54279
  doneFlag: settingsStore.bindingsMigrationDoneState,
54060
54280
  logger: deps.ctx().logger
54061
54281
  }).catch((err) => {
54062
- deps.ctxIfReady()?.logger.warn("bindings migration failed — will retry on next boot", { meta: { error: errMsg(err) } });
54282
+ deps.ctxIfReady()?.logger.warn("bindings migration failed — will retry on next boot", { meta: { error: errMsg$1(err) } });
54063
54283
  });
54064
54284
  migrateStepGating({
54065
54285
  readCameraSettings: () => settingsStore.readCameraSettingsMap(),
@@ -54070,7 +54290,7 @@ async function buildOrchestratorControllers(deps) {
54070
54290
  }).then(async () => {
54071
54291
  if (await settingsStore.applyPerNodeDeviceMigration()) deps.ctxIfReady()?.logger.info("per-(node,device) config migration applied");
54072
54292
  }).catch((err) => {
54073
- deps.ctxIfReady()?.logger.warn("step-gating / per-node-device migration failed — retry next boot", { meta: { error: errMsg(err) } });
54293
+ deps.ctxIfReady()?.logger.warn("step-gating / per-node-device migration failed — retry next boot", { meta: { error: errMsg$1(err) } });
54074
54294
  });
54075
54295
  const zoneRulesProvider = new ZoneRulesProvider({
54076
54296
  logger: deps.ctx().logger.child("zone-rules"),
@@ -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
  }
@@ -54126,7 +54346,7 @@ async function buildOrchestratorControllers(deps) {
54126
54346
  deviceId,
54127
54347
  nodeId: assignment.agentNodeId
54128
54348
  },
54129
- meta: { error: errMsg(err) }
54349
+ meta: { error: errMsg$1(err) }
54130
54350
  });
54131
54351
  });
54132
54352
  }
@@ -54142,7 +54362,7 @@ async function buildOrchestratorControllers(deps) {
54142
54362
  }],
54143
54363
  logger: deps.ctx().logger.child("zones")
54144
54364
  }).catch((err) => {
54145
- deps.ctxIfReady()?.logger.warn("zones mirror boot hydration failed", { meta: { error: errMsg(err) } });
54365
+ deps.ctxIfReady()?.logger.warn("zones mirror boot hydration failed", { meta: { error: errMsg$1(err) } });
54146
54366
  });
54147
54367
  const unsubOrchestratorSubscriptions = wireOrchestratorSubscriptions({
54148
54368
  eventBus: deps.ctx().eventBus,
@@ -54191,10 +54411,11 @@ async function buildOrchestratorControllers(deps) {
54191
54411
  isCapActiveForDevice: (deviceId, capName) => deps.isCapActiveForDevice(deviceId, capName),
54192
54412
  deviceHasOnboardMotionCap: (deviceId) => deps.deviceHasOnboardMotionCap(deviceId),
54193
54413
  deviceHasActivitySignalCap: (deviceId) => deps.deviceHasActivitySignalCap(deviceId),
54414
+ deviceHasNativeObjectDetectionCap: (deviceId) => deps.deviceHasNativeObjectDetectionCap(deviceId),
54194
54415
  deviceSettingsSchema: () => deps.deviceSettingsSchema()
54195
54416
  });
54196
54417
  await detectionWiring.hydrateFeaturesMirror().catch((err) => {
54197
- deps.ctx().logger.warn("device-features mirror not restored — this boot starts cold", { meta: { error: errMsg(err) } });
54418
+ deps.ctx().logger.warn("device-features mirror not restored — this boot starts cold", { meta: { error: errMsg$1(err) } });
54198
54419
  });
54199
54420
  return {
54200
54421
  ledger,
@@ -55267,7 +55488,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
55267
55488
  for (const deviceId of this.detectionWiring.activeDetectionDeviceIds()) try {
55268
55489
  await this.releaseCamera({ deviceId });
55269
55490
  } catch (err) {
55270
- const msg = errMsg(err);
55491
+ const msg = errMsg$1(err);
55271
55492
  this.ctx.logger.debug("releaseCamera failed during shutdown", {
55272
55493
  tags: { deviceId },
55273
55494
  meta: { error: msg }
@@ -55893,7 +56114,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
55893
56114
  tags: { nodeId },
55894
56115
  meta: {
55895
56116
  nodeId,
55896
- error: errMsg(err)
56117
+ error: errMsg$1(err)
55897
56118
  }
55898
56119
  });
55899
56120
  return null;
@@ -55999,7 +56220,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
55999
56220
  tags: { nodeId },
56000
56221
  meta: {
56001
56222
  nodeId,
56002
- error: errMsg(err)
56223
+ error: errMsg$1(err)
56003
56224
  }
56004
56225
  });
56005
56226
  return {
@@ -56046,7 +56267,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
56046
56267
  } catch (err) {
56047
56268
  this.ctx.logger.warn("resetNodePipelineDefaults: executor clearDeviceOverrides failed (node offline?)", {
56048
56269
  tags: { nodeId: node },
56049
- meta: { error: errMsg(err) }
56270
+ meta: { error: errMsg$1(err) }
56050
56271
  });
56051
56272
  }
56052
56273
  this.settingsStore.invalidateCatalog();
@@ -56057,7 +56278,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
56057
56278
  } catch (err) {
56058
56279
  this.ctx.logger.warn("resetNodePipelineDefaults: effective-model probe failed (node offline?)", {
56059
56280
  tags: { nodeId: node },
56060
- meta: { error: errMsg(err) }
56281
+ meta: { error: errMsg$1(err) }
56061
56282
  });
56062
56283
  }
56063
56284
  this.ctx.logger.info("node pipeline reset to hardware-aware defaults", {
@@ -56274,7 +56495,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
56274
56495
  tags: { deviceId },
56275
56496
  meta: {
56276
56497
  capName,
56277
- error: errMsg(err)
56498
+ error: errMsg$1(err)
56278
56499
  }
56279
56500
  });
56280
56501
  return true;