@camstack/types 1.2.42 → 1.2.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/addon.js +8 -2
  2. package/dist/addon.mjs +8 -2
  3. package/dist/cap-call-context.d.ts +26 -0
  4. package/dist/capabilities/index.d.ts +8 -5
  5. package/dist/capabilities/osd-manager.cap.d.ts +900 -0
  6. package/dist/capabilities/pipeline-analytics.cap.d.ts +171 -4
  7. package/dist/capabilities/pipeline-orchestrator.cap.d.ts +36 -0
  8. package/dist/capabilities/privacy-mask.cap.d.ts +69 -9
  9. package/dist/capabilities/recording.cap.d.ts +27 -0
  10. package/dist/capabilities/schemas/streaming-shared.d.ts +2 -0
  11. package/dist/capabilities/server-management.cap.d.ts +3 -3
  12. package/dist/capabilities/snapshot.cap.d.ts +1 -1
  13. package/dist/capabilities/stream-broker.cap.d.ts +36 -0
  14. package/dist/capabilities/stream-params.cap.d.ts +8 -4
  15. package/dist/device/device-profile.d.ts +12 -4
  16. package/dist/device/system-mirror.d.ts +11 -0
  17. package/dist/ffmpeg/encode-defaults.d.ts +18 -0
  18. package/dist/ffmpeg/fmp4-box-splitter.d.ts +113 -0
  19. package/dist/ffmpeg/fmp4-fragment-child.d.ts +85 -0
  20. package/dist/ffmpeg/fmp4-fragment-plane.d.ts +142 -0
  21. package/dist/ffmpeg/invocation.d.ts +102 -2
  22. package/dist/ffmpeg/sharing-key.d.ts +54 -2
  23. package/dist/fmp4-box-splitter-B53u9-Nu.mjs +615 -0
  24. package/dist/fmp4-box-splitter-BkWH7O3L.js +686 -0
  25. package/dist/generated/addon-api.d.ts +117 -0
  26. package/dist/generated/cap-input-defaults.d.ts +1 -1
  27. package/dist/generated/capability-router-map.d.ts +5 -2
  28. package/dist/generated/device-proxy.d.ts +4 -2
  29. package/dist/generated/method-access-map.d.ts +1 -1
  30. package/dist/generated/system-proxy.d.ts +2 -0
  31. package/dist/index.d.ts +4 -0
  32. package/dist/index.js +1264 -394
  33. package/dist/index.mjs +1217 -385
  34. package/dist/interfaces/camera-switches.d.ts +211 -5
  35. package/dist/interfaces/inference-engine.d.ts +24 -3
  36. package/dist/interfaces/stream-broker.d.ts +18 -0
  37. package/dist/node.d.ts +4 -0
  38. package/dist/node.js +509 -3
  39. package/dist/node.mjs +507 -3
  40. package/dist/notification/schedule.d.ts +20 -0
  41. package/dist/pipeline/native-lease.d.ts +150 -0
  42. package/dist/{sleep-BmNKsY7v.mjs → sleep-cC4Fuup8.mjs} +59 -3
  43. package/dist/{sleep-Cvi1JxZp.js → sleep-eiC10_cX.js} +64 -2
  44. package/dist/types/pipeline-step.d.ts +1 -1
  45. package/dist/utils/addon-id.d.ts +30 -0
  46. package/package.json +1 -1
  47. package/dist/canonical-hash-7nfBbEqR.mjs +0 -35
  48. package/dist/canonical-hash-BcZHRHIx.js +0 -40
@@ -5,7 +5,7 @@
5
5
  * ## This file adds no state
6
6
  *
7
7
  * Every switch here is a VIEW onto an authority that already existed
8
- * ([D61](../../../../docs/decisions/adr-0062.md)). The whole point of the
8
+ * ([D62](../../../../docs/decisions/adr-0062.md)). The whole point of the
9
9
  * group is that there is exactly one place each function is turned off, and
10
10
  * the group routes to it:
11
11
  *
@@ -16,6 +16,53 @@
16
16
  * | `audio-analysis` | `deviceManager.setWrapperActive('audio-analysis')` | `AudioSubscriptionController.subscribeAudioStream` returns `null` before opening the stream |
17
17
  * | `recording` | `recording.setDeviceConfig` → `RecordingConfig.enabled` | `band-decision.shouldRecord` returns false; the controller detaches the device |
18
18
  * | `notifications` | `notificationRules.setDeviceMuted` | `NotificationCenter.evaluateAndEnqueue` returns before any rule is evaluated |
19
+ * | `privacy-mask` | `privacyMask.setMask({ enabled })` → the CAMERA | the camera blanks the masked regions itself; every stream and recording carries the black boxes |
20
+ * | `device-audio` | `privacyMask.setAudioEnabled` → the CAMERA | the camera stops encoding an audio track at all; every consumer sees silent video |
21
+ * | `broker-audio` | `streamBroker.setDeviceAudioMute` → `DeviceOverride.audioMuted` | `StreamBroker.setAudioMuted` drops the audio plane at the source: no `type:'audio'` packet leaves `fanOutEncoded`, no RTP reaches the restreamer, and the restreamer serves the video-only SDP |
22
+ *
23
+ * ## `device-audio` and `broker-audio` are two functions, not two knobs
24
+ *
25
+ * They look adjacent and they are not the same control ([D83](../../../../docs/decisions/adr-0083.md)):
26
+ * `device-audio` writes the CAMERA, so it is hardware privacy — the microphone
27
+ * genuinely stops, it survives CamStack entirely, and it costs a multi-second
28
+ * encoder restart on every flip. `broker-audio` writes THIS server, so it is
29
+ * instant, vendor-independent and reversible without touching the camera, and
30
+ * a camera that ignores or lacks the ISAPI/Reolink control is still silenced.
31
+ * D62 forbids a second switch that *disagrees* with the first; these two
32
+ * cannot disagree, because neither reads the other's store — the camera holds
33
+ * one, the broker holds the other, and each reports its own fact.
34
+ *
35
+ * ## The two switches whose authority is not on this server
36
+ *
37
+ * `privacy-mask` and `device-audio` write the CAMERA. That is not a loophole
38
+ * in "the group stores nothing" — it is the purest form of it: the camera
39
+ * holds the fact, every read is a read-through, and there is no server-side
40
+ * copy that could drift. Their availability therefore cannot come from
41
+ * `listBindableCapsForDeviceType` (a device-NATIVE cap carries no wrappers and
42
+ * is filtered out there); it comes from the cap's own camera-probed
43
+ * `privacyMask.getOptions()`, which is strictly more honest — it answers for
44
+ * THIS camera rather than for the device type
45
+ * ([D74](../../../../docs/decisions/adr-0074.md)).
46
+ *
47
+ * ## `privacy-mask` is the one row whose ON is not "the function is working"
48
+ *
49
+ * Every other switch means *this camera's function is doing its job*, so
50
+ * `enabled: false` is a thing an operator took away. `privacy-mask` means **the
51
+ * MASK is active** — `enabled: true` is video deliberately obscured. The
52
+ * polarity is not a choice made here: `addon-export-hap`'s privacy `Switch`
53
+ * (`builders/privacy-switch.ts`) already mirrors `patch.enabled` verbatim, and
54
+ * a HomeKit toggle that disagreed with the app's toggle for the same camera is
55
+ * worse than either surface not having one.
56
+ *
57
+ * Two consequences follow and both are load-bearing:
58
+ *
59
+ * - **It never counts as `switchedOff`.** `countsAsSwitchedOff` is `false` for
60
+ * exactly this row. With the polarity above, every camera that has NOT drawn
61
+ * a privacy mask would otherwise report `switchedOff: ['privacy-mask']` — the
62
+ * normal, healthy state of most cameras rendered as an operator disablement.
63
+ * - **Its cost line names BOTH directions.** `costWhenOff` is rendered
64
+ * unconditionally by both clients, so for this row it has to read correctly
65
+ * whichever way the switch is sitting.
19
66
  *
20
67
  * The wrapper-binding pair is not a new idea: `legacy-migrations.ts` already
21
68
  * migrated the legacy `audioEnabled` / `pipelineEnabled` /
@@ -35,20 +82,39 @@
35
82
  */
36
83
  import { z } from 'zod';
37
84
  /**
38
- * The five functions the operator named (2026-08-05). Deliberately NOT one id
39
- * per pipeline step: face recognition and plate/LPR are per-step toggles on
85
+ * The functions the operator named — five on 2026-08-05, plus the camera's own
86
+ * microphone on 2026-08-07. Deliberately NOT one id per pipeline step: face
87
+ * recognition and plate/LPR are per-step toggles on
40
88
  * `pipelineOrchestrator.setCameraStepToggle` and belong in the pipeline
41
- * editor, not in a five-button safety group.
89
+ * editor, not in a safety group.
42
90
  */
43
91
  export declare const CameraSwitchIdSchema: z.ZodEnum<{
92
+ "privacy-mask": "privacy-mask";
44
93
  "audio-analysis": "audio-analysis";
45
94
  recording: "recording";
46
95
  "stream-broker": "stream-broker";
47
96
  notifications: "notifications";
48
97
  "object-detection": "object-detection";
98
+ "device-audio": "device-audio";
99
+ "broker-audio": "broker-audio";
49
100
  }>;
50
101
  export type CameraSwitchId = z.infer<typeof CameraSwitchIdSchema>;
51
- /** Stable render order — broadest blast radius first. */
102
+ /**
103
+ * Stable render order — broadest blast radius first, and a source before the
104
+ * thing that consumes it. `device-audio` sits ABOVE `audio-analysis` because
105
+ * turning the microphone off leaves the analyzer with nothing to analyse; the
106
+ * reverse is not true.
107
+ *
108
+ * `privacy-mask` sits directly ABOVE `device-audio` because they are literal
109
+ * siblings — one cap, one device plane, video then audio — and NOT above
110
+ * `object-detection` despite feeding it: a mask blanks REGIONS, so its blast
111
+ * radius is partial, and the "broadest first" rule does not rank a partial
112
+ * control above a whole-function one.
113
+ *
114
+ * `broker-audio` sits directly BELOW `device-audio` by the same source-first
115
+ * rule: the camera's microphone feeds the broker, so silencing the camera
116
+ * leaves the broker's mute with nothing to suppress; the reverse is not true.
117
+ */
52
118
  export declare const CAMERA_SWITCH_ORDER: readonly CameraSwitchId[];
53
119
  /**
54
120
  * WHERE the switch's state actually lives. A discriminated union rather than a
@@ -65,6 +131,14 @@ export declare const CameraSwitchAuthoritySchema: z.ZodDiscriminatedUnion<[z.Zod
65
131
  kind: z.ZodLiteral<"recording-config">;
66
132
  }, z.core.$strip>, z.ZodObject<{
67
133
  kind: z.ZodLiteral<"notification-mute">;
134
+ }, z.core.$strip>, z.ZodObject<{
135
+ kind: z.ZodLiteral<"camera-audio">;
136
+ capName: z.ZodString;
137
+ }, z.core.$strip>, z.ZodObject<{
138
+ kind: z.ZodLiteral<"camera-mask">;
139
+ capName: z.ZodString;
140
+ }, z.core.$strip>, z.ZodObject<{
141
+ kind: z.ZodLiteral<"broker-audio-mute">;
68
142
  }, z.core.$strip>], "kind">;
69
143
  export type CameraSwitchAuthority = z.infer<typeof CameraSwitchAuthoritySchema>;
70
144
  /**
@@ -75,6 +149,7 @@ export type CameraSwitchAuthority = z.infer<typeof CameraSwitchAuthoritySchema>;
75
149
  export declare const CameraSwitchUnavailableReasonSchema: z.ZodEnum<{
76
150
  "no-provider": "no-provider";
77
151
  "source-unreachable": "source-unreachable";
152
+ "not-configured": "not-configured";
78
153
  }>;
79
154
  export type CameraSwitchUnavailableReason = z.infer<typeof CameraSwitchUnavailableReasonSchema>;
80
155
  /**
@@ -87,11 +162,14 @@ export type CameraSwitchUnavailableReason = z.infer<typeof CameraSwitchUnavailab
87
162
  */
88
163
  export declare const CameraSwitchSchema: z.ZodObject<{
89
164
  id: z.ZodEnum<{
165
+ "privacy-mask": "privacy-mask";
90
166
  "audio-analysis": "audio-analysis";
91
167
  recording: "recording";
92
168
  "stream-broker": "stream-broker";
93
169
  notifications: "notifications";
94
170
  "object-detection": "object-detection";
171
+ "device-audio": "device-audio";
172
+ "broker-audio": "broker-audio";
95
173
  }>;
96
174
  label: z.ZodString;
97
175
  costWhenOff: z.ZodString;
@@ -99,6 +177,7 @@ export declare const CameraSwitchSchema: z.ZodObject<{
99
177
  unavailableReason: z.ZodOptional<z.ZodEnum<{
100
178
  "no-provider": "no-provider";
101
179
  "source-unreachable": "source-unreachable";
180
+ "not-configured": "not-configured";
102
181
  }>>;
103
182
  enabled: z.ZodBoolean;
104
183
  authority: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -110,6 +189,14 @@ export declare const CameraSwitchSchema: z.ZodObject<{
110
189
  kind: z.ZodLiteral<"recording-config">;
111
190
  }, z.core.$strip>, z.ZodObject<{
112
191
  kind: z.ZodLiteral<"notification-mute">;
192
+ }, z.core.$strip>, z.ZodObject<{
193
+ kind: z.ZodLiteral<"camera-audio">;
194
+ capName: z.ZodString;
195
+ }, z.core.$strip>, z.ZodObject<{
196
+ kind: z.ZodLiteral<"camera-mask">;
197
+ capName: z.ZodString;
198
+ }, z.core.$strip>, z.ZodObject<{
199
+ kind: z.ZodLiteral<"broker-audio-mute">;
113
200
  }, z.core.$strip>], "kind">;
114
201
  }, z.core.$strip>;
115
202
  export type CameraSwitch = z.infer<typeof CameraSwitchSchema>;
@@ -118,11 +205,14 @@ export declare const CameraSwitchGroupSchema: z.ZodObject<{
118
205
  deviceId: z.ZodNumber;
119
206
  switches: z.ZodReadonly<z.ZodArray<z.ZodObject<{
120
207
  id: z.ZodEnum<{
208
+ "privacy-mask": "privacy-mask";
121
209
  "audio-analysis": "audio-analysis";
122
210
  recording: "recording";
123
211
  "stream-broker": "stream-broker";
124
212
  notifications: "notifications";
125
213
  "object-detection": "object-detection";
214
+ "device-audio": "device-audio";
215
+ "broker-audio": "broker-audio";
126
216
  }>;
127
217
  label: z.ZodString;
128
218
  costWhenOff: z.ZodString;
@@ -130,6 +220,7 @@ export declare const CameraSwitchGroupSchema: z.ZodObject<{
130
220
  unavailableReason: z.ZodOptional<z.ZodEnum<{
131
221
  "no-provider": "no-provider";
132
222
  "source-unreachable": "source-unreachable";
223
+ "not-configured": "not-configured";
133
224
  }>>;
134
225
  enabled: z.ZodBoolean;
135
226
  authority: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -141,6 +232,14 @@ export declare const CameraSwitchGroupSchema: z.ZodObject<{
141
232
  kind: z.ZodLiteral<"recording-config">;
142
233
  }, z.core.$strip>, z.ZodObject<{
143
234
  kind: z.ZodLiteral<"notification-mute">;
235
+ }, z.core.$strip>, z.ZodObject<{
236
+ kind: z.ZodLiteral<"camera-audio">;
237
+ capName: z.ZodString;
238
+ }, z.core.$strip>, z.ZodObject<{
239
+ kind: z.ZodLiteral<"camera-mask">;
240
+ capName: z.ZodString;
241
+ }, z.core.$strip>, z.ZodObject<{
242
+ kind: z.ZodLiteral<"broker-audio-mute">;
144
243
  }, z.core.$strip>], "kind">;
145
244
  }, z.core.$strip>>>;
146
245
  fetchedAt: z.ZodNumber;
@@ -154,12 +253,32 @@ export type CameraSwitchGroup = z.infer<typeof CameraSwitchGroupSchema>;
154
253
  */
155
254
  export declare const DETECTION_PIPELINE_CAP_NAME = "detection-pipeline";
156
255
  export declare const AUDIO_ANALYSIS_CAP_NAME = "audio-analysis";
256
+ /**
257
+ * The device-NATIVE cap that owns what the camera does not capture — masked
258
+ * video regions and, since 2026-08-07, the microphone. Named here because the
259
+ * `camera-audio` authority, the orchestrator's gather and the fake harness all
260
+ * have to agree on it.
261
+ */
262
+ export declare const PRIVACY_MASK_CAP_NAME = "privacy-mask";
157
263
  /** Static half of a switch: everything that does not depend on a device. */
158
264
  export interface CameraSwitchDescriptor {
159
265
  readonly id: CameraSwitchId;
160
266
  readonly label: string;
161
267
  readonly costWhenOff: string;
162
268
  readonly authority: CameraSwitchAuthority;
269
+ /**
270
+ * May `enabled: false` on this row appear in {@link switchedOffIds}?
271
+ *
272
+ * `true` for every switch that means "this camera's function is doing its
273
+ * job", where OFF is something a person took away and a status surface must
274
+ * render as disabled rather than broken.
275
+ *
276
+ * `false` for `privacy-mask` alone, and only because its polarity is
277
+ * inverted: OFF there means the mask is not obscuring anything, which is the
278
+ * ordinary state of nearly every camera. Reporting it would put a
279
+ * `switchedOff` badge on healthy cameras and drown the badge that matters.
280
+ */
281
+ readonly countsAsSwitchedOff: boolean;
163
282
  }
164
283
  /**
165
284
  * THE catalog. One entry per switch; the cost lines are the operator-facing
@@ -195,6 +314,87 @@ export interface CameraSwitchDerivationInput {
195
314
  readonly recordingEnabled: boolean | null;
196
315
  /** `notificationRules` per-camera mute; `null` when the cap did not answer. */
197
316
  readonly notificationsMuted: boolean | null;
317
+ /**
318
+ * The camera's own microphone, read through the `privacy-mask` native cap.
319
+ * `null` = the cap is bound to this camera but did not answer.
320
+ *
321
+ * A camera with no `privacy-mask` provider at all is `{ supported: false }`,
322
+ * not `null` — "this camera has no such control" and "we could not read it"
323
+ * are different answers and the operator is shown different copy for each.
324
+ */
325
+ readonly deviceAudio: DeviceAudioSwitchState | null;
326
+ /**
327
+ * The camera's own VIDEO privacy mask, read through the same `privacy-mask`
328
+ * native cap and the same pair of round trips as {@link deviceAudio} — one
329
+ * `getOptions` + one `getStatus` answer both, so the second switch is free.
330
+ *
331
+ * `null` = the cap is bound to this camera but did not answer.
332
+ */
333
+ readonly privacyMask: PrivacyMaskSwitchState | null;
334
+ /**
335
+ * The BROKER's audio-plane policy for this camera, read from the
336
+ * stream-broker on the device's source-owner node. `null` = the broker did
337
+ * not answer, which renders no control rather than a control defaulted to
338
+ * "audio flows".
339
+ */
340
+ readonly brokerAudio: BrokerAudioSwitchState | null;
341
+ }
342
+ /** What the stream-broker reported about its audio plane for one camera. */
343
+ export interface BrokerAudioSwitchState {
344
+ /**
345
+ * `DeviceOverride.audioMuted` — the broker's own persisted policy. `true`
346
+ * means the broker drops this camera's audio on every plane it serves.
347
+ *
348
+ * There is no `supported` companion, deliberately. Muting a camera that is
349
+ * currently silent is not a dead control: the policy governs what happens
350
+ * when sound DOES appear (a camera unmuted at the device, a stream that
351
+ * only carries audio at night), so it is meaningful to set in advance.
352
+ * That is the opposite of the privacy mask with zero zones, where flipping
353
+ * the master enable is provably a no-op until something else changes.
354
+ */
355
+ readonly muted: boolean;
356
+ }
357
+ /** What the camera-probed audio switch reported for one camera. */
358
+ export interface DeviceAudioSwitchState {
359
+ /**
360
+ * `privacyMask.getOptions().supportsAudioMute` — camera-probed, never a
361
+ * device-type guess. A camera that does not expose the control renders no
362
+ * switch rather than a toggle that silently does nothing.
363
+ */
364
+ readonly supported: boolean;
365
+ /**
366
+ * `privacyMask.getStatus().audioEnabled` — the camera's current answer.
367
+ * `null` when unsupported, or when supported but unreadable; the second
368
+ * case yields `source-unreachable`, never a control defaulted to "on".
369
+ */
370
+ readonly enabled: boolean | null;
371
+ }
372
+ /** What the camera-probed VIDEO privacy mask reported for one camera. */
373
+ export interface PrivacyMaskSwitchState {
374
+ /**
375
+ * Can this camera store privacy zones at all? Derived from the probed
376
+ * `getOptions()`: `maxRegions > 0` AND at least one supported shape kind.
377
+ * Reolink answers `maxNum: 0` / `supportedShapes: []` honestly on models
378
+ * that cannot, and that must render no control rather than a toggle whose
379
+ * write the camera discards.
380
+ */
381
+ readonly supported: boolean;
382
+ /**
383
+ * How many zones are actually drawn on the camera right now
384
+ * (`getStatus().regions.length`). `null` = supported, but the status could
385
+ * not be read.
386
+ *
387
+ * **Zero is not "off", it is "nothing to switch".** Toggling the master
388
+ * enable with no zones changes not one pixel — the dead control D62 exists
389
+ * to remove — so it resolves to `not-configured`, which tells the operator
390
+ * to go and draw one instead of leaving them pressing a button.
391
+ */
392
+ readonly configuredRegions: number | null;
393
+ /**
394
+ * `getStatus().enabled` — the camera's master mask flag, `true` when the
395
+ * zones are being blanked. `null` when unreadable; never defaulted.
396
+ */
397
+ readonly enabled: boolean | null;
198
398
  }
199
399
  /**
200
400
  * Pure derivation of the whole group. No I/O — the orchestrator gathers, this
@@ -213,5 +413,11 @@ export declare function deriveCameraSwitches(input: CameraSwitchDerivationInput)
213
413
  * `switchedOff: ['object-detection']` was turned off; the same camera with an
214
414
  * empty list is broken. Unavailable switches never appear — a function nobody
215
415
  * provides was not switched off by anyone.
416
+ *
417
+ * `privacy-mask` never appears either, whichever way it is sitting, because its
418
+ * ON means "the mask is active" rather than "the function works"
419
+ * ({@link CameraSwitchDescriptor.countsAsSwitchedOff}). Without that filter the
420
+ * ordinary state of every camera nobody has masked would carry a
421
+ * "switched off" badge, and the badge that matters would be lost in it.
216
422
  */
217
423
  export declare function switchedOffIds(switches: readonly CameraSwitch[]): readonly CameraSwitchId[];
@@ -16,16 +16,36 @@ import type { RawFrameFormat } from '../types/io.js';
16
16
  * raw buffer to JPEG internally rather than throwing — `infer()` must
17
17
  * always succeed for either kind.
18
18
  */
19
- export type InferenceInput = {
19
+ /**
20
+ * Fields every `InferenceInput` variant carries regardless of pixel transport.
21
+ */
22
+ interface InferenceInputCommon {
23
+ /**
24
+ * The camera this frame belongs to — **diagnostic only**. It changes no
25
+ * dispatch decision, no deadline and no shed rule; it exists so an inference
26
+ * failure inside a SHARED pool can name the camera that paid for it.
27
+ *
28
+ * A `SharedInferencePool` serves every camera on its
29
+ * `(node, runtime, device)`, so its `inference request timed out` and
30
+ * `worker saturated` lines could describe the pool and nothing else — and
31
+ * "why is 617 worse than 615?" is the question those lines always get asked.
32
+ *
33
+ * Omitted by callers with no camera (commands, model loads, the benchmark);
34
+ * the failure line then carries no `deviceId` tag rather than a fabricated
35
+ * one.
36
+ */
37
+ readonly deviceId?: number;
38
+ }
39
+ export type InferenceInput = ({
20
40
  readonly kind: 'jpeg';
21
41
  readonly data: Buffer;
22
- } | {
42
+ } & InferenceInputCommon) | ({
23
43
  readonly kind: 'raw';
24
44
  readonly data: Buffer;
25
45
  readonly width: number;
26
46
  readonly height: number;
27
47
  readonly format: RawFrameFormat;
28
- };
48
+ } & InferenceInputCommon);
29
49
  export interface IInferenceEngine {
30
50
  readonly runtime: DetectionRuntime;
31
51
  readonly device: DetectionDevice;
@@ -34,3 +54,4 @@ export interface IInferenceEngine {
34
54
  run?(input: Float32Array, inputShape: readonly number[]): Promise<Float32Array>;
35
55
  dispose(): Promise<void>;
36
56
  }
57
+ export {};
@@ -208,6 +208,24 @@ export interface BrokerStats {
208
208
  readonly channels: number;
209
209
  readonly supported: boolean;
210
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;
211
229
  }
212
230
  export interface IStreamBroker {
213
231
  readonly deviceId: string;
package/dist/node.d.ts CHANGED
@@ -8,3 +8,7 @@ export { canonicalDeviceFingerprint, diffExportTargets, resolveExportFingerprint
8
8
  export type { DeviceExportShape, ExportDelta, ExportTargetEntry, } from './utils/export-reconciler.js';
9
9
  export { FfmpegProcess } from './ffmpeg/process.js';
10
10
  export type { FfmpegProcessOptions, FfmpegExit, FfmpegExitClass } from './ffmpeg/process.js';
11
+ export { Fmp4FragmentPlane } from './ffmpeg/fmp4-fragment-plane.js';
12
+ export type { Fmp4CloseReason, Fmp4Packet, Fmp4PrebufferOptions, Fmp4PrebufferStats, Fmp4SubscribeInput, Fmp4SubscriberInfo, Fmp4Subscription, } from './ffmpeg/fmp4-fragment-plane.js';
13
+ export { Fmp4FragmentChild } from './ffmpeg/fmp4-fragment-child.js';
14
+ export type { Fmp4FragmentChildArgs, Fmp4FragmentChildDeps, } from './ffmpeg/fmp4-fragment-child.js';