@camstack/addon-pipeline-orchestrator 1.2.311 → 1.2.312

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
@@ -5418,7 +5418,7 @@ var ZodIssueCode = {
5418
5418
  var ZodFirstPartyTypeKind;
5419
5419
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5420
5420
  //#endregion
5421
- //#region ../types/dist/sleep-vWTnHq9G.mjs
5421
+ //#region ../types/dist/sleep-B_3F_YwS.mjs
5422
5422
  /**
5423
5423
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5424
5424
  * window to float samples (D455).
@@ -15021,6 +15021,16 @@ var BrokerClientsSchema = object({
15021
15021
  /** Total encoded + raw-RTP callback subscriber count (sum of `encoded[].length`). */
15022
15022
  encodedSubscribers: number()
15023
15023
  });
15024
+ /**
15025
+ * How many people are watching one camera LIVE right now — see
15026
+ * `getLiveViewerCounts`. A camera with nobody watching is absent from the list
15027
+ * (so `viewers` is always at least 1): the listing carries the cameras that
15028
+ * have viewers, never a row of zeros.
15029
+ */
15030
+ var LiveViewerCountSchema = object({
15031
+ deviceId: number().int().nonnegative(),
15032
+ viewers: number().int().positive()
15033
+ });
15024
15034
  _enum([
15025
15035
  "reconnecting",
15026
15036
  "sleeping",
@@ -15381,7 +15391,7 @@ method(object({
15381
15391
  }), {
15382
15392
  kind: "mutation",
15383
15393
  auth: "admin"
15384
- }), method(object({ brokerId: string() }), BrokerClientsSchema), method(object({
15394
+ }), method(object({ brokerId: string() }), BrokerClientsSchema), method(_void(), array(LiveViewerCountSchema).readonly()), method(object({
15385
15395
  brokerId: string(),
15386
15396
  channel: _enum(["rtsp", "audio"]),
15387
15397
  handle: string()
@@ -28808,19 +28818,6 @@ var RunnerCameraDeviceUIFields = [
28808
28818
  label: MOTION_SOURCE_LABELS[value]
28809
28819
  })
28810
28820
  },
28811
- {
28812
- key: "detectionSources",
28813
- type: "multiselect",
28814
- label: "Detection Sources",
28815
- default: ["pipeline"],
28816
- options: [{
28817
- value: "pipeline",
28818
- label: "This node (ML root step on decoded frames)"
28819
- }, {
28820
- value: "onboard",
28821
- label: "Camera onboard AI (replaces the root step when picked alone)"
28822
- }]
28823
- },
28824
28821
  {
28825
28822
  key: "motionFps",
28826
28823
  type: "slider",
@@ -29303,6 +29300,12 @@ var CameraStepOverridePatchSchema = object({
29303
29300
  settings: record(string(), unknown()).readonly().optional()
29304
29301
  });
29305
29302
  var CameraStepSettingsSchema = record(string(), record(string(), unknown()).readonly());
29303
+ /** The three root-detector choices a camera has (D507: at most one root). */
29304
+ var CameraDetectionSourceSchema = _enum([
29305
+ "pipeline",
29306
+ "onboard",
29307
+ "none"
29308
+ ]);
29306
29309
  var CameraPipelineSettingsSchema = object({
29307
29310
  stepToggles: record(string(), boolean()).optional(),
29308
29311
  stepSettings: CameraStepSettingsSchema.optional(),
@@ -30201,6 +30204,41 @@ var pipelineOrchestratorCapability = {
30201
30204
  kind: "mutation",
30202
30205
  auth: "admin"
30203
30206
  }),
30207
+ /**
30208
+ * Where this camera's first-level detections come from: this node's own
30209
+ * root step (`pipeline`), the camera's onboard detector alone (`onboard`),
30210
+ * or no root detector (`none`). A camera runs at most one root detector
30211
+ * (D507), so there is no "both". Read from the camera's stored
30212
+ * `detectionSources` — the one authority; `explicit` is false while the
30213
+ * operator has never picked and the default stands.
30214
+ */
30215
+ getCameraDetectionSource: method(object({ deviceId: number() }), object({
30216
+ source: CameraDetectionSourceSchema,
30217
+ explicit: boolean(),
30218
+ onboard: object({
30219
+ /** The camera has an onboard detector this system can read. */
30220
+ available: boolean(),
30221
+ /** What its detections carry — a camera with no box cannot be a root step. */
30222
+ geometry: _enum([
30223
+ "boxed",
30224
+ "while-streaming",
30225
+ "flag-only",
30226
+ "unknown"
30227
+ ])
30228
+ })
30229
+ })),
30230
+ /**
30231
+ * Pick where this camera's detections come from. Writes `detectionSources`
30232
+ * and arms (or disarms) the vendor's boxed sub-stream that the choice
30233
+ * drives. Refuses `onboard` on a camera with no onboard detector.
30234
+ */
30235
+ setCameraDetectionSource: method(object({
30236
+ deviceId: number(),
30237
+ source: CameraDetectionSourceSchema
30238
+ }), object({ success: literal(true) }), {
30239
+ kind: "mutation",
30240
+ auth: "admin"
30241
+ }),
30204
30242
  /** Read every per-(node,device) override map for a device. Null when device has no overrides. */
30205
30243
  getCameraStepOverrides: method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()),
30206
30244
  /**
@@ -36895,7 +36933,14 @@ var TopologyNodeSchema = object({
36895
36933
  * completed a mutual-TLS handshake, `clear` otherwise. Absent for the hub,
36896
36934
  * for offline rows and when the hub cannot tell.
36897
36935
  */
36898
- meshTransport: _enum(["tls", "clear"]).optional()
36936
+ meshTransport: _enum(["tls", "clear"]).optional(),
36937
+ /**
36938
+ * Whether the hub holds this online AGENT's capability registration (its
36939
+ * `registerNode` manifest). `false` = online in the mesh but not ready: the
36940
+ * hub dropped the registration on a disconnect only it saw and the agent has
36941
+ * not re-sent it. Absent for the hub and offline rows.
36942
+ */
36943
+ capabilitiesRegistered: boolean().optional()
36899
36944
  });
36900
36945
  var CapUsageEdgeSchema = object({
36901
36946
  callerAddonId: string(),
@@ -47143,6 +47188,12 @@ Object.freeze({
47143
47188
  addonId: null,
47144
47189
  access: "view"
47145
47190
  },
47191
+ "pipelineOrchestrator.getCameraDetectionSource": {
47192
+ capName: "pipeline-orchestrator",
47193
+ capScope: "system",
47194
+ addonId: null,
47195
+ access: "view"
47196
+ },
47146
47197
  "pipelineOrchestrator.getCameraMetrics": {
47147
47198
  capName: "pipeline-orchestrator",
47148
47199
  capScope: "system",
@@ -47371,6 +47422,12 @@ Object.freeze({
47371
47422
  addonId: null,
47372
47423
  access: "create"
47373
47424
  },
47425
+ "pipelineOrchestrator.setCameraDetectionSource": {
47426
+ capName: "pipeline-orchestrator",
47427
+ capScope: "system",
47428
+ addonId: null,
47429
+ access: "create"
47430
+ },
47374
47431
  "pipelineOrchestrator.setCameraPipelineForAgent": {
47375
47432
  capName: "pipeline-orchestrator",
47376
47433
  capScope: "system",
@@ -48823,6 +48880,12 @@ Object.freeze({
48823
48880
  addonId: null,
48824
48881
  access: "view"
48825
48882
  },
48883
+ "streamBroker.getLiveViewerCounts": {
48884
+ capName: "stream-broker",
48885
+ capScope: "system",
48886
+ addonId: null,
48887
+ access: "view"
48888
+ },
48826
48889
  "streamBroker.getPreBufferInfo": {
48827
48890
  capName: "stream-broker",
48828
48891
  capScope: "system",
@@ -52996,6 +53059,11 @@ Object.freeze({
52996
53059
  form: "single",
52997
53060
  optional: false
52998
53061
  }],
53062
+ "pipelineOrchestrator.getCameraDetectionSource": [{
53063
+ name: "deviceId",
53064
+ form: "single",
53065
+ optional: false
53066
+ }],
52999
53067
  "pipelineOrchestrator.getCameraMetrics": [{
53000
53068
  name: "deviceId",
53001
53069
  form: "single",
@@ -53056,6 +53124,11 @@ Object.freeze({
53056
53124
  form: "single",
53057
53125
  optional: false
53058
53126
  }],
53127
+ "pipelineOrchestrator.setCameraDetectionSource": [{
53128
+ name: "deviceId",
53129
+ form: "single",
53130
+ optional: false
53131
+ }],
53059
53132
  "pipelineOrchestrator.setCameraPipelineForAgent": [{
53060
53133
  name: "deviceId",
53061
53134
  form: "single",
@@ -65109,6 +65182,86 @@ function selectedDeviceKey(selection) {
65109
65182
  return selection.kind === "selected" ? selection.deviceKey : void 0;
65110
65183
  }
65111
65184
  //#endregion
65185
+ //#region src/camera-detection-source.ts
65186
+ /**
65187
+ * The pick a stored list means. A legacy two-root list is truncated to its
65188
+ * first element — the same rule the schema applies on the attach path
65189
+ * (`DetectionSourcesSchema`), so the UI shows what actually runs. Absent or
65190
+ * unreadable is the default, `pipeline`: a value that cannot be read is not an
65191
+ * empty pick.
65192
+ */
65193
+ function pickFromStored(raw) {
65194
+ if (!Array.isArray(raw)) return {
65195
+ source: "pipeline",
65196
+ explicit: false
65197
+ };
65198
+ const first = raw.find((v) => typeof v === "string");
65199
+ if (first === void 0) return {
65200
+ source: "none",
65201
+ explicit: true
65202
+ };
65203
+ return {
65204
+ source: first === "onboard" ? "onboard" : "pipeline",
65205
+ explicit: true
65206
+ };
65207
+ }
65208
+ /** The list a pick is stored as. */
65209
+ function storedFromPick(source) {
65210
+ return source === "none" ? [] : [source];
65211
+ }
65212
+ /**
65213
+ * What the camera's detections actually CARRY, asked of the cap that knows. A
65214
+ * camera whose firmware ships no bounding box cannot be a root step — there is
65215
+ * nothing to track — and the operator has to read that BEFORE picking.
65216
+ * `unknown` stays unknown: a cap that could not answer is not "flag-only".
65217
+ */
65218
+ async function readGeometry(deps, deviceId) {
65219
+ try {
65220
+ const options = await deps.ctx().api?.nativeObjectDetection.getOptions.query({ deviceId });
65221
+ if (options?.geometry === "boxed" || options?.geometry === "while-streaming" || options?.geometry === "flag-only") return options.geometry;
65222
+ } catch {}
65223
+ return "unknown";
65224
+ }
65225
+ async function readCameraDetectionSource(deps, deviceId) {
65226
+ let raw;
65227
+ try {
65228
+ raw = (await deps.ctx().settings?.readDeviceStore(deviceId))?.["detectionSources"];
65229
+ } catch {}
65230
+ const { source, explicit } = pickFromStored(raw);
65231
+ const available = await deps.deviceHasNativeObjectDetectionCap(deviceId);
65232
+ return {
65233
+ source,
65234
+ explicit,
65235
+ onboard: {
65236
+ available,
65237
+ geometry: available ? await readGeometry(deps, deviceId) : "unknown"
65238
+ }
65239
+ };
65240
+ }
65241
+ /**
65242
+ * Arm (or disarm) the vendor's boxed sub-stream for a camera whose root
65243
+ * detector is its own firmware — and stop paying for it on a camera that just
65244
+ * stopped being one. A failure is logged and swallowed: the setting still
65245
+ * lands, and the sub-stream re-arms on the provider's next login or the
65246
+ * orchestrator's forwarding reconcile.
65247
+ */
65248
+ async function armOnboardChannel(ctx, deviceId, wantsOnboard) {
65249
+ try {
65250
+ await ctx().api?.nativeObjectDetection.setEnabled.mutate({
65251
+ deviceId,
65252
+ enabled: wantsOnboard
65253
+ });
65254
+ } catch (err) {
65255
+ ctx().logger.warn("failed to arm the onboard detection channel", {
65256
+ tags: { deviceId },
65257
+ meta: {
65258
+ wantsOnboard,
65259
+ error: errMsg$2(err)
65260
+ }
65261
+ });
65262
+ }
65263
+ }
65264
+ //#endregion
65112
65265
  //#region src/ingest-owner.ts
65113
65266
  /**
65114
65267
  * The cluster's single camera-source owner + its LAN-reachable host, resolved
@@ -65204,48 +65357,7 @@ var DeviceConfigContributions = class {
65204
65357
  span: 1
65205
65358
  }]
65206
65359
  };
65207
- const hasNativeObjectDetection = await this.deps.deviceHasNativeObjectDetectionCap(input.deviceId);
65208
- const nativeObjectDetectionSections = [];
65209
- if (hasNativeObjectDetection) {
65210
- let currentDetectionSources = ["pipeline"];
65211
- try {
65212
- const raw = (await this.deps.ctx().settings?.readDeviceStore(input.deviceId))?.["detectionSources"];
65213
- if (Array.isArray(raw)) currentDetectionSources = raw.filter((v) => typeof v === "string");
65214
- } catch {}
65215
- let geometry = "unknown";
65216
- try {
65217
- const options = await this.deps.ctx().api?.nativeObjectDetection.getOptions.query({ deviceId: input.deviceId });
65218
- if (options?.geometry === "boxed" || options?.geometry === "while-streaming" || options?.geometry === "flag-only") geometry = options.geometry;
65219
- } catch {}
65220
- const onboardNote = geometry === "boxed" ? "This camera ships a bounding box with each detection, so picking it alone replaces the ML root step: the accelerator is not asked, and the track still gets its best shot, face, plate and embedding." : geometry === "while-streaming" ? "This is a battery camera: its boxes ride whatever stream is already open rather than a feed of their own, so they cost it nothing — and they exist exactly while it is awake, which is when something is in front of it. Between wake-ups it reports nothing, so pick this alone only if you accept that the camera is the only thing deciding when to look." : geometry === "flag-only" ? "This camera ships the class with NO bounding box. It cannot serve as a root step; its onboard AI is worth what it already is, a wake signal with a class." : "This camera has not said whether its detections carry a bounding box. Without one it cannot serve as a root step.";
65221
- nativeObjectDetectionSections.push({
65222
- id: "detection-sources",
65223
- title: "Detection sources",
65224
- tab: "detection-pipeline",
65225
- location: "top-tab",
65226
- order: 8,
65227
- fields: [{
65228
- type: "multiselect",
65229
- key: "detectionSources",
65230
- label: "Root detector",
65231
- description: `Which detector produces this camera's first-level detections. ${onboardNote}`,
65232
- options: [{
65233
- value: "pipeline",
65234
- label: "This node (ML root step on decoded frames)"
65235
- }, {
65236
- value: "onboard",
65237
- label: "Camera onboard AI"
65238
- }],
65239
- default: ["pipeline"],
65240
- value: currentDetectionSources
65241
- }]
65242
- });
65243
- }
65244
- return { sections: [
65245
- ...baseSections,
65246
- zonesSection,
65247
- ...nativeObjectDetectionSections
65248
- ] };
65360
+ return { sections: [...baseSections, zonesSection] };
65249
65361
  }
65250
65362
  async getDeviceLiveContribution(input) {
65251
65363
  const assignment = this.deps.getAssignment(input.deviceId);
@@ -65289,6 +65401,23 @@ var DeviceConfigContributions = class {
65289
65401
  return true;
65290
65402
  }
65291
65403
  }
65404
+ /** Where this camera's detections come from, for the Steps editor's first control. */
65405
+ async getCameraDetectionSource(input) {
65406
+ return readCameraDetectionSource(this.deps, input.deviceId);
65407
+ }
65408
+ /**
65409
+ * Pick where this camera's detections come from. Goes through the same write
65410
+ * as every other detection-wiring field (the device store + the settings
65411
+ * event), and arms the vendor sub-stream the pick drives.
65412
+ */
65413
+ async setCameraDetectionSource(input) {
65414
+ if (input.source === "onboard") {
65415
+ if (!(await readCameraDetectionSource(this.deps, input.deviceId)).onboard.available) throw new Error(`setCameraDetectionSource: device ${String(input.deviceId)} has no onboard detector to use as its root`);
65416
+ }
65417
+ await armOnboardChannel(this.deps.ctx, input.deviceId, input.source === "onboard");
65418
+ await this.writeDeviceOrchestratorSettings(input.deviceId, { detectionSources: storedFromPick(input.source) });
65419
+ return { success: true };
65420
+ }
65292
65421
  async applyDeviceSettingsPatch(input) {
65293
65422
  const sensors = validateCameraSensorsPatch(input.patch);
65294
65423
  if (sensors.kind === "refused") {
@@ -65300,23 +65429,7 @@ var DeviceConfigContributions = class {
65300
65429
  }
65301
65430
  const { pipelinePatch, rest } = this.splitPipelinePatch(input.patch);
65302
65431
  const nextSources = rest["detectionSources"];
65303
- if (Array.isArray(nextSources)) {
65304
- const wantsOnboard = nextSources.includes("onboard");
65305
- try {
65306
- await this.deps.ctx().api?.nativeObjectDetection.setEnabled.mutate({
65307
- deviceId: input.deviceId,
65308
- enabled: wantsOnboard
65309
- });
65310
- } catch (err) {
65311
- this.deps.ctx().logger.warn("failed to arm the onboard detection channel", {
65312
- tags: { deviceId: input.deviceId },
65313
- meta: {
65314
- wantsOnboard,
65315
- error: err instanceof Error ? err.message : String(err)
65316
- }
65317
- });
65318
- }
65319
- }
65432
+ if (Array.isArray(nextSources)) await armOnboardChannel(this.deps.ctx, input.deviceId, nextSources.includes("onboard"));
65320
65433
  const orchestratorRest = sensors.kind === "valid" ? {
65321
65434
  ...rest,
65322
65435
  [CAMERA_SENSORS_SETTINGS_KEY]: sensors.value
@@ -78528,6 +78641,12 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
78528
78641
  async getDeviceLiveContribution(input) {
78529
78642
  return this.deviceConfig.getDeviceLiveContribution(input);
78530
78643
  }
78644
+ async getCameraDetectionSource(input) {
78645
+ return this.deviceConfig.getCameraDetectionSource(input);
78646
+ }
78647
+ async setCameraDetectionSource(input) {
78648
+ return this.deviceConfig.setCameraDetectionSource(input);
78649
+ }
78531
78650
  async applyDeviceSettingsPatch(input) {
78532
78651
  return this.deviceConfig.applyDeviceSettingsPatch(input);
78533
78652
  }