@camstack/types 1.2.44 → 1.2.46

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.
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import type { SubscribeAudioChunksResult, SubscribeFramesInput, SubscribeFramesResult } from '../capabilities/schemas/streaming-shared.js';
2
+ import type { BrokerStatsSchema, BrokerStatusSchema, SubscribeAudioChunksResult, SubscribeFramesInput, SubscribeFramesResult } from '../capabilities/schemas/streaming-shared.js';
3
3
  import type { BrokerConsumerAttribution } from '../capabilities/stream-broker.cap.js';
4
4
  import type { FrameFormat } from '../types/io.js';
5
5
  import type { FrameHandle } from './frame-handle.js';
@@ -161,72 +161,24 @@ export interface AudioSubscribeOptions {
161
161
  */
162
162
  readonly tag?: string;
163
163
  }
164
- export type BrokerStatus = 'idle' | 'connecting' | 'streaming' | 'error' | 'stopped';
165
- export interface BrokerStats {
166
- readonly status: BrokerStatus;
167
- readonly inputFps: number;
168
- readonly decodeFps: number;
169
- readonly encodedSubscribers: number;
170
- readonly decodedSubscribers: number;
171
- readonly uptimeMs: number;
172
- /** Measured bitrate in kbps (averaged over 2s window) */
173
- readonly bitrateKbps: number;
174
- /** Time between last two keyframes in ms (IDR interval) */
175
- readonly idrIntervalMs: number;
176
- /** Detected video codec (h264, h265) */
177
- readonly codec?: string;
178
- /** Total bytes received since broker start */
179
- readonly totalBytes: number;
180
- /** Total encoded packets received since broker start */
181
- readonly packetCount: number;
182
- /** Number of connected RTSP restream clients */
183
- readonly rtspClients: number;
184
- /** Number of connected TCP pipe clients */
185
- readonly pipeClients: number;
186
- /** Pre-buffer configured duration in seconds */
187
- readonly preBufferSec: number;
188
- /** Pre-buffer actual buffered duration in ms */
189
- readonly preBufferMs: number;
190
- /** Pre-buffer packet count */
191
- readonly preBufferPackets: number;
192
- /**
193
- * Moleculer node id of the decoder provider currently servicing this
194
- * stream's decoded subscribers. `null` until the deferred decoder is
195
- * created (no decoded clients yet, or codec not detected).
196
- */
197
- readonly decoderNodeId: string | null;
198
- /**
199
- * Detected audio track parameters from the RTSP DESCRIBE / SDP. Null
200
- * when the stream has no audio track or the broker is still in cold
201
- * start. `supported` reflects whether the local native + ffmpeg-based
202
- * decoder pipeline can produce PCM chunks for downstream consumers
203
- * (audio-analyzer). When `false`, the codec is detected but skipped.
204
- */
205
- readonly audio?: {
206
- readonly codec: string;
207
- readonly sampleRate: number;
208
- readonly channels: number;
209
- readonly supported: boolean;
210
- } | null;
211
- /**
212
- * BROKER-SIDE AUDIO MUTE ([D83](../../../../docs/decisions/adr-0083.md)).
213
- * `true` = this broker is deliberately distributing none of the device's
214
- * audio, live or recorded. It is what tells a silent camera apart from a
215
- * broken one on the stream panel: a broker holding an `audio` descriptor
216
- * with `audioMuted: true` is doing exactly what it was asked.
217
- *
218
- * `audioMutedDropped` counts the audio units the mute threw away since the
219
- * current dial — the proof the mute is on the packet path and not merely
220
- * persisted.
221
- *
222
- * NOTE: this interface is the hand-written twin of `BrokerStatsSchema` in
223
- * `capabilities/schemas/streaming-shared.ts`. They are not generated from
224
- * each other; a field added to one and not the other compiles and then
225
- * silently disappears on the wire.
226
- */
227
- readonly audioMuted?: boolean;
228
- readonly audioMutedDropped?: number;
229
- }
164
+ /**
165
+ * Broker lifecycle state. Inferred from `BrokerStatusSchema` — the enum the
166
+ * wire actually validates against.
167
+ */
168
+ export type BrokerStatus = z.infer<typeof BrokerStatusSchema>;
169
+ /**
170
+ * Live broker telemetry: the payload of `streamBroker.getBrokerStats` and of
171
+ * the stats push the admin-UI panel subscribes to.
172
+ *
173
+ * Inferred from `BrokerStatsSchema` in
174
+ * `capabilities/schemas/streaming-shared.ts`, which is the schema the cap
175
+ * method validates its output against — so the schema IS the type. This was a
176
+ * hand-written twin until 2026-08-08: two shapes, neither generated from the
177
+ * other, and a field added to one and not the other compiled fine and then
178
+ * silently disappeared on the wire. Every field is documented on the schema;
179
+ * do not restate it here, and never re-introduce a second declaration.
180
+ */
181
+ export type BrokerStats = z.infer<typeof BrokerStatsSchema>;
230
182
  export interface IStreamBroker {
231
183
  readonly deviceId: string;
232
184
  readonly status: BrokerStatus;
@@ -3207,6 +3207,17 @@ function createDeviceProxy(api, binding, opts) {
3207
3207
  listOpsLog: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listOpsLog", "query", input),
3208
3208
  getTrainingExportSummary: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getTrainingExportSummary", "query", input),
3209
3209
  getTrainingExportUrl: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getTrainingExportUrl", "query", input),
3210
+ listRetrainStaging: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRetrainStaging", "query", input),
3211
+ listRetrainFrames: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRetrainFrames", "query", input),
3212
+ selectRetrainFrames: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "selectRetrainFrames", "mutation", input),
3213
+ deselectRetrainFrame: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "deselectRetrainFrame", "mutation", input),
3214
+ getRetrainFrameImage: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getRetrainFrameImage", "query", input),
3215
+ proposeRetrainAnnotations: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "proposeRetrainAnnotations", "mutation", input),
3216
+ listRetrainAnnotations: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRetrainAnnotations", "query", input),
3217
+ saveRetrainAnnotations: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "saveRetrainAnnotations", "mutation", input),
3218
+ completeRetrainTrack: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "completeRetrainTrack", "mutation", input),
3219
+ restageRetrainTrack: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "restageRetrainTrack", "mutation", input),
3220
+ getRetrainExportUrl: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getRetrainExportUrl", "query", input),
3210
3221
  getEventMedia: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getEventMedia", "query", input),
3211
3222
  getTrackMedia: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getTrackMedia", "query", input),
3212
3223
  listTrackMedia: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listTrackMedia", "query", input),
@@ -3489,6 +3500,7 @@ function createDeviceProxy(api, binding, opts) {
3489
3500
  assignProfile: (input) => dispatchSystem("streamBroker", "assignProfile", "mutation", input),
3490
3501
  unassignProfile: (input) => dispatchSystem("streamBroker", "unassignProfile", "mutation", input),
3491
3502
  renderPreBufferClip: (input) => dispatchSystem("streamBroker", "renderPreBufferClip", "mutation", input),
3503
+ produceEventMedia: (input) => dispatchSystem("streamBroker", "produceEventMedia", "mutation", input),
3492
3504
  restartProfile: (input) => dispatchSystem("streamBroker", "restartProfile", "mutation", input),
3493
3505
  getDeviceAudioMute: (input) => dispatchSystem("streamBroker", "getDeviceAudioMute", "query", input),
3494
3506
  setDeviceAudioMute: (input) => dispatchSystem("streamBroker", "setDeviceAudioMute", "mutation", input),
@@ -3207,6 +3207,17 @@ function createDeviceProxy(api, binding, opts) {
3207
3207
  listOpsLog: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listOpsLog", "query", input),
3208
3208
  getTrainingExportSummary: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getTrainingExportSummary", "query", input),
3209
3209
  getTrainingExportUrl: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getTrainingExportUrl", "query", input),
3210
+ listRetrainStaging: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRetrainStaging", "query", input),
3211
+ listRetrainFrames: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRetrainFrames", "query", input),
3212
+ selectRetrainFrames: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "selectRetrainFrames", "mutation", input),
3213
+ deselectRetrainFrame: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "deselectRetrainFrame", "mutation", input),
3214
+ getRetrainFrameImage: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getRetrainFrameImage", "query", input),
3215
+ proposeRetrainAnnotations: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "proposeRetrainAnnotations", "mutation", input),
3216
+ listRetrainAnnotations: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRetrainAnnotations", "query", input),
3217
+ saveRetrainAnnotations: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "saveRetrainAnnotations", "mutation", input),
3218
+ completeRetrainTrack: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "completeRetrainTrack", "mutation", input),
3219
+ restageRetrainTrack: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "restageRetrainTrack", "mutation", input),
3220
+ getRetrainExportUrl: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getRetrainExportUrl", "query", input),
3210
3221
  getEventMedia: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getEventMedia", "query", input),
3211
3222
  getTrackMedia: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getTrackMedia", "query", input),
3212
3223
  listTrackMedia: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listTrackMedia", "query", input),
@@ -3489,6 +3500,7 @@ function createDeviceProxy(api, binding, opts) {
3489
3500
  assignProfile: (input) => dispatchSystem("streamBroker", "assignProfile", "mutation", input),
3490
3501
  unassignProfile: (input) => dispatchSystem("streamBroker", "unassignProfile", "mutation", input),
3491
3502
  renderPreBufferClip: (input) => dispatchSystem("streamBroker", "renderPreBufferClip", "mutation", input),
3503
+ produceEventMedia: (input) => dispatchSystem("streamBroker", "produceEventMedia", "mutation", input),
3492
3504
  restartProfile: (input) => dispatchSystem("streamBroker", "restartProfile", "mutation", input),
3493
3505
  getDeviceAudioMute: (input) => dispatchSystem("streamBroker", "getDeviceAudioMute", "query", input),
3494
3506
  setDeviceAudioMute: (input) => dispatchSystem("streamBroker", "setDeviceAudioMute", "mutation", input),
@@ -70,6 +70,24 @@ export interface ScoredLabel {
70
70
  * that carries it.
71
71
  */
72
72
  readonly detectionId?: string;
73
+ /**
74
+ * WHICH label slot this text may occupy on a track / ObjectEvent, copied
75
+ * VERBATIM from the producing step's `StepDefinition.labelTier` (roadmap
76
+ * 4g). 1 = sub-class (`dog`), 2 = instance (`Turdus migratorius`, `Alice`,
77
+ * a plate read).
78
+ *
79
+ * Absent means the producing step declares no tier — an internal marker
80
+ * (`embedding:512d`), or a step that was never given a declaration. The
81
+ * persistence write rule REFUSES an undeclared label rather than inferring
82
+ * a tier from the text or the step name, and says so in the log. Inheriting
83
+ * a label onto a parent copies the tier unchanged: the tier belongs to the
84
+ * step that decided the text, not to the entry that carries it.
85
+ */
86
+ readonly tier?: 1 | 2;
87
+ /** Step that decided this text — the tier's attribution. */
88
+ readonly stepId?: string;
89
+ /** Model that decided this text — the tier's attribution. */
90
+ readonly modelId?: string;
73
91
  }
74
92
  /** What kind of entry a detection is at the root of `detections[]`. */
75
93
  export type DetectionKind = 'first-level' | 'detail' | 'audio';
@@ -110,6 +128,19 @@ export interface DetectionDebug {
110
128
  * mapped to `macroClass: 'animal'`).
111
129
  */
112
130
  readonly originalClass?: string;
131
+ /**
132
+ * The label tier {@link originalClass} may occupy, from the ROOT detector
133
+ * step's `StepDefinition.labelTier` (roadmap 4g). Ships in the same
134
+ * `verbosity: 'full'` bag as the value it qualifies, so it costs nothing
135
+ * where `originalClass` costs nothing.
136
+ *
137
+ * Without it the raw class is a label with no declared tier and the write
138
+ * rule refuses it — which is the correct outcome, because outside
139
+ * `verbosity: 'full'` the FrameProcessor substitutes `det.macroClass` for a
140
+ * missing `originalClass` and a tier guessed here would put a MACRO class in
141
+ * a label slot. That is the exact regression the 2026-08-07 rule refuses.
142
+ */
143
+ readonly originalClassTier?: 1 | 2;
113
144
  /**
114
145
  * Full top-N ranked alternatives per source (classifier / recognizer).
115
146
  * The winner of each list already appears in `detection.labels[]` —
@@ -42,6 +42,27 @@ export interface StepDefinition {
42
42
  readonly inputClasses: readonly string[] | null;
43
43
  /** Classes this step outputs (e.g., ['person','vehicle','animal'] for YOLO) */
44
44
  readonly outputClasses: readonly string[];
45
+ /**
46
+ * WHICH label tier this step's answer occupies on a track / ObjectEvent
47
+ * (roadmap 4g). **Declared here and nowhere else** — a consumer never infers
48
+ * a tier from `outputClasses`, from the step id, or from the shape of the
49
+ * text. A step that produces a label and declares no tier has its answer
50
+ * REFUSED and logged, because a guess here is exactly how a species ends up
51
+ * in the coarse slot and blocks the sub-class that should have gone there.
52
+ *
53
+ * - `1` — a SUB-CLASS, finer than the macro class but still a taxonomy
54
+ * token: `animal-classifier` (`animal-type`), `vehicle-classifier`
55
+ * (`vehicle-type`), and `object-detection` itself (its raw class, when
56
+ * finer than the macro it maps to — `dog` under `animal`).
57
+ * - `2` — an INSTANCE, the finest thing sayable about this subject:
58
+ * `bird-classifier` (`species`), `face-embedding` (`identity`),
59
+ * `plate-ocr` (`plate-text`).
60
+ *
61
+ * Absent on a step that produces no label at all (a detector whose classes
62
+ * ARE macro classes, an embedder, a segmenter). Absence is not tier 0 — it
63
+ * means "this step never fills a label slot".
64
+ */
65
+ readonly labelTier?: 1 | 2;
45
66
  /** Available models for this step */
46
67
  readonly models: readonly ModelCatalogEntry[];
47
68
  /** Default model when no user preference is set */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/types",
3
- "version": "1.2.44",
3
+ "version": "1.2.46",
4
4
  "description": "Shared types, interfaces, and model catalogs for the CamStack detection ecosystem",
5
5
  "keywords": [
6
6
  "camstack",