@ceralive/cerastream 2026.6.2 → 2026.7.0

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/client.d.ts CHANGED
@@ -28,31 +28,80 @@ export interface Subscription {
28
28
  /**
29
29
  * Bidirectional JSON-RPC 2.0 control client for cerastream. One method per v1
30
30
  * request plus the handshake. Server-push events arrive via `subscribeEvents`.
31
+ *
32
+ * Every request method rejects with a {@link CerastreamRpcError} when the engine
33
+ * returns a typed error, a {@link CerastreamTimeoutError} when no reply arrives
34
+ * within the per-request timeout, or a {@link CerastreamConnectionError} when the
35
+ * control socket is not open.
31
36
  */
32
37
  export interface CerastreamClient {
33
38
  /** Negotiated handshake result (protocol + schema/engine versions). */
34
39
  readonly hello: HelloResult;
35
- /** Start the streaming pipeline (encode → bond → SRT). */
40
+ /**
41
+ * Start the streaming pipeline (encode → bond → SRT).
42
+ * @param params Unified engine config (pipeline, SRT, bitrate, input).
43
+ * @returns The new session id and initial stream state.
44
+ * @throws {CerastreamRpcError} when params are invalid or already streaming.
45
+ */
36
46
  start(params: StartParams): Promise<StartResult>;
37
- /** Stop the streaming pipeline. Idempotent. Stops the pipeline, NOT the OS process. */
47
+ /**
48
+ * Stop the streaming pipeline. Idempotent. Stops the pipeline, NOT the OS process.
49
+ * @param params Optional stop reason recorded by the engine.
50
+ * @returns The stream state after the stop (`idle`).
51
+ */
38
52
  stop(params?: StopParams): Promise<StopResult>;
39
- /** Hot-reload engine config (replaces SIGHUP). Returns the applied config. */
53
+ /**
54
+ * Hot-reload engine config (replaces SIGHUP).
55
+ * @param params Partial bitrate/SRT/audio fields to update.
56
+ * @returns The post-clamp values actually applied.
57
+ * @throws {CerastreamRpcError} when a field is out of range (e.g. audio delay).
58
+ */
40
59
  reloadConfig(params: ReloadConfigParams): Promise<ReloadConfigResult>;
41
- /** Hot-adjust max bitrate while streaming. Returns the post-clamp applied value. */
60
+ /**
61
+ * Hot-adjust max bitrate while streaming.
62
+ * @param params The new bitrate ceiling, in kbps.
63
+ * @returns The post-clamp applied bitrate.
64
+ * @throws {CerastreamRpcError} when the value is out of the configured range.
65
+ */
42
66
  setBitrate(params: SetBitrateParams): Promise<SetBitrateResult>;
43
- /** Switch the active capture source (manual) or hand selection to failover (auto). */
67
+ /**
68
+ * Switch the active capture source (manual) or hand selection to failover (auto).
69
+ * @param params The target input id and switch mode.
70
+ * @returns The input now active and the mode in effect.
71
+ * @throws {CerastreamRpcError} when the input id is unknown.
72
+ */
44
73
  switchInput(params: SwitchInputParams): Promise<SwitchInputResult>;
45
- /** Enumerate capture devices (GstDeviceMonitor, de-duped by device path). */
74
+ /**
75
+ * Enumerate capture devices (GstDeviceMonitor, de-duped by device path).
76
+ * @param params Optional media-class filter.
77
+ * @returns The discovered capture devices.
78
+ */
46
79
  listDevices(params?: ListDevicesParams): Promise<ListDevicesResult>;
47
- /** Subscribe to the live event stream; `handler` fires for each pushed event. */
80
+ /**
81
+ * Subscribe to the live event stream; `handler` fires for each pushed event.
82
+ * @param params The topics to subscribe to (absent ⇒ all topics).
83
+ * @param handler Invoked for every matching server-pushed event.
84
+ * @returns A {@link Subscription} whose `close()` stops delivery.
85
+ */
48
86
  subscribeEvents(params: SubscribeEventsParams, handler: EventHandler): Promise<Subscription>;
49
- /** Control a local preview session (WebCodecs binary tier / WebRTC signaling). */
87
+ /**
88
+ * Control a local preview session (WebCodecs binary tier / WebRTC signaling).
89
+ * @param params The session action (start/stop/signal) and its fields.
90
+ * @returns The session id, tier, and how to reach the preview media.
91
+ * @throws {CerastreamRpcError} when the requested tier is unavailable.
92
+ */
50
93
  previewSession(params: PreviewSessionParams): Promise<PreviewSessionResult>;
51
- /** Close the control connection. Never respawns the engine (ADR-0005). */
94
+ /**
95
+ * Close the control connection. Never respawns the engine (ADR-0005).
96
+ * @returns A promise that resolves once the socket is closed.
97
+ */
52
98
  close(): Promise<void>;
53
99
  }
54
100
  /**
55
101
  * Connect to the cerastream control socket, run the mandatory `hello`
56
102
  * handshake, and return a {@link CerastreamClient}.
103
+ * @param options Optional socket path, client name, timeout, and reconnect knobs.
104
+ * @returns A connected, handshaked {@link CerastreamClient}.
105
+ * @throws {CerastreamConnectionError} when the control socket cannot be reached.
57
106
  */
58
107
  export declare function connect(options?: ConnectOptions): Promise<CerastreamClient>;
package/dist/client.js CHANGED
@@ -266,6 +266,9 @@ function sleep(ms) {
266
266
  /**
267
267
  * Connect to the cerastream control socket, run the mandatory `hello`
268
268
  * handshake, and return a {@link CerastreamClient}.
269
+ * @param options Optional socket path, client name, timeout, and reconnect knobs.
270
+ * @returns A connected, handshaked {@link CerastreamClient}.
271
+ * @throws {CerastreamConnectionError} when the control socket cannot be reached.
269
272
  */
270
273
  export async function connect(options) {
271
274
  const client = new ClientImpl(options ?? {});
@@ -8,7 +8,7 @@ export declare const PROTOCOL_VERSION: "cerastream-ipc/1";
8
8
  * additive-only within protocol major `cerastream-ipc/1` (ADR-0002 §4); this value
9
9
  * only moves when the wire schema itself does, in lockstep across both languages.
10
10
  */
11
- export declare const SCHEMA_VERSION: "0.3.0";
11
+ export declare const SCHEMA_VERSION: "0.4.0";
12
12
  /** Runtime dir holding both control + preview sockets. systemd `RuntimeDirectory=cerastream`. */
13
13
  export declare const DEFAULT_IPC_DIR: "/run/cerastream";
14
14
  /** Env override for the IPC dir (tests/dev). Defaults to {@link DEFAULT_IPC_DIR}. */
@@ -25,6 +25,37 @@ export declare const PREVIEW_SOCKET_PATH: "/run/cerastream/preview.sock";
25
25
  export declare const MAX_LINE_BYTES: number;
26
26
  /** Upper bound (ms) for `reload-config.audio.delay_ms`. Mirrors the Rust `AUDIO_DELAY_MAX_MS` and CeraUI's `AUDIO_DELAY_MAX`. */
27
27
  export declare const AUDIO_DELAY_MAX_MS = 2000;
28
+ /**
29
+ * SRT receive-latency capability range (ms) reported by `get-capabilities`
30
+ * (`latency_range`). Latency is a CONTINUOUS control wired to `SRTO_LATENCY`,
31
+ * applied on (re)connect; CeraUI renders these as the slider's min/default/max.
32
+ * `MAX` is the device-recommended ceiling; a receiver may advertise a lower cap.
33
+ * Mirror the Rust `LATENCY_MIN_MS` / `LATENCY_DEFAULT_MS` / `LATENCY_MAX_MS`.
34
+ */
35
+ export declare const LATENCY_MIN_MS = 100;
36
+ export declare const LATENCY_DEFAULT_MS = 1500;
37
+ export declare const LATENCY_MAX_MS = 5000;
38
+ /**
39
+ * Recommended SRT FEC sender full-config string for `srtConfig.fec`. The sender
40
+ * defines the complete matrix (staircase 10×10, ARQ on-request); a CeraLive
41
+ * receiver sets just `fec` and adopts it (one-sided negotiation). The device
42
+ * applies it to `SRTO_PACKETFILTER` ONLY against a known FEC-capable receiver.
43
+ * Mirrors the Rust `DEFAULT_FEC_CONFIG`.
44
+ */
45
+ export declare const DEFAULT_FEC_CONFIG: "fec,layout:staircase,rows:10,cols:10,arq:onreq";
46
+ /**
47
+ * The v1 SRT receive-profile catalog: the preset ids `get-capabilities`
48
+ * advertises in `supported_profiles`. A profile is a named preset CeraUI expands
49
+ * to an SRT/bitrate config; the resolver and the Stream Tuning card read this list
50
+ * to gate which presets the device offers. Mirrors the Rust `SUPPORTED_PROFILES`.
51
+ */
52
+ export declare const SUPPORTED_PROFILES: readonly ["balanced", "low-latency", "resilient", "classic", "low-latency-fec"];
53
+ /**
54
+ * Version of the profile catalog {@link SUPPORTED_PROFILES} comes from (semver),
55
+ * echoed by `get-capabilities` as `profile_catalog_version`. Bumped when the preset
56
+ * set or any preset's meaning changes. Mirrors the Rust `PROFILE_CATALOG_VERSION`.
57
+ */
58
+ export declare const PROFILE_CATALOG_VERSION: "1.0.0";
28
59
  /** Engine binary name (systemd-owned; CeraUI never spawns it — ADR-0005). */
29
60
  export declare const CERASTREAM_BIN: "cerastream";
30
61
  export declare const DEFAULT_MIN_BITRATE = 300;
package/dist/constants.js CHANGED
@@ -11,7 +11,7 @@ export const PROTOCOL_VERSION = "cerastream-ipc/1";
11
11
  * additive-only within protocol major `cerastream-ipc/1` (ADR-0002 §4); this value
12
12
  * only moves when the wire schema itself does, in lockstep across both languages.
13
13
  */
14
- export const SCHEMA_VERSION = "0.3.0";
14
+ export const SCHEMA_VERSION = "0.4.0";
15
15
  /** Runtime dir holding both control + preview sockets. systemd `RuntimeDirectory=cerastream`. */
16
16
  export const DEFAULT_IPC_DIR = "/run/cerastream";
17
17
  /** Env override for the IPC dir (tests/dev). Defaults to {@link DEFAULT_IPC_DIR}. */
@@ -28,6 +28,43 @@ export const PREVIEW_SOCKET_PATH = "/run/cerastream/preview.sock";
28
28
  export const MAX_LINE_BYTES = 1024 * 1024; // 1 MiB
29
29
  /** Upper bound (ms) for `reload-config.audio.delay_ms`. Mirrors the Rust `AUDIO_DELAY_MAX_MS` and CeraUI's `AUDIO_DELAY_MAX`. */
30
30
  export const AUDIO_DELAY_MAX_MS = 2000;
31
+ /**
32
+ * SRT receive-latency capability range (ms) reported by `get-capabilities`
33
+ * (`latency_range`). Latency is a CONTINUOUS control wired to `SRTO_LATENCY`,
34
+ * applied on (re)connect; CeraUI renders these as the slider's min/default/max.
35
+ * `MAX` is the device-recommended ceiling; a receiver may advertise a lower cap.
36
+ * Mirror the Rust `LATENCY_MIN_MS` / `LATENCY_DEFAULT_MS` / `LATENCY_MAX_MS`.
37
+ */
38
+ export const LATENCY_MIN_MS = 100;
39
+ export const LATENCY_DEFAULT_MS = 1500;
40
+ export const LATENCY_MAX_MS = 5000;
41
+ /**
42
+ * Recommended SRT FEC sender full-config string for `srtConfig.fec`. The sender
43
+ * defines the complete matrix (staircase 10×10, ARQ on-request); a CeraLive
44
+ * receiver sets just `fec` and adopts it (one-sided negotiation). The device
45
+ * applies it to `SRTO_PACKETFILTER` ONLY against a known FEC-capable receiver.
46
+ * Mirrors the Rust `DEFAULT_FEC_CONFIG`.
47
+ */
48
+ export const DEFAULT_FEC_CONFIG = "fec,layout:staircase,rows:10,cols:10,arq:onreq";
49
+ /**
50
+ * The v1 SRT receive-profile catalog: the preset ids `get-capabilities`
51
+ * advertises in `supported_profiles`. A profile is a named preset CeraUI expands
52
+ * to an SRT/bitrate config; the resolver and the Stream Tuning card read this list
53
+ * to gate which presets the device offers. Mirrors the Rust `SUPPORTED_PROFILES`.
54
+ */
55
+ export const SUPPORTED_PROFILES = [
56
+ "balanced",
57
+ "low-latency",
58
+ "resilient",
59
+ "classic",
60
+ "low-latency-fec",
61
+ ];
62
+ /**
63
+ * Version of the profile catalog {@link SUPPORTED_PROFILES} comes from (semver),
64
+ * echoed by `get-capabilities` as `profile_catalog_version`. Bumped when the preset
65
+ * set or any preset's meaning changes. Mirrors the Rust `PROFILE_CATALOG_VERSION`.
66
+ */
67
+ export const PROFILE_CATALOG_VERSION = "1.0.0";
31
68
  /** Engine binary name (systemd-owned; CeraUI never spawns it — ADR-0005). */
32
69
  export const CERASTREAM_BIN = "cerastream";
33
70
  // ---- config defaults (mirror ceracoder, the engine being replaced) ----
package/dist/events.d.ts CHANGED
@@ -1,4 +1,29 @@
1
1
  import { z } from "zod";
2
+ /**
3
+ * The engine's RESOLVED runtime encode state (0.4.0, additive), reported on the
4
+ * `status` event as `active_encode`. Engine = reporter of record: this is the
5
+ * encode actually running (realized graph), not the requested params. `decoder`
6
+ * names the runtime-selected decode element for a compressed capture. Absent on a
7
+ * legacy emitter or a bare state-only heartbeat.
8
+ */
9
+ export declare const activeEncodeSchema: z.ZodObject<{
10
+ codec: z.ZodString;
11
+ resolution: z.ZodString;
12
+ framerate: z.ZodNumber;
13
+ active_input: z.ZodOptional<z.ZodString>;
14
+ decoder: z.ZodOptional<z.ZodString>;
15
+ }, z.core.$strip>;
16
+ export type ActiveEncode = z.infer<typeof activeEncodeSchema>;
17
+ /**
18
+ * `status` event — stream state change + heartbeat. The trailing fields are
19
+ * additive: the `buffering*` / `spooled_bytes` / `data_headroom_bytes` /
20
+ * `disk_warning` egress-spool telemetry (Task 32) is absent on a plain heartbeat
21
+ * and present only on a spool engage/drain transition or disk-usage warning;
22
+ * `active_profile` (srt-receive-profiles) reports the profile/config the stream is
23
+ * running under and is absent on a legacy emitter or a bare state-only heartbeat;
24
+ * `active_encode` (0.4.0) reports the resolved runtime encode and is absent on a
25
+ * legacy emitter or a bare state-only heartbeat.
26
+ */
2
27
  export declare const statusEventSchema: z.ZodObject<{
3
28
  type: z.ZodLiteral<"status">;
4
29
  seq: z.ZodNumber;
@@ -10,8 +35,26 @@ export declare const statusEventSchema: z.ZodObject<{
10
35
  }>;
11
36
  streaming: z.ZodBoolean;
12
37
  active_input: z.ZodOptional<z.ZodString>;
38
+ active_profile: z.ZodOptional<z.ZodString>;
39
+ buffering: z.ZodOptional<z.ZodBoolean>;
40
+ spooled_bytes: z.ZodOptional<z.ZodNumber>;
41
+ data_headroom_bytes: z.ZodOptional<z.ZodNumber>;
42
+ disk_warning: z.ZodOptional<z.ZodBoolean>;
43
+ active_encode: z.ZodOptional<z.ZodObject<{
44
+ codec: z.ZodString;
45
+ resolution: z.ZodString;
46
+ framerate: z.ZodNumber;
47
+ active_input: z.ZodOptional<z.ZodString>;
48
+ decoder: z.ZodOptional<z.ZodString>;
49
+ }, z.core.$strip>>;
13
50
  }, z.core.$strip>;
51
+ /** Payload of a {@link statusEventSchema} event. */
14
52
  export type StatusEvent = z.infer<typeof statusEventSchema>;
53
+ /**
54
+ * `switch` event — active input changed (manual or failover). `media_class` is
55
+ * additive (absent on legacy video-only emitters); `switch-audio` sets it to
56
+ * `"audio"`.
57
+ */
15
58
  export declare const switchEventSchema: z.ZodObject<{
16
59
  type: z.ZodLiteral<"switch">;
17
60
  seq: z.ZodNumber;
@@ -26,7 +69,9 @@ export declare const switchEventSchema: z.ZodObject<{
26
69
  audio: "audio";
27
70
  }>>;
28
71
  }, z.core.$strip>;
72
+ /** Payload of a {@link switchEventSchema} event. */
29
73
  export type SwitchEvent = z.infer<typeof switchEventSchema>;
74
+ /** `device` event — a GstDeviceMonitor hotplug add/remove. */
30
75
  export declare const deviceEventSchema: z.ZodObject<{
31
76
  type: z.ZodLiteral<"device">;
32
77
  seq: z.ZodNumber;
@@ -48,16 +93,30 @@ export declare const deviceEventSchema: z.ZodObject<{
48
93
  framerate: z.ZodOptional<z.ZodString>;
49
94
  media_type: z.ZodOptional<z.ZodString>;
50
95
  }, z.core.$strip>>>;
96
+ kind: z.ZodOptional<z.ZodEnum<{
97
+ audio: "audio";
98
+ hdmi: "hdmi";
99
+ uvc_h264: "uvc_h264";
100
+ uvc_h265: "uvc_h265";
101
+ mjpeg: "mjpeg";
102
+ camlink: "camlink";
103
+ test: "test";
104
+ network: "network";
105
+ }>>;
51
106
  }, z.core.$strip>;
52
107
  }, z.core.$strip>;
108
+ /** Payload of a {@link deviceEventSchema} event. */
53
109
  export type DeviceEvent = z.infer<typeof deviceEventSchema>;
110
+ /** `bitrate` event — the adaptive controller adjusted the encode bitrate. */
54
111
  export declare const bitrateEventSchema: z.ZodObject<{
55
112
  type: z.ZodLiteral<"bitrate">;
56
113
  seq: z.ZodNumber;
57
114
  current_bitrate: z.ZodNumber;
58
115
  max_bitrate: z.ZodNumber;
59
116
  }, z.core.$strip>;
117
+ /** Payload of a {@link bitrateEventSchema} event. */
60
118
  export type BitrateEvent = z.infer<typeof bitrateEventSchema>;
119
+ /** `srt-stats` event — periodic SRT transport telemetry. */
61
120
  export declare const srtStatsEventSchema: z.ZodObject<{
62
121
  type: z.ZodLiteral<"srt-stats">;
63
122
  seq: z.ZodNumber;
@@ -65,7 +124,12 @@ export declare const srtStatsEventSchema: z.ZodObject<{
65
124
  send_buffer: z.ZodNumber;
66
125
  pkt_loss: z.ZodNumber;
67
126
  }, z.core.$strip>;
127
+ /** Payload of a {@link srtStatsEventSchema} event. */
68
128
  export type SrtStatsEvent = z.infer<typeof srtStatsEventSchema>;
129
+ /**
130
+ * `error` event — a runtime error (replaces stderr scraping). Carries a Tier-2
131
+ * code; the engine reports facts and CeraUI decides what to surface.
132
+ */
69
133
  export declare const runtimeErrorEventSchema: z.ZodObject<{
70
134
  type: z.ZodLiteral<"error">;
71
135
  seq: z.ZodNumber;
@@ -84,13 +148,16 @@ export declare const runtimeErrorEventSchema: z.ZodObject<{
84
148
  }>;
85
149
  reason: z.ZodOptional<z.ZodString>;
86
150
  }, z.core.$strip>;
151
+ /** Payload of a {@link runtimeErrorEventSchema} event. */
87
152
  export type RuntimeErrorEvent = z.infer<typeof runtimeErrorEventSchema>;
153
+ /** `preview` event — a preview-session lifecycle/phase change. */
88
154
  export declare const previewEventSchema: z.ZodObject<{
89
155
  type: z.ZodLiteral<"preview">;
90
156
  seq: z.ZodNumber;
91
157
  session_id: z.ZodString;
92
158
  phase: z.ZodString;
93
159
  }, z.core.$strip>;
160
+ /** Payload of a {@link previewEventSchema} event. */
94
161
  export type PreviewEvent = z.infer<typeof previewEventSchema>;
95
162
  /** Discriminated union of every v1 event payload (the inner `params`). */
96
163
  export declare const eventParamsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -104,6 +171,18 @@ export declare const eventParamsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
104
171
  }>;
105
172
  streaming: z.ZodBoolean;
106
173
  active_input: z.ZodOptional<z.ZodString>;
174
+ active_profile: z.ZodOptional<z.ZodString>;
175
+ buffering: z.ZodOptional<z.ZodBoolean>;
176
+ spooled_bytes: z.ZodOptional<z.ZodNumber>;
177
+ data_headroom_bytes: z.ZodOptional<z.ZodNumber>;
178
+ disk_warning: z.ZodOptional<z.ZodBoolean>;
179
+ active_encode: z.ZodOptional<z.ZodObject<{
180
+ codec: z.ZodString;
181
+ resolution: z.ZodString;
182
+ framerate: z.ZodNumber;
183
+ active_input: z.ZodOptional<z.ZodString>;
184
+ decoder: z.ZodOptional<z.ZodString>;
185
+ }, z.core.$strip>>;
107
186
  }, z.core.$strip>, z.ZodObject<{
108
187
  type: z.ZodLiteral<"switch">;
109
188
  seq: z.ZodNumber;
@@ -138,6 +217,16 @@ export declare const eventParamsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
138
217
  framerate: z.ZodOptional<z.ZodString>;
139
218
  media_type: z.ZodOptional<z.ZodString>;
140
219
  }, z.core.$strip>>>;
220
+ kind: z.ZodOptional<z.ZodEnum<{
221
+ audio: "audio";
222
+ hdmi: "hdmi";
223
+ uvc_h264: "uvc_h264";
224
+ uvc_h265: "uvc_h265";
225
+ mjpeg: "mjpeg";
226
+ camlink: "camlink";
227
+ test: "test";
228
+ network: "network";
229
+ }>>;
141
230
  }, z.core.$strip>;
142
231
  }, z.core.$strip>, z.ZodObject<{
143
232
  type: z.ZodLiteral<"bitrate">;
@@ -189,6 +278,18 @@ export declare const cerastreamEventSchema: z.ZodObject<{
189
278
  }>;
190
279
  streaming: z.ZodBoolean;
191
280
  active_input: z.ZodOptional<z.ZodString>;
281
+ active_profile: z.ZodOptional<z.ZodString>;
282
+ buffering: z.ZodOptional<z.ZodBoolean>;
283
+ spooled_bytes: z.ZodOptional<z.ZodNumber>;
284
+ data_headroom_bytes: z.ZodOptional<z.ZodNumber>;
285
+ disk_warning: z.ZodOptional<z.ZodBoolean>;
286
+ active_encode: z.ZodOptional<z.ZodObject<{
287
+ codec: z.ZodString;
288
+ resolution: z.ZodString;
289
+ framerate: z.ZodNumber;
290
+ active_input: z.ZodOptional<z.ZodString>;
291
+ decoder: z.ZodOptional<z.ZodString>;
292
+ }, z.core.$strip>>;
192
293
  }, z.core.$strip>, z.ZodObject<{
193
294
  type: z.ZodLiteral<"switch">;
194
295
  seq: z.ZodNumber;
@@ -223,6 +324,16 @@ export declare const cerastreamEventSchema: z.ZodObject<{
223
324
  framerate: z.ZodOptional<z.ZodString>;
224
325
  media_type: z.ZodOptional<z.ZodString>;
225
326
  }, z.core.$strip>>>;
327
+ kind: z.ZodOptional<z.ZodEnum<{
328
+ audio: "audio";
329
+ hdmi: "hdmi";
330
+ uvc_h264: "uvc_h264";
331
+ uvc_h265: "uvc_h265";
332
+ mjpeg: "mjpeg";
333
+ camlink: "camlink";
334
+ test: "test";
335
+ network: "network";
336
+ }>>;
226
337
  }, z.core.$strip>;
227
338
  }, z.core.$strip>, z.ZodObject<{
228
339
  type: z.ZodLiteral<"bitrate">;
@@ -276,6 +387,18 @@ export declare const eventSchemas: {
276
387
  }>;
277
388
  streaming: z.ZodBoolean;
278
389
  active_input: z.ZodOptional<z.ZodString>;
390
+ active_profile: z.ZodOptional<z.ZodString>;
391
+ buffering: z.ZodOptional<z.ZodBoolean>;
392
+ spooled_bytes: z.ZodOptional<z.ZodNumber>;
393
+ data_headroom_bytes: z.ZodOptional<z.ZodNumber>;
394
+ disk_warning: z.ZodOptional<z.ZodBoolean>;
395
+ active_encode: z.ZodOptional<z.ZodObject<{
396
+ codec: z.ZodString;
397
+ resolution: z.ZodString;
398
+ framerate: z.ZodNumber;
399
+ active_input: z.ZodOptional<z.ZodString>;
400
+ decoder: z.ZodOptional<z.ZodString>;
401
+ }, z.core.$strip>>;
279
402
  }, z.core.$strip>;
280
403
  readonly switch: z.ZodObject<{
281
404
  type: z.ZodLiteral<"switch">;
@@ -312,6 +435,16 @@ export declare const eventSchemas: {
312
435
  framerate: z.ZodOptional<z.ZodString>;
313
436
  media_type: z.ZodOptional<z.ZodString>;
314
437
  }, z.core.$strip>>>;
438
+ kind: z.ZodOptional<z.ZodEnum<{
439
+ audio: "audio";
440
+ hdmi: "hdmi";
441
+ uvc_h264: "uvc_h264";
442
+ uvc_h265: "uvc_h265";
443
+ mjpeg: "mjpeg";
444
+ camlink: "camlink";
445
+ test: "test";
446
+ network: "network";
447
+ }>>;
315
448
  }, z.core.$strip>;
316
449
  }, z.core.$strip>;
317
450
  readonly bitrate: z.ZodObject<{
package/dist/events.js CHANGED
@@ -5,16 +5,48 @@ import { captureDeviceSchema, inputModeSchema, mediaClassSchema, streamStateSche
5
5
  // (schema.md "Events"). Each event is the inner `params` of an rpcEventSchema:
6
6
  // { type, seq, … }. `type` discriminates; `seq` is a per-type monotonic counter.
7
7
  const seq = z.number().int().nonnegative();
8
- // status — stream state change + heartbeat
8
+ /**
9
+ * The engine's RESOLVED runtime encode state (0.4.0, additive), reported on the
10
+ * `status` event as `active_encode`. Engine = reporter of record: this is the
11
+ * encode actually running (realized graph), not the requested params. `decoder`
12
+ * names the runtime-selected decode element for a compressed capture. Absent on a
13
+ * legacy emitter or a bare state-only heartbeat.
14
+ */
15
+ export const activeEncodeSchema = z.object({
16
+ codec: z.string(), // egress codec actually encoding, e.g. "h264"/"h265"
17
+ resolution: z.string(), // "WxH" pixels in effect, e.g. "1920x1080"
18
+ framerate: z.number(), // fps in effect, e.g. 29.97
19
+ active_input: z.string().optional(), // active input id feeding the encode
20
+ decoder: z.string().optional(), // runtime-selected decode element when transcoding
21
+ });
22
+ /**
23
+ * `status` event — stream state change + heartbeat. The trailing fields are
24
+ * additive: the `buffering*` / `spooled_bytes` / `data_headroom_bytes` /
25
+ * `disk_warning` egress-spool telemetry (Task 32) is absent on a plain heartbeat
26
+ * and present only on a spool engage/drain transition or disk-usage warning;
27
+ * `active_profile` (srt-receive-profiles) reports the profile/config the stream is
28
+ * running under and is absent on a legacy emitter or a bare state-only heartbeat;
29
+ * `active_encode` (0.4.0) reports the resolved runtime encode and is absent on a
30
+ * legacy emitter or a bare state-only heartbeat.
31
+ */
9
32
  export const statusEventSchema = z.object({
10
33
  type: z.literal("status"),
11
34
  seq,
12
35
  state: streamStateSchema,
13
36
  streaming: z.boolean(),
14
37
  active_input: z.string().optional(),
38
+ active_profile: z.string().optional(),
39
+ buffering: z.boolean().optional(),
40
+ spooled_bytes: z.number().int().nonnegative().optional(),
41
+ data_headroom_bytes: z.number().int().nonnegative().optional(),
42
+ disk_warning: z.boolean().optional(),
43
+ active_encode: activeEncodeSchema.optional(),
15
44
  });
16
- // switch — active input changed (manual or failover). media_class is additive
17
- // (absent on legacy video-only emitters); switch-audio sets it to "audio".
45
+ /**
46
+ * `switch` event active input changed (manual or failover). `media_class` is
47
+ * additive (absent on legacy video-only emitters); `switch-audio` sets it to
48
+ * `"audio"`.
49
+ */
18
50
  export const switchEventSchema = z.object({
19
51
  type: z.literal("switch"),
20
52
  seq,
@@ -23,21 +55,21 @@ export const switchEventSchema = z.object({
23
55
  reason: z.string().optional(),
24
56
  media_class: mediaClassSchema.optional(),
25
57
  });
26
- // device — GstDeviceMonitor hotplug
58
+ /** `device` event a GstDeviceMonitor hotplug add/remove. */
27
59
  export const deviceEventSchema = z.object({
28
60
  type: z.literal("device"),
29
61
  seq,
30
62
  change: z.enum(["added", "removed"]),
31
63
  device: captureDeviceSchema,
32
64
  });
33
- // bitrate — adaptive controller adjusted encode bitrate
65
+ /** `bitrate` event the adaptive controller adjusted the encode bitrate. */
34
66
  export const bitrateEventSchema = z.object({
35
67
  type: z.literal("bitrate"),
36
68
  seq,
37
69
  current_bitrate: z.number().int(),
38
70
  max_bitrate: z.number().int(),
39
71
  });
40
- // srt-stats — periodic transport stats
72
+ /** `srt-stats` event — periodic SRT transport telemetry. */
41
73
  export const srtStatsEventSchema = z.object({
42
74
  type: z.literal("srt-stats"),
43
75
  seq,
@@ -45,8 +77,10 @@ export const srtStatsEventSchema = z.object({
45
77
  send_buffer: z.number().int(),
46
78
  pkt_loss: z.number(),
47
79
  });
48
- // error — runtime error (replaces stderr scraping). Tier 2 code; engine reports
49
- // facts, CeraUI decides what to show (suppressIfSrtlaNotified is a client policy).
80
+ /**
81
+ * `error` event a runtime error (replaces stderr scraping). Carries a Tier-2
82
+ * code; the engine reports facts and CeraUI decides what to surface.
83
+ */
50
84
  export const runtimeErrorEventSchema = z.object({
51
85
  type: z.literal("error"),
52
86
  seq,
@@ -54,7 +88,7 @@ export const runtimeErrorEventSchema = z.object({
54
88
  source: processErrorSourceSchema,
55
89
  reason: z.string().optional(), // structured replacement for the stderr <reason>
56
90
  });
57
- // preview — preview session lifecycle
91
+ /** `preview` event a preview-session lifecycle/phase change. */
58
92
  export const previewEventSchema = z.object({
59
93
  type: z.literal("preview"),
60
94
  seq,
@@ -6,7 +6,10 @@ export declare const startParamsSchema: z.ZodObject<{
6
6
  port: z.ZodNumber;
7
7
  streamid: z.ZodOptional<z.ZodString>;
8
8
  latency_ms: z.ZodNumber;
9
+ latency_max_ms: z.ZodOptional<z.ZodNumber>;
9
10
  reduced_packet_size: z.ZodOptional<z.ZodBoolean>;
11
+ fec: z.ZodOptional<z.ZodString>;
12
+ receiver_supports_fec: z.ZodOptional<z.ZodBoolean>;
10
13
  }, z.core.$strip>;
11
14
  bitrate: z.ZodObject<{
12
15
  min_bitrate: z.ZodNumber;
@@ -18,6 +21,17 @@ export declare const startParamsSchema: z.ZodObject<{
18
21
  }>>;
19
22
  }, z.core.$strip>;
20
23
  input_id: z.ZodOptional<z.ZodString>;
24
+ codec: z.ZodOptional<z.ZodEnum<{
25
+ h264: "h264";
26
+ h265: "h265";
27
+ }>>;
28
+ resolution: z.ZodOptional<z.ZodString>;
29
+ framerate: z.ZodOptional<z.ZodNumber>;
30
+ audio: z.ZodOptional<z.ZodObject<{
31
+ device: z.ZodOptional<z.ZodString>;
32
+ codec: z.ZodOptional<z.ZodString>;
33
+ delay_ms: z.ZodOptional<z.ZodNumber>;
34
+ }, z.core.$strip>>;
21
35
  }, z.core.$strip>;
22
36
  export type StartParams = z.infer<typeof startParamsSchema>;
23
37
  export declare const startResultSchema: z.ZodObject<{
@@ -58,6 +72,7 @@ export declare const reloadConfigParamsSchema: z.ZodObject<{
58
72
  }, z.core.$strip>>;
59
73
  audio: z.ZodOptional<z.ZodObject<{
60
74
  delay_ms: z.ZodOptional<z.ZodNumber>;
75
+ delay_ms_signed: z.ZodOptional<z.ZodNumber>;
61
76
  }, z.core.$strip>>;
62
77
  }, z.core.$strip>;
63
78
  export type ReloadConfigParams = z.infer<typeof reloadConfigParamsSchema>;
@@ -77,6 +92,7 @@ export declare const reloadConfigResultSchema: z.ZodObject<{
77
92
  }, z.core.$strip>>;
78
93
  audio: z.ZodOptional<z.ZodObject<{
79
94
  delay_ms: z.ZodOptional<z.ZodNumber>;
95
+ delay_ms_signed: z.ZodOptional<z.ZodNumber>;
80
96
  }, z.core.$strip>>;
81
97
  }, z.core.$strip>;
82
98
  }, z.core.$strip>;
@@ -145,15 +161,25 @@ export declare const listDevicesResultSchema: z.ZodObject<{
145
161
  framerate: z.ZodOptional<z.ZodString>;
146
162
  media_type: z.ZodOptional<z.ZodString>;
147
163
  }, z.core.$strip>>>;
164
+ kind: z.ZodOptional<z.ZodEnum<{
165
+ audio: "audio";
166
+ hdmi: "hdmi";
167
+ uvc_h264: "uvc_h264";
168
+ uvc_h265: "uvc_h265";
169
+ mjpeg: "mjpeg";
170
+ camlink: "camlink";
171
+ test: "test";
172
+ network: "network";
173
+ }>>;
148
174
  }, z.core.$strip>>;
149
175
  }, z.core.$strip>;
150
176
  export type ListDevicesResult = z.infer<typeof listDevicesResultSchema>;
151
177
  export declare const eventTopicSchema: z.ZodEnum<{
152
178
  error: "error";
179
+ device: "device";
153
180
  bitrate: "bitrate";
154
181
  status: "status";
155
182
  switch: "switch";
156
- device: "device";
157
183
  "srt-stats": "srt-stats";
158
184
  preview: "preview";
159
185
  }>;
@@ -161,10 +187,10 @@ export type EventTopic = z.infer<typeof eventTopicSchema>;
161
187
  export declare const subscribeEventsParamsSchema: z.ZodObject<{
162
188
  topics: z.ZodOptional<z.ZodArray<z.ZodEnum<{
163
189
  error: "error";
190
+ device: "device";
164
191
  bitrate: "bitrate";
165
192
  status: "status";
166
193
  switch: "switch";
167
- device: "device";
168
194
  "srt-stats": "srt-stats";
169
195
  preview: "preview";
170
196
  }>>>;
@@ -173,10 +199,10 @@ export type SubscribeEventsParams = z.infer<typeof subscribeEventsParamsSchema>;
173
199
  export declare const subscribeEventsResultSchema: z.ZodObject<{
174
200
  subscribed: z.ZodArray<z.ZodEnum<{
175
201
  error: "error";
202
+ device: "device";
176
203
  bitrate: "bitrate";
177
204
  status: "status";
178
205
  switch: "switch";
179
- device: "device";
180
206
  "srt-stats": "srt-stats";
181
207
  preview: "preview";
182
208
  }>>;
@@ -228,6 +254,12 @@ export declare const bitrateRangeCapsSchema: z.ZodObject<{
228
254
  unit: z.ZodString;
229
255
  }, z.core.$strip>;
230
256
  export type BitrateRangeCaps = z.infer<typeof bitrateRangeCapsSchema>;
257
+ export declare const latencyRangeCapsSchema: z.ZodObject<{
258
+ min: z.ZodNumber;
259
+ default: z.ZodNumber;
260
+ max: z.ZodNumber;
261
+ }, z.core.$strip>;
262
+ export type LatencyRangeCaps = z.infer<typeof latencyRangeCapsSchema>;
231
263
  export declare const encoderCapsSchema: z.ZodObject<{
232
264
  codecs: z.ZodArray<z.ZodString>;
233
265
  bitrate_range: z.ZodObject<{
@@ -243,6 +275,12 @@ export declare const platformCapsSchema: z.ZodObject<{
243
275
  max_resolution: z.ZodString;
244
276
  }, z.core.$strip>;
245
277
  export type PlatformCaps = z.infer<typeof platformCapsSchema>;
278
+ export declare const previewAvailabilitySchema: z.ZodObject<{
279
+ enabled: z.ZodBoolean;
280
+ port: z.ZodOptional<z.ZodNumber>;
281
+ bound: z.ZodBoolean;
282
+ }, z.core.$strip>;
283
+ export type PreviewAvailability = z.infer<typeof previewAvailabilitySchema>;
246
284
  export declare const getCapabilitiesResultSchema: z.ZodObject<{
247
285
  platform: z.ZodObject<{
248
286
  supports_h265: z.ZodBoolean;
@@ -266,6 +304,19 @@ export declare const getCapabilitiesResultSchema: z.ZodObject<{
266
304
  default_framerate: z.ZodNumber;
267
305
  }, z.core.$strip>>;
268
306
  audio_live_switch: z.ZodOptional<z.ZodBoolean>;
307
+ latency_range: z.ZodOptional<z.ZodObject<{
308
+ min: z.ZodNumber;
309
+ default: z.ZodNumber;
310
+ max: z.ZodNumber;
311
+ }, z.core.$strip>>;
312
+ fec_capable: z.ZodOptional<z.ZodBoolean>;
313
+ supported_profiles: z.ZodOptional<z.ZodArray<z.ZodString>>;
314
+ profile_catalog_version: z.ZodOptional<z.ZodString>;
315
+ preview: z.ZodOptional<z.ZodObject<{
316
+ enabled: z.ZodBoolean;
317
+ port: z.ZodOptional<z.ZodNumber>;
318
+ bound: z.ZodBoolean;
319
+ }, z.core.$strip>>;
269
320
  }, z.core.$strip>;
270
321
  export type GetCapabilitiesResult = z.infer<typeof getCapabilitiesResultSchema>;
271
322
  /** The eight v1 control methods (the literal JSON-RPC `method` strings). */
@@ -296,7 +347,10 @@ export declare const requestSchemas: {
296
347
  port: z.ZodNumber;
297
348
  streamid: z.ZodOptional<z.ZodString>;
298
349
  latency_ms: z.ZodNumber;
350
+ latency_max_ms: z.ZodOptional<z.ZodNumber>;
299
351
  reduced_packet_size: z.ZodOptional<z.ZodBoolean>;
352
+ fec: z.ZodOptional<z.ZodString>;
353
+ receiver_supports_fec: z.ZodOptional<z.ZodBoolean>;
300
354
  }, z.core.$strip>;
301
355
  bitrate: z.ZodObject<{
302
356
  min_bitrate: z.ZodNumber;
@@ -308,6 +362,17 @@ export declare const requestSchemas: {
308
362
  }>>;
309
363
  }, z.core.$strip>;
310
364
  input_id: z.ZodOptional<z.ZodString>;
365
+ codec: z.ZodOptional<z.ZodEnum<{
366
+ h264: "h264";
367
+ h265: "h265";
368
+ }>>;
369
+ resolution: z.ZodOptional<z.ZodString>;
370
+ framerate: z.ZodOptional<z.ZodNumber>;
371
+ audio: z.ZodOptional<z.ZodObject<{
372
+ device: z.ZodOptional<z.ZodString>;
373
+ codec: z.ZodOptional<z.ZodString>;
374
+ delay_ms: z.ZodOptional<z.ZodNumber>;
375
+ }, z.core.$strip>>;
311
376
  }, z.core.$strip>;
312
377
  readonly result: z.ZodObject<{
313
378
  session_id: z.ZodString;
@@ -348,6 +413,7 @@ export declare const requestSchemas: {
348
413
  }, z.core.$strip>>;
349
414
  audio: z.ZodOptional<z.ZodObject<{
350
415
  delay_ms: z.ZodOptional<z.ZodNumber>;
416
+ delay_ms_signed: z.ZodOptional<z.ZodNumber>;
351
417
  }, z.core.$strip>>;
352
418
  }, z.core.$strip>;
353
419
  readonly result: z.ZodObject<{
@@ -366,6 +432,7 @@ export declare const requestSchemas: {
366
432
  }, z.core.$strip>>;
367
433
  audio: z.ZodOptional<z.ZodObject<{
368
434
  delay_ms: z.ZodOptional<z.ZodNumber>;
435
+ delay_ms_signed: z.ZodOptional<z.ZodNumber>;
369
436
  }, z.core.$strip>>;
370
437
  }, z.core.$strip>;
371
438
  }, z.core.$strip>;
@@ -418,6 +485,16 @@ export declare const requestSchemas: {
418
485
  framerate: z.ZodOptional<z.ZodString>;
419
486
  media_type: z.ZodOptional<z.ZodString>;
420
487
  }, z.core.$strip>>>;
488
+ kind: z.ZodOptional<z.ZodEnum<{
489
+ audio: "audio";
490
+ hdmi: "hdmi";
491
+ uvc_h264: "uvc_h264";
492
+ uvc_h265: "uvc_h265";
493
+ mjpeg: "mjpeg";
494
+ camlink: "camlink";
495
+ test: "test";
496
+ network: "network";
497
+ }>>;
421
498
  }, z.core.$strip>>;
422
499
  }, z.core.$strip>;
423
500
  };
@@ -425,10 +502,10 @@ export declare const requestSchemas: {
425
502
  readonly params: z.ZodObject<{
426
503
  topics: z.ZodOptional<z.ZodArray<z.ZodEnum<{
427
504
  error: "error";
505
+ device: "device";
428
506
  bitrate: "bitrate";
429
507
  status: "status";
430
508
  switch: "switch";
431
- device: "device";
432
509
  "srt-stats": "srt-stats";
433
510
  preview: "preview";
434
511
  }>>>;
@@ -436,10 +513,10 @@ export declare const requestSchemas: {
436
513
  readonly result: z.ZodObject<{
437
514
  subscribed: z.ZodArray<z.ZodEnum<{
438
515
  error: "error";
516
+ device: "device";
439
517
  bitrate: "bitrate";
440
518
  status: "status";
441
519
  switch: "switch";
442
- device: "device";
443
520
  "srt-stats": "srt-stats";
444
521
  preview: "preview";
445
522
  }>>;
package/dist/messages.js CHANGED
@@ -37,7 +37,8 @@ export const reloadConfigParamsSchema = z.object({
37
37
  .optional(),
38
38
  audio: z
39
39
  .object({
40
- delay_ms: z.number().int().min(0).max(AUDIO_DELAY_MAX_MS).optional(),
40
+ delay_ms: z.number().int().min(0).max(AUDIO_DELAY_MAX_MS).optional(), // legacy unsigned; kept for 0.3.0 callers
41
+ delay_ms_signed: z.number().int().optional(), // signed sibling; clamped at apply, so unbounded
41
42
  })
42
43
  .optional(),
43
44
  });
@@ -138,6 +139,13 @@ export const bitrateRangeCapsSchema = z.object({
138
139
  max: z.number().int(),
139
140
  unit: z.string(), // "bps" or "kbps"
140
141
  });
142
+ // SRT receive-latency range (ms) for the device-side latency slider. Continuous
143
+ // control (not discrete buckets): min/default/max bounds rendered by CeraUI.
144
+ export const latencyRangeCapsSchema = z.object({
145
+ min: z.number().int(),
146
+ default: z.number().int(),
147
+ max: z.number().int(),
148
+ });
141
149
  export const encoderCapsSchema = z.object({
142
150
  codecs: z.array(z.string()),
143
151
  bitrate_range: bitrateRangeCapsSchema,
@@ -147,11 +155,23 @@ export const platformCapsSchema = z.object({
147
155
  hardware_accelerated: z.boolean(),
148
156
  max_resolution: z.string(),
149
157
  });
158
+ // Preview-server availability (0.4.0, additive). Lets the UI tell an unbound /
159
+ // port-conflicted preview (enabled:true, bound:false) from a down engine.
160
+ export const previewAvailabilitySchema = z.object({
161
+ enabled: z.boolean(),
162
+ port: z.number().int().min(1).max(65535).optional(), // present when a listener is (or would be) bound
163
+ bound: z.boolean(),
164
+ });
150
165
  export const getCapabilitiesResultSchema = z.object({
151
166
  platform: platformCapsSchema,
152
167
  encoder: encoderCapsSchema,
153
168
  sources: z.array(videoSourceCapSchema),
154
169
  audio_live_switch: z.boolean().optional(),
170
+ latency_range: latencyRangeCapsSchema.optional(),
171
+ fec_capable: z.boolean().optional(), // engine can encode FEC on egress (SRTO_PACKETFILTER)
172
+ supported_profiles: z.array(z.string()).optional(), // SRT receive presets the device offers
173
+ profile_catalog_version: z.string().optional(), // semver of the supported_profiles catalog
174
+ preview: previewAvailabilitySchema.optional(), // preview-server availability (unbound vs down)
155
175
  });
156
176
  // ---- method registry (count-assertion source of truth) ----
157
177
  /** The eight v1 control methods (the literal JSON-RPC `method` strings). */
@@ -18,9 +18,18 @@ export declare class LineSocket {
18
18
  private handlers;
19
19
  private closed;
20
20
  constructor(socketPath: string);
21
- /** Connect to the socket and start framing. Rejects on a connect failure. */
21
+ /**
22
+ * Connect to the socket and start framing.
23
+ * @param handlers Line + close callbacks the client installs.
24
+ * @returns A promise that resolves once connected.
25
+ * @throws when the underlying `Bun.connect` fails (surfaced to the caller).
26
+ */
22
27
  open(handlers: LineSocketHandlers): Promise<void>;
23
- /** Write one NDJSON line (the trailing newline is added here). */
28
+ /**
29
+ * Write one NDJSON line (the trailing newline is added here).
30
+ * @param line One compact JSON value, without a trailing newline.
31
+ * @throws {Error} when the socket is already closed or not open.
32
+ */
24
33
  send(line: string): void;
25
34
  /** Close the connection. Idempotent; does not fire {@link LineSocketHandlers.onClose}. */
26
35
  close(): void;
package/dist/transport.js CHANGED
@@ -14,7 +14,12 @@ export class LineSocket {
14
14
  constructor(socketPath) {
15
15
  this.socketPath = socketPath;
16
16
  }
17
- /** Connect to the socket and start framing. Rejects on a connect failure. */
17
+ /**
18
+ * Connect to the socket and start framing.
19
+ * @param handlers Line + close callbacks the client installs.
20
+ * @returns A promise that resolves once connected.
21
+ * @throws when the underlying `Bun.connect` fails (surfaced to the caller).
22
+ */
18
23
  async open(handlers) {
19
24
  this.handlers = handlers;
20
25
  this.socket = await Bun.connect({
@@ -27,7 +32,11 @@ export class LineSocket {
27
32
  },
28
33
  });
29
34
  }
30
- /** Write one NDJSON line (the trailing newline is added here). */
35
+ /**
36
+ * Write one NDJSON line (the trailing newline is added here).
37
+ * @param line One compact JSON value, without a trailing newline.
38
+ * @throws {Error} when the socket is already closed or not open.
39
+ */
31
40
  send(line) {
32
41
  if (this.closed || !this.socket) {
33
42
  throw new Error("LineSocket.send: socket is not open");
package/dist/types.d.ts CHANGED
@@ -27,13 +27,32 @@ export declare const previewTierSchema: z.ZodEnum<{
27
27
  webrtc: "webrtc";
28
28
  }>;
29
29
  export type PreviewTier = z.infer<typeof previewTierSchema>;
30
+ export declare const videoCodecSchema: z.ZodEnum<{
31
+ h264: "h264";
32
+ h265: "h265";
33
+ }>;
34
+ export type VideoCodec = z.infer<typeof videoCodecSchema>;
35
+ export declare const captureDeviceKindSchema: z.ZodEnum<{
36
+ audio: "audio";
37
+ hdmi: "hdmi";
38
+ uvc_h264: "uvc_h264";
39
+ uvc_h265: "uvc_h265";
40
+ mjpeg: "mjpeg";
41
+ camlink: "camlink";
42
+ test: "test";
43
+ network: "network";
44
+ }>;
45
+ export type CaptureDeviceKind = z.infer<typeof captureDeviceKindSchema>;
30
46
  /** SRT transport config. Mirrors schema.md `start.srt` exactly. */
31
47
  export declare const srtConfigSchema: z.ZodObject<{
32
48
  host: z.ZodString;
33
49
  port: z.ZodNumber;
34
50
  streamid: z.ZodOptional<z.ZodString>;
35
51
  latency_ms: z.ZodNumber;
52
+ latency_max_ms: z.ZodOptional<z.ZodNumber>;
36
53
  reduced_packet_size: z.ZodOptional<z.ZodBoolean>;
54
+ fec: z.ZodOptional<z.ZodString>;
55
+ receiver_supports_fec: z.ZodOptional<z.ZodBoolean>;
37
56
  }, z.core.$strip>;
38
57
  export type SrtConfig = z.infer<typeof srtConfigSchema>;
39
58
  /** Bitrate / balancer config. Mirrors schema.md `start.bitrate` exactly. */
@@ -47,6 +66,19 @@ export declare const bitrateConfigSchema: z.ZodObject<{
47
66
  }>>;
48
67
  }, z.core.$strip>;
49
68
  export type BitrateConfig = z.infer<typeof bitrateConfigSchema>;
69
+ /**
70
+ * Audio config section of the unified engine config (0.4.0, additive). Every
71
+ * field is optional, so a legacy caller omits the whole `audio` section and a
72
+ * 0.3.0 engine ignores it. `delay_ms` is signed from birth (positive = audio
73
+ * later, negative = earlier); it is clamped to ±AUDIO_DELAY_MAX_MS when applied,
74
+ * never rejected — so the schema does NOT bound it.
75
+ */
76
+ export declare const audioConfigSchema: z.ZodObject<{
77
+ device: z.ZodOptional<z.ZodString>;
78
+ codec: z.ZodOptional<z.ZodString>;
79
+ delay_ms: z.ZodOptional<z.ZodNumber>;
80
+ }, z.core.$strip>;
81
+ export type AudioConfig = z.infer<typeof audioConfigSchema>;
50
82
  /**
51
83
  * Unified cerastream engine config — the complete shape needed to `start` a
52
84
  * stream and the canonical persisted profile. `start` params ARE this config
@@ -60,7 +92,10 @@ export declare const cerastreamConfigSchema: z.ZodObject<{
60
92
  port: z.ZodNumber;
61
93
  streamid: z.ZodOptional<z.ZodString>;
62
94
  latency_ms: z.ZodNumber;
95
+ latency_max_ms: z.ZodOptional<z.ZodNumber>;
63
96
  reduced_packet_size: z.ZodOptional<z.ZodBoolean>;
97
+ fec: z.ZodOptional<z.ZodString>;
98
+ receiver_supports_fec: z.ZodOptional<z.ZodBoolean>;
64
99
  }, z.core.$strip>;
65
100
  bitrate: z.ZodObject<{
66
101
  min_bitrate: z.ZodNumber;
@@ -72,6 +107,17 @@ export declare const cerastreamConfigSchema: z.ZodObject<{
72
107
  }>>;
73
108
  }, z.core.$strip>;
74
109
  input_id: z.ZodOptional<z.ZodString>;
110
+ codec: z.ZodOptional<z.ZodEnum<{
111
+ h264: "h264";
112
+ h265: "h265";
113
+ }>>;
114
+ resolution: z.ZodOptional<z.ZodString>;
115
+ framerate: z.ZodOptional<z.ZodNumber>;
116
+ audio: z.ZodOptional<z.ZodObject<{
117
+ device: z.ZodOptional<z.ZodString>;
118
+ codec: z.ZodOptional<z.ZodString>;
119
+ delay_ms: z.ZodOptional<z.ZodNumber>;
120
+ }, z.core.$strip>>;
75
121
  }, z.core.$strip>;
76
122
  export type CerastreamConfig = z.infer<typeof cerastreamConfigSchema>;
77
123
  export type PartialCerastreamConfig = z.input<typeof cerastreamConfigSchema>;
@@ -102,6 +148,16 @@ export declare const captureDeviceSchema: z.ZodObject<{
102
148
  framerate: z.ZodOptional<z.ZodString>;
103
149
  media_type: z.ZodOptional<z.ZodString>;
104
150
  }, z.core.$strip>>>;
151
+ kind: z.ZodOptional<z.ZodEnum<{
152
+ audio: "audio";
153
+ hdmi: "hdmi";
154
+ uvc_h264: "uvc_h264";
155
+ uvc_h265: "uvc_h265";
156
+ mjpeg: "mjpeg";
157
+ camlink: "camlink";
158
+ test: "test";
159
+ network: "network";
160
+ }>>;
105
161
  }, z.core.$strip>;
106
162
  export type CaptureDevice = z.infer<typeof captureDeviceSchema>;
107
163
  export declare const srtStatsSchema: z.ZodObject<{
package/dist/types.js CHANGED
@@ -14,20 +14,63 @@ export const inputModeSchema = z.enum(["manual", "auto"]);
14
14
  export const balancerAlgorithmSchema = z.enum(["adaptive", "fixed", "aimd"]);
15
15
  export const mediaClassSchema = z.enum(["video", "audio"]);
16
16
  export const previewTierSchema = z.enum(["webcodecs", "webrtc"]);
17
+ // Requested egress video codec (0.4.0, additive). Absent ⇒ the engine picks its
18
+ // platform default. Wire values are the codec id strings the encoder caps also
19
+ // advertise ("h264"/"h265") — never an encoder element name.
20
+ export const videoCodecSchema = z.enum(["h264", "h265"]);
21
+ // Engine-typed capture-device family (0.4.0, additive). CeraUI groups a device
22
+ // by the engine's resolved kind (a UVC/USB dongle is uvc_h264/mjpeg, never
23
+ // mislabeled HDMI). Absent ⇒ CeraUI falls back to a bus/name heuristic.
24
+ export const captureDeviceKindSchema = z.enum([
25
+ "hdmi",
26
+ "uvc_h264",
27
+ "uvc_h265",
28
+ "mjpeg",
29
+ "camlink",
30
+ "audio",
31
+ "test",
32
+ "network",
33
+ ]);
17
34
  // ---- config sub-schemas (canonical; reused by `start` + the unified config) ----
18
35
  /** SRT transport config. Mirrors schema.md `start.srt` exactly. */
19
36
  export const srtConfigSchema = z.object({
20
37
  host: z.string(),
21
38
  port: z.number().int().min(1).max(65535),
22
39
  streamid: z.string().optional(),
40
+ // Continuous device-side latency wired to SRTO_LATENCY, applied on (re)connect.
23
41
  latency_ms: z.number().int().min(100).max(10_000),
42
+ // Receiver-advertised ceiling; latency_ms is clamped to it. Additive/optional.
43
+ latency_max_ms: z.number().int().min(100).max(10_000).optional(),
24
44
  reduced_packet_size: z.boolean().optional(),
45
+ // SRT FEC packet-filter config (sender full config). Wired to SRTO_PACKETFILTER
46
+ // on (re)connect, but ONLY when receiver_supports_fec is true (G2). Additive.
47
+ fec: z.string().optional(),
48
+ // Receiver affirmatively known FEC-capable; gates `fec`. Additive (default off).
49
+ receiver_supports_fec: z.boolean().optional(),
25
50
  });
26
51
  /** Bitrate / balancer config. Mirrors schema.md `start.bitrate` exactly. */
27
- export const bitrateConfigSchema = z.object({
52
+ export const bitrateConfigSchema = z
53
+ .object({
28
54
  min_bitrate: z.number().int().min(1),
29
55
  max_bitrate: z.number().int().min(1),
30
56
  balancer: balancerAlgorithmSchema.default(DEFAULT_BALANCER),
57
+ })
58
+ // Mirrors the Rust dispatch guard: an inverted range can't drive the balancer.
59
+ .refine((b) => b.min_bitrate <= b.max_bitrate, {
60
+ message: "min_bitrate must not exceed max_bitrate",
61
+ path: ["min_bitrate"],
62
+ });
63
+ /**
64
+ * Audio config section of the unified engine config (0.4.0, additive). Every
65
+ * field is optional, so a legacy caller omits the whole `audio` section and a
66
+ * 0.3.0 engine ignores it. `delay_ms` is signed from birth (positive = audio
67
+ * later, negative = earlier); it is clamped to ±AUDIO_DELAY_MAX_MS when applied,
68
+ * never rejected — so the schema does NOT bound it.
69
+ */
70
+ export const audioConfigSchema = z.object({
71
+ device: z.string().optional(), // ALSA capture device id; absent ⇒ test-tone fallback
72
+ codec: z.string().optional(), // audio encoder codec id (e.g. "aac", "opus")
73
+ delay_ms: z.number().int().optional(), // signed A/V-sync delay (clamped at apply)
31
74
  });
32
75
  /**
33
76
  * Unified cerastream engine config — the complete shape needed to `start` a
@@ -40,6 +83,10 @@ export const cerastreamConfigSchema = z.object({
40
83
  srt: srtConfigSchema,
41
84
  bitrate: bitrateConfigSchema,
42
85
  input_id: z.string().optional(), // initial active input; defaults to primary
86
+ codec: videoCodecSchema.optional(), // additive (0.4.0): egress codec; absent ⇒ platform default
87
+ resolution: z.string().optional(), // additive (0.4.0): "WxH" pixel form (never a UI token)
88
+ framerate: z.number().optional(), // additive (0.4.0): fps as a number, e.g. 29.97
89
+ audio: audioConfigSchema.optional(), // additive (0.4.0): audio device/codec/signed delay
43
90
  });
44
91
  // convenience defaults for building a config client-side
45
92
  export const DEFAULT_BITRATE_CONFIG = {
@@ -61,6 +108,7 @@ export const captureDeviceSchema = z.object({
61
108
  display_name: z.string(),
62
109
  media_class: mediaClassSchema,
63
110
  caps: z.array(captureCapSchema).optional(),
111
+ kind: captureDeviceKindSchema.optional(), // additive (0.4.0): engine-typed device family; absent on legacy producers
64
112
  });
65
113
  // ---- transport telemetry (srt-stats event payload) ----
66
114
  export const srtStatsSchema = z.object({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ceralive/cerastream",
3
- "version": "2026.6.2",
3
+ "version": "2026.7.0",
4
4
  "description": "Type-safe TypeScript schema + IPC client for the cerastream streaming engine (JSON-RPC 2.0 / NDJSON over a Unix domain socket).",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",