@camstack/types 1.2.41 → 1.2.43

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 (43) hide show
  1. package/dist/addon.js +1 -1
  2. package/dist/addon.mjs +1 -1
  3. package/dist/canonical-hash-7nfBbEqR.mjs +35 -0
  4. package/dist/canonical-hash-BcZHRHIx.js +40 -0
  5. package/dist/cap-call-context.d.ts +26 -0
  6. package/dist/capabilities/index.d.ts +5 -5
  7. package/dist/capabilities/notification-rules.cap.d.ts +41 -0
  8. package/dist/capabilities/pipeline-analytics.cap.d.ts +92 -4
  9. package/dist/capabilities/pipeline-orchestrator.cap.d.ts +149 -0
  10. package/dist/capabilities/pipeline-runner.cap.d.ts +119 -1
  11. package/dist/capabilities/platform-probe.cap.d.ts +3 -3
  12. package/dist/capabilities/privacy-mask.cap.d.ts +69 -9
  13. package/dist/capabilities/recording.cap.d.ts +30 -0
  14. package/dist/capabilities/snapshot.cap.d.ts +1 -1
  15. package/dist/capabilities/stream-broker.cap.d.ts +304 -0
  16. package/dist/capabilities/stream-params.cap.d.ts +8 -4
  17. package/dist/device/device-profile.d.ts +12 -4
  18. package/dist/device/system-mirror.d.ts +11 -0
  19. package/dist/encode-profile.d.ts +2 -0
  20. package/dist/ffmpeg/encode-defaults.d.ts +107 -0
  21. package/dist/ffmpeg/hwaccel.d.ts +98 -0
  22. package/dist/ffmpeg/invocation.d.ts +348 -0
  23. package/dist/ffmpeg/process.d.ts +135 -0
  24. package/dist/ffmpeg/sharing-key.d.ts +91 -0
  25. package/dist/generated/addon-api.d.ts +92 -4
  26. package/dist/generated/device-proxy.d.ts +2 -2
  27. package/dist/generated/method-access-map.d.ts +1 -1
  28. package/dist/generated/system-proxy.d.ts +2 -2
  29. package/dist/index.d.ts +7 -0
  30. package/dist/index.js +2069 -42
  31. package/dist/index.mjs +2006 -43
  32. package/dist/interfaces/camera-switches.d.ts +375 -0
  33. package/dist/interfaces/inference-engine.d.ts +24 -3
  34. package/dist/interfaces/ops-log.d.ts +4 -0
  35. package/dist/interfaces/pipeline-runner-capability.d.ts +9 -1
  36. package/dist/node.d.ts +2 -0
  37. package/dist/node.js +270 -36
  38. package/dist/node.mjs +269 -36
  39. package/dist/pipeline/native-lease.d.ts +150 -0
  40. package/dist/{sleep-DTce7-ch.js → sleep-Bx9IIoT0.js} +43 -1
  41. package/dist/{sleep-CXimb854.mjs → sleep-DtstvzWm.mjs} +38 -2
  42. package/dist/utils/addon-id.d.ts +30 -0
  43. package/package.json +1 -1
@@ -0,0 +1,375 @@
1
+ /**
2
+ * Per-camera FUNCTION SWITCHES — the one coherent on/off surface over the
3
+ * pipeline functions an operator thinks in terms of.
4
+ *
5
+ * ## This file adds no state
6
+ *
7
+ * Every switch here is a VIEW onto an authority that already existed
8
+ * ([D62](../../../../docs/decisions/adr-0062.md)). The whole point of the
9
+ * group is that there is exactly one place each function is turned off, and
10
+ * the group routes to it:
11
+ *
12
+ * | Switch | Authority | Proven "off stops the work" gate |
13
+ * | --- | --- | --- |
14
+ * | `stream-broker` | `deviceManager.setDisabled` | `StreamBrokerManager.reconcileAllCatalogs` releases the brokers; `ensureBroker` refuses re-creation |
15
+ * | `object-detection` | `deviceManager.setWrapperActive('detection-pipeline')` | `PipelineSettingsStore.resolvePipelineForDevice` returns `{ steps: [], audio: null }` |
16
+ * | `audio-analysis` | `deviceManager.setWrapperActive('audio-analysis')` | `AudioSubscriptionController.subscribeAudioStream` returns `null` before opening the stream |
17
+ * | `recording` | `recording.setDeviceConfig` → `RecordingConfig.enabled` | `band-decision.shouldRecord` returns false; the controller detaches the device |
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
+ *
22
+ * ## The two switches whose authority is not on this server
23
+ *
24
+ * `privacy-mask` and `device-audio` write the CAMERA. That is not a loophole
25
+ * in "the group stores nothing" — it is the purest form of it: the camera
26
+ * holds the fact, every read is a read-through, and there is no server-side
27
+ * copy that could drift. Their availability therefore cannot come from
28
+ * `listBindableCapsForDeviceType` (a device-NATIVE cap carries no wrappers and
29
+ * is filtered out there); it comes from the cap's own camera-probed
30
+ * `privacyMask.getOptions()`, which is strictly more honest — it answers for
31
+ * THIS camera rather than for the device type
32
+ * ([D74](../../../../docs/decisions/adr-0074.md)).
33
+ *
34
+ * ## `privacy-mask` is the one row whose ON is not "the function is working"
35
+ *
36
+ * Every other switch means *this camera's function is doing its job*, so
37
+ * `enabled: false` is a thing an operator took away. `privacy-mask` means **the
38
+ * MASK is active** — `enabled: true` is video deliberately obscured. The
39
+ * polarity is not a choice made here: `addon-export-hap`'s privacy `Switch`
40
+ * (`builders/privacy-switch.ts`) already mirrors `patch.enabled` verbatim, and
41
+ * a HomeKit toggle that disagreed with the app's toggle for the same camera is
42
+ * worse than either surface not having one.
43
+ *
44
+ * Two consequences follow and both are load-bearing:
45
+ *
46
+ * - **It never counts as `switchedOff`.** `countsAsSwitchedOff` is `false` for
47
+ * exactly this row. With the polarity above, every camera that has NOT drawn
48
+ * a privacy mask would otherwise report `switchedOff: ['privacy-mask']` — the
49
+ * normal, healthy state of most cameras rendered as an operator disablement.
50
+ * - **Its cost line names BOTH directions.** `costWhenOff` is rendered
51
+ * unconditionally by both clients, so for this row it has to read correctly
52
+ * whichever way the switch is sitting.
53
+ *
54
+ * The wrapper-binding pair is not a new idea: `legacy-migrations.ts` already
55
+ * migrated the legacy `audioEnabled` / `pipelineEnabled` /
56
+ * `motionDetectionEnabled` booleans ONTO `setWrapperActive`. The group is the
57
+ * surface that decision never got.
58
+ *
59
+ * ## Two rules that are load-bearing
60
+ *
61
+ * - **Recording's switch is `enabled`, never the bands.** `bands` is the only
62
+ * authored intent and `mode` is derived from it (`deriveRecordingMode`).
63
+ * Expressing "off" by clearing bands destroys the operator's schedule and
64
+ * turning the camera back on would then silently record nothing.
65
+ * - **A switch that is off must be reported as off**, not merely produce
66
+ * nothing. {@link CameraSwitch.enabled} is what a status surface renders as
67
+ * "disabled by an operator" instead of "broken" — see
68
+ * `CameraStatus.switchedOff`.
69
+ */
70
+ import { z } from 'zod';
71
+ /**
72
+ * The functions the operator named — five on 2026-08-05, plus the camera's own
73
+ * microphone on 2026-08-07. Deliberately NOT one id per pipeline step: face
74
+ * recognition and plate/LPR are per-step toggles on
75
+ * `pipelineOrchestrator.setCameraStepToggle` and belong in the pipeline
76
+ * editor, not in a safety group.
77
+ */
78
+ export declare const CameraSwitchIdSchema: z.ZodEnum<{
79
+ "privacy-mask": "privacy-mask";
80
+ "audio-analysis": "audio-analysis";
81
+ recording: "recording";
82
+ "stream-broker": "stream-broker";
83
+ notifications: "notifications";
84
+ "object-detection": "object-detection";
85
+ "device-audio": "device-audio";
86
+ }>;
87
+ export type CameraSwitchId = z.infer<typeof CameraSwitchIdSchema>;
88
+ /**
89
+ * Stable render order — broadest blast radius first, and a source before the
90
+ * thing that consumes it. `device-audio` sits ABOVE `audio-analysis` because
91
+ * turning the microphone off leaves the analyzer with nothing to analyse; the
92
+ * reverse is not true.
93
+ *
94
+ * `privacy-mask` sits directly ABOVE `device-audio` because they are literal
95
+ * siblings — one cap, one device plane, video then audio — and NOT above
96
+ * `object-detection` despite feeding it: a mask blanks REGIONS, so its blast
97
+ * radius is partial, and the "broadest first" rule does not rank a partial
98
+ * control above a whole-function one.
99
+ */
100
+ export declare const CAMERA_SWITCH_ORDER: readonly CameraSwitchId[];
101
+ /**
102
+ * WHERE the switch's state actually lives. A discriminated union rather than a
103
+ * string so both the writer (the orchestrator's `setCameraSwitch`) and any
104
+ * reader can exhaustively narrow — and so "the group added a parallel map" is
105
+ * a compile error rather than a review comment.
106
+ */
107
+ export declare const CameraSwitchAuthoritySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
108
+ kind: z.ZodLiteral<"device-disabled">;
109
+ }, z.core.$strip>, z.ZodObject<{
110
+ kind: z.ZodLiteral<"wrapper-binding">;
111
+ capName: z.ZodString;
112
+ }, z.core.$strip>, z.ZodObject<{
113
+ kind: z.ZodLiteral<"recording-config">;
114
+ }, z.core.$strip>, z.ZodObject<{
115
+ kind: z.ZodLiteral<"notification-mute">;
116
+ }, z.core.$strip>, z.ZodObject<{
117
+ kind: z.ZodLiteral<"camera-audio">;
118
+ capName: z.ZodString;
119
+ }, z.core.$strip>, z.ZodObject<{
120
+ kind: z.ZodLiteral<"camera-mask">;
121
+ capName: z.ZodString;
122
+ }, z.core.$strip>], "kind">;
123
+ export type CameraSwitchAuthority = z.infer<typeof CameraSwitchAuthoritySchema>;
124
+ /**
125
+ * Why a switch is not offered for this camera. Rendered instead of the
126
+ * control, never as a dead control — an absent function and a broken one must
127
+ * not look the same.
128
+ */
129
+ export declare const CameraSwitchUnavailableReasonSchema: z.ZodEnum<{
130
+ "no-provider": "no-provider";
131
+ "source-unreachable": "source-unreachable";
132
+ "not-configured": "not-configured";
133
+ }>;
134
+ export type CameraSwitchUnavailableReason = z.infer<typeof CameraSwitchUnavailableReasonSchema>;
135
+ /**
136
+ * One switch, resolved for one camera.
137
+ *
138
+ * `label` and `costWhenOff` travel ON THE WIRE rather than being looked up
139
+ * client-side: the viewer is a separate repository that does not import
140
+ * `@camstack/types`, and a cost line duplicated in two clients is a cost line
141
+ * that will disagree with itself. Five rows per camera is nothing.
142
+ */
143
+ export declare const CameraSwitchSchema: z.ZodObject<{
144
+ id: z.ZodEnum<{
145
+ "privacy-mask": "privacy-mask";
146
+ "audio-analysis": "audio-analysis";
147
+ recording: "recording";
148
+ "stream-broker": "stream-broker";
149
+ notifications: "notifications";
150
+ "object-detection": "object-detection";
151
+ "device-audio": "device-audio";
152
+ }>;
153
+ label: z.ZodString;
154
+ costWhenOff: z.ZodString;
155
+ available: z.ZodBoolean;
156
+ unavailableReason: z.ZodOptional<z.ZodEnum<{
157
+ "no-provider": "no-provider";
158
+ "source-unreachable": "source-unreachable";
159
+ "not-configured": "not-configured";
160
+ }>>;
161
+ enabled: z.ZodBoolean;
162
+ authority: z.ZodDiscriminatedUnion<[z.ZodObject<{
163
+ kind: z.ZodLiteral<"device-disabled">;
164
+ }, z.core.$strip>, z.ZodObject<{
165
+ kind: z.ZodLiteral<"wrapper-binding">;
166
+ capName: z.ZodString;
167
+ }, z.core.$strip>, z.ZodObject<{
168
+ kind: z.ZodLiteral<"recording-config">;
169
+ }, z.core.$strip>, z.ZodObject<{
170
+ kind: z.ZodLiteral<"notification-mute">;
171
+ }, z.core.$strip>, z.ZodObject<{
172
+ kind: z.ZodLiteral<"camera-audio">;
173
+ capName: z.ZodString;
174
+ }, z.core.$strip>, z.ZodObject<{
175
+ kind: z.ZodLiteral<"camera-mask">;
176
+ capName: z.ZodString;
177
+ }, z.core.$strip>], "kind">;
178
+ }, z.core.$strip>;
179
+ export type CameraSwitch = z.infer<typeof CameraSwitchSchema>;
180
+ /** The whole group for one camera. */
181
+ export declare const CameraSwitchGroupSchema: z.ZodObject<{
182
+ deviceId: z.ZodNumber;
183
+ switches: z.ZodReadonly<z.ZodArray<z.ZodObject<{
184
+ id: z.ZodEnum<{
185
+ "privacy-mask": "privacy-mask";
186
+ "audio-analysis": "audio-analysis";
187
+ recording: "recording";
188
+ "stream-broker": "stream-broker";
189
+ notifications: "notifications";
190
+ "object-detection": "object-detection";
191
+ "device-audio": "device-audio";
192
+ }>;
193
+ label: z.ZodString;
194
+ costWhenOff: z.ZodString;
195
+ available: z.ZodBoolean;
196
+ unavailableReason: z.ZodOptional<z.ZodEnum<{
197
+ "no-provider": "no-provider";
198
+ "source-unreachable": "source-unreachable";
199
+ "not-configured": "not-configured";
200
+ }>>;
201
+ enabled: z.ZodBoolean;
202
+ authority: z.ZodDiscriminatedUnion<[z.ZodObject<{
203
+ kind: z.ZodLiteral<"device-disabled">;
204
+ }, z.core.$strip>, z.ZodObject<{
205
+ kind: z.ZodLiteral<"wrapper-binding">;
206
+ capName: z.ZodString;
207
+ }, z.core.$strip>, z.ZodObject<{
208
+ kind: z.ZodLiteral<"recording-config">;
209
+ }, z.core.$strip>, z.ZodObject<{
210
+ kind: z.ZodLiteral<"notification-mute">;
211
+ }, z.core.$strip>, z.ZodObject<{
212
+ kind: z.ZodLiteral<"camera-audio">;
213
+ capName: z.ZodString;
214
+ }, z.core.$strip>, z.ZodObject<{
215
+ kind: z.ZodLiteral<"camera-mask">;
216
+ capName: z.ZodString;
217
+ }, z.core.$strip>], "kind">;
218
+ }, z.core.$strip>>>;
219
+ fetchedAt: z.ZodNumber;
220
+ }, z.core.$strip>;
221
+ export type CameraSwitchGroup = z.infer<typeof CameraSwitchGroupSchema>;
222
+ /**
223
+ * The wrapper capability each wrapper-backed switch controls. Named constants
224
+ * because the same strings appear in `legacy-migrations.ts`, in
225
+ * `isCapActiveForDevice` call sites and in the fake harness — a typo in any of
226
+ * them is a switch that silently writes a binding nobody reads.
227
+ */
228
+ export declare const DETECTION_PIPELINE_CAP_NAME = "detection-pipeline";
229
+ export declare const AUDIO_ANALYSIS_CAP_NAME = "audio-analysis";
230
+ /**
231
+ * The device-NATIVE cap that owns what the camera does not capture — masked
232
+ * video regions and, since 2026-08-07, the microphone. Named here because the
233
+ * `camera-audio` authority, the orchestrator's gather and the fake harness all
234
+ * have to agree on it.
235
+ */
236
+ export declare const PRIVACY_MASK_CAP_NAME = "privacy-mask";
237
+ /** Static half of a switch: everything that does not depend on a device. */
238
+ export interface CameraSwitchDescriptor {
239
+ readonly id: CameraSwitchId;
240
+ readonly label: string;
241
+ readonly costWhenOff: string;
242
+ readonly authority: CameraSwitchAuthority;
243
+ /**
244
+ * May `enabled: false` on this row appear in {@link switchedOffIds}?
245
+ *
246
+ * `true` for every switch that means "this camera's function is doing its
247
+ * job", where OFF is something a person took away and a status surface must
248
+ * render as disabled rather than broken.
249
+ *
250
+ * `false` for `privacy-mask` alone, and only because its polarity is
251
+ * inverted: OFF there means the mask is not obscuring anything, which is the
252
+ * ordinary state of nearly every camera. Reporting it would put a
253
+ * `switchedOff` badge on healthy cameras and drown the badge that matters.
254
+ */
255
+ readonly countsAsSwitchedOff: boolean;
256
+ }
257
+ /**
258
+ * THE catalog. One entry per switch; the cost lines are the operator-facing
259
+ * contract and are written to be true rather than reassuring.
260
+ */
261
+ export declare const CAMERA_SWITCH_CATALOG: Readonly<Record<CameraSwitchId, CameraSwitchDescriptor>>;
262
+ /**
263
+ * Everything the pure derivation needs, gathered by the caller. A `null`
264
+ * sub-state means the owning source did not answer — which produces
265
+ * `available: false` with `source-unreachable`, NEVER a control defaulted to
266
+ * "on". Guessing a switch is on when we could not read it is how an operator
267
+ * learns a function is off a week later.
268
+ */
269
+ export interface CameraSwitchDerivationInput {
270
+ readonly deviceId: number;
271
+ /** `deviceManager` soft-disable flag for this device. */
272
+ readonly deviceDisabled: boolean;
273
+ /**
274
+ * Capability names bindable for this device's TYPE
275
+ * (`deviceManager.listBindableCapsForDeviceType`). This is what makes the
276
+ * group derived rather than hardcoded: a deployment with no audio analyzer
277
+ * has no `audio-analysis` here, so no audio switch is rendered.
278
+ * `null` = the lookup failed.
279
+ */
280
+ readonly bindableCapNames: readonly string[] | null;
281
+ /**
282
+ * Capability names currently bound `kind: 'wrapped'` for this device
283
+ * (`deviceManager.getBindings`). Absence IS how a deactivated wrapper is
284
+ * represented — there is no `active: false` row.
285
+ */
286
+ readonly activeWrapperCapNames: readonly string[] | null;
287
+ /** `RecordingConfig.enabled`; `null` when the recording cap did not answer. */
288
+ readonly recordingEnabled: boolean | null;
289
+ /** `notificationRules` per-camera mute; `null` when the cap did not answer. */
290
+ readonly notificationsMuted: boolean | null;
291
+ /**
292
+ * The camera's own microphone, read through the `privacy-mask` native cap.
293
+ * `null` = the cap is bound to this camera but did not answer.
294
+ *
295
+ * A camera with no `privacy-mask` provider at all is `{ supported: false }`,
296
+ * not `null` — "this camera has no such control" and "we could not read it"
297
+ * are different answers and the operator is shown different copy for each.
298
+ */
299
+ readonly deviceAudio: DeviceAudioSwitchState | null;
300
+ /**
301
+ * The camera's own VIDEO privacy mask, read through the same `privacy-mask`
302
+ * native cap and the same pair of round trips as {@link deviceAudio} — one
303
+ * `getOptions` + one `getStatus` answer both, so the second switch is free.
304
+ *
305
+ * `null` = the cap is bound to this camera but did not answer.
306
+ */
307
+ readonly privacyMask: PrivacyMaskSwitchState | null;
308
+ }
309
+ /** What the camera-probed audio switch reported for one camera. */
310
+ export interface DeviceAudioSwitchState {
311
+ /**
312
+ * `privacyMask.getOptions().supportsAudioMute` — camera-probed, never a
313
+ * device-type guess. A camera that does not expose the control renders no
314
+ * switch rather than a toggle that silently does nothing.
315
+ */
316
+ readonly supported: boolean;
317
+ /**
318
+ * `privacyMask.getStatus().audioEnabled` — the camera's current answer.
319
+ * `null` when unsupported, or when supported but unreadable; the second
320
+ * case yields `source-unreachable`, never a control defaulted to "on".
321
+ */
322
+ readonly enabled: boolean | null;
323
+ }
324
+ /** What the camera-probed VIDEO privacy mask reported for one camera. */
325
+ export interface PrivacyMaskSwitchState {
326
+ /**
327
+ * Can this camera store privacy zones at all? Derived from the probed
328
+ * `getOptions()`: `maxRegions > 0` AND at least one supported shape kind.
329
+ * Reolink answers `maxNum: 0` / `supportedShapes: []` honestly on models
330
+ * that cannot, and that must render no control rather than a toggle whose
331
+ * write the camera discards.
332
+ */
333
+ readonly supported: boolean;
334
+ /**
335
+ * How many zones are actually drawn on the camera right now
336
+ * (`getStatus().regions.length`). `null` = supported, but the status could
337
+ * not be read.
338
+ *
339
+ * **Zero is not "off", it is "nothing to switch".** Toggling the master
340
+ * enable with no zones changes not one pixel — the dead control D62 exists
341
+ * to remove — so it resolves to `not-configured`, which tells the operator
342
+ * to go and draw one instead of leaving them pressing a button.
343
+ */
344
+ readonly configuredRegions: number | null;
345
+ /**
346
+ * `getStatus().enabled` — the camera's master mask flag, `true` when the
347
+ * zones are being blanked. `null` when unreadable; never defaulted.
348
+ */
349
+ readonly enabled: boolean | null;
350
+ }
351
+ /**
352
+ * Pure derivation of the whole group. No I/O — the orchestrator gathers, this
353
+ * decides, so the decision is testable without a hub.
354
+ *
355
+ * Order is {@link CAMERA_SWITCH_ORDER}; unavailable switches are RETURNED
356
+ * rather than filtered out, so a client can explain the gap instead of
357
+ * silently rendering four buttons where another camera shows five.
358
+ */
359
+ export declare function deriveCameraSwitches(input: CameraSwitchDerivationInput): readonly CameraSwitch[];
360
+ /**
361
+ * The ids an operator has switched OFF, for a status surface.
362
+ *
363
+ * This is the answer to "a disabled function must be visible as DISABLED, not
364
+ * merely quiet": a camera reporting zero detections with
365
+ * `switchedOff: ['object-detection']` was turned off; the same camera with an
366
+ * empty list is broken. Unavailable switches never appear — a function nobody
367
+ * provides was not switched off by anyone.
368
+ *
369
+ * `privacy-mask` never appears either, whichever way it is sitting, because its
370
+ * ON means "the mask is active" rather than "the function works"
371
+ * ({@link CameraSwitchDescriptor.countsAsSwitchedOff}). Without that filter the
372
+ * ordinary state of every camera nobody has masked would carry a
373
+ * "switched off" badge, and the badge that matters would be lost in it.
374
+ */
375
+ 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 {};
@@ -23,6 +23,7 @@ export declare const OpsLogOpSchema: z.ZodEnum<{
23
23
  rescan: "rescan";
24
24
  "retention-run": "retention-run";
25
25
  relocate: "relocate";
26
+ "orphan-audit": "orphan-audit";
26
27
  }>;
27
28
  export type OpsLogOp = z.infer<typeof OpsLogOpSchema>;
28
29
  /** Why the operation ran. */
@@ -31,6 +32,7 @@ export declare const OpsLogReasonSchema: z.ZodEnum<{
31
32
  operator: "operator";
32
33
  retention: "retention";
33
34
  quota: "quota";
35
+ maintenance: "maintenance";
34
36
  }>;
35
37
  export type OpsLogReason = z.infer<typeof OpsLogReasonSchema>;
36
38
  /** One audit row, shared verbatim by both domains. */
@@ -47,12 +49,14 @@ export declare const OpsLogEntrySchema: z.ZodObject<{
47
49
  rescan: "rescan";
48
50
  "retention-run": "retention-run";
49
51
  relocate: "relocate";
52
+ "orphan-audit": "orphan-audit";
50
53
  }>;
51
54
  reason: z.ZodEnum<{
52
55
  manual: "manual";
53
56
  operator: "operator";
54
57
  retention: "retention";
55
58
  quota: "quota";
59
+ maintenance: "maintenance";
56
60
  }>;
57
61
  deviceId: z.ZodNullable<z.ZodNumber>;
58
62
  nodeId: z.ZodString;
@@ -1,7 +1,7 @@
1
- import type { OrchestratorMetrics, CameraMetrics } from './api-shared.js';
2
1
  import type { PipelineStepInputOutput } from '../capabilities/pipeline-executor.cap.js';
3
2
  import type { Zone } from '../capabilities/zones.cap.js';
4
3
  import type { PipelinePhaseMode } from '../device/device-profile.js';
4
+ import type { CameraMetrics, OrchestratorMetrics } from './api-shared.js';
5
5
  /**
6
6
  * Camera assignment payload sent by the pipeline-orchestrator to a runner
7
7
  * via `attachCamera`. Carries everything the runner needs to subscribe to
@@ -204,4 +204,12 @@ export interface IPipelineRunnerProvider {
204
204
  * `null` when neither `frameHandle` nor `cropJpeg` resolves to a crop.
205
205
  */
206
206
  runDetailSubtree(input: import('../capabilities/pipeline-runner.cap.js').RunDetailSubtreeInput): Promise<import('../capabilities/pipeline-runner.cap.js').RunDetailSubtreeResult | null>;
207
+ /**
208
+ * Run ONE enrichment step against caller-supplied pixels with NO camera
209
+ * session — no attach, no handle, no device affinity. See
210
+ * `pipelineRunnerCapability.runStatelessStep`
211
+ * (`capabilities/pipeline-runner.cap.ts`) for the full contract, including
212
+ * why the model pin is refused rather than substituted.
213
+ */
214
+ runStatelessStep(input: import('../capabilities/pipeline-runner.cap.js').RunStatelessStepInput): Promise<import('../capabilities/pipeline-runner.cap.js').RunStatelessStepResult>;
207
215
  }
package/dist/node.d.ts CHANGED
@@ -6,3 +6,5 @@ export { FilesystemStorageProvider } from './storage/filesystem-storage-provider
6
6
  export { canonicalHash } from './utils/canonical-hash.js';
7
7
  export { canonicalDeviceFingerprint, diffExportTargets, resolveExportFingerprint, } from './utils/export-reconciler.js';
8
8
  export type { DeviceExportShape, ExportDelta, ExportTargetEntry, } from './utils/export-reconciler.js';
9
+ export { FfmpegProcess } from './ffmpeg/process.js';
10
+ export type { FfmpegProcessOptions, FfmpegExit, FfmpegExitClass } from './ffmpeg/process.js';