@ceralive/cerastream 2026.7.6 → 2026.8.1

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
@@ -1,6 +1,6 @@
1
- import { type HelloResult } from "./envelope.js";
2
- import { type EventParams } from "./events.js";
3
- import { type ChangeConfigParams, type ChangeConfigResult, type GetCapabilitiesResult, type ListDevicesParams, type ListDevicesResult, type PreviewSessionParams, type PreviewSessionResult, type ReloadConfigParams, type ReloadConfigResult, type SetBitrateParams, type SetBitrateResult, type StartParams, type StartResult, type StopParams, type StopResult, type SubscribeEventsParams, type SubscribeEventsResult, type SwitchInputParams, type SwitchInputResult } from "./messages.js";
1
+ import { type HelloResult } from './envelope.js';
2
+ import { type EventParams } from './events.js';
3
+ import { type ChangeConfigParams, type ChangeConfigResult, type GetCapabilitiesResult, type ListDevicesParams, type ListDevicesResult, type PreviewSessionParams, type PreviewSessionResult, type ReloadConfigParams, type ReloadConfigResult, type SetBitrateParams, type SetBitrateResult, type StartParams, type StartResult, type StopParams, type StopResult, type SubscribeEventsParams, type SubscribeEventsResult, type SwitchInputParams, type SwitchInputResult } from './messages.js';
4
4
  /** Options for {@link connect}. All optional — `connect({})` is valid. */
5
5
  export interface ConnectOptions {
6
6
  /** Control socket path override. Defaults to the resolved /run/cerastream/control.sock. */
package/dist/client.js CHANGED
@@ -1,11 +1,11 @@
1
- import { CONTROL_SOCKET_PATH, PROTOCOL_VERSION } from "./constants.js";
2
- import { helloResultSchema, rpcErrorSchema, rpcResponseSchema, } from "./envelope.js";
3
- import { existsSync } from "node:fs";
4
- import { CerastreamConnectionError, CerastreamRpcError, CerastreamTimeoutError, } from "./errors.js";
5
- import { eventParamsSchema } from "./events.js";
6
- import { controlSocketPath } from "./paths.js";
7
- import { changeConfigParamsSchema, changeConfigResultSchema, getCapabilitiesResultSchema, requestSchemas, } from "./messages.js";
8
- import { LineSocket } from "./transport.js";
1
+ import { existsSync } from 'node:fs';
2
+ import { CONTROL_SOCKET_PATH, PROTOCOL_VERSION } from './constants.js';
3
+ import { helloResultSchema, rpcErrorSchema, rpcResponseSchema, } from './envelope.js';
4
+ import { CerastreamConnectionError, CerastreamRpcError, CerastreamTimeoutError, } from './errors.js';
5
+ import { eventParamsSchema } from './events.js';
6
+ import { changeConfigParamsSchema, changeConfigResultSchema, getCapabilitiesResultSchema, requestSchemas, } from './messages.js';
7
+ import { controlSocketPath } from './paths.js';
8
+ import { LineSocket } from './transport.js';
9
9
  const DEFAULTS = {
10
10
  requestTimeoutMs: 10_000,
11
11
  reconnectInitialDelayMs: 200,
@@ -26,16 +26,13 @@ class ClientImpl {
26
26
  reconnectInitialDelayMs;
27
27
  reconnectMaxDelayMs;
28
28
  constructor(options) {
29
- this.socketPath =
30
- options.socketPath ?? safeControlSocketPath();
31
- this.clientName = options.client ?? "@ceralive/cerastream";
32
- this.requestTimeoutMs =
33
- options.requestTimeoutMs ?? DEFAULTS.requestTimeoutMs;
29
+ this.socketPath = options.socketPath ?? safeControlSocketPath();
30
+ this.clientName = options.client ?? '@ceralive/cerastream';
31
+ this.requestTimeoutMs = options.requestTimeoutMs ?? DEFAULTS.requestTimeoutMs;
34
32
  this.autoReconnect = options.autoReconnect ?? false;
35
33
  this.reconnectInitialDelayMs =
36
34
  options.reconnectInitialDelayMs ?? DEFAULTS.reconnectInitialDelayMs;
37
- this.reconnectMaxDelayMs =
38
- options.reconnectMaxDelayMs ?? DEFAULTS.reconnectMaxDelayMs;
35
+ this.reconnectMaxDelayMs = options.reconnectMaxDelayMs ?? DEFAULTS.reconnectMaxDelayMs;
39
36
  }
40
37
  async init() {
41
38
  await this.openSocket();
@@ -55,41 +52,41 @@ class ClientImpl {
55
52
  this.socket = socket;
56
53
  }
57
54
  async handshake() {
58
- const raw = await this.rawRequest("hello", {
55
+ const raw = await this.rawRequest('hello', {
59
56
  protocol: PROTOCOL_VERSION,
60
57
  client: this.clientName,
61
58
  });
62
59
  return helloResultSchema.parse(raw);
63
60
  }
64
61
  start(params) {
65
- return this.call("start", params);
62
+ return this.call('start', params);
66
63
  }
67
64
  stop(params) {
68
- return this.call("stop", params);
65
+ return this.call('stop', params);
69
66
  }
70
67
  reloadConfig(params) {
71
- return this.call("reload-config", params);
68
+ return this.call('reload-config', params);
72
69
  }
73
70
  setBitrate(params) {
74
- return this.call("set-bitrate", params);
71
+ return this.call('set-bitrate', params);
75
72
  }
76
73
  switchInput(params) {
77
- return this.call("switch-input", params);
74
+ return this.call('switch-input', params);
78
75
  }
79
76
  listDevices(params) {
80
- return this.call("list-devices", params);
77
+ return this.call('list-devices', params);
81
78
  }
82
79
  async getCapabilities() {
83
- return getCapabilitiesResultSchema.parse(await this.rawRequest("get-capabilities", undefined));
80
+ return getCapabilitiesResultSchema.parse(await this.rawRequest('get-capabilities', undefined));
84
81
  }
85
82
  async changeConfig(params) {
86
- return changeConfigResultSchema.parse(await this.rawRequest("change-config", changeConfigParamsSchema.parse(params)));
83
+ return changeConfigResultSchema.parse(await this.rawRequest('change-config', changeConfigParamsSchema.parse(params)));
87
84
  }
88
85
  previewSession(params) {
89
- return this.call("preview-session", params);
86
+ return this.call('preview-session', params);
90
87
  }
91
88
  async subscribeEvents(params, handler) {
92
- const result = await this.call("subscribe-events", params);
89
+ const result = await this.call('subscribe-events', params);
93
90
  const sub = {
94
91
  result,
95
92
  handler,
@@ -105,7 +102,7 @@ class ClientImpl {
105
102
  this.intentionalClose = true;
106
103
  for (const sub of this.subscriptions)
107
104
  sub.close();
108
- const conn = new CerastreamConnectionError("client closed", undefined, "closed");
105
+ const conn = new CerastreamConnectionError('client closed', undefined, 'closed');
109
106
  this.rejectAllPending(conn);
110
107
  this.socket?.close();
111
108
  this.socket = undefined;
@@ -121,11 +118,11 @@ class ClientImpl {
121
118
  rawRequest(method, params) {
122
119
  const socket = this.socket;
123
120
  if (!socket) {
124
- return Promise.reject(new CerastreamConnectionError("control connection is not open", undefined, "closed"));
121
+ return Promise.reject(new CerastreamConnectionError('control connection is not open', undefined, 'closed'));
125
122
  }
126
123
  const id = this.nextId++;
127
124
  const envelope = {
128
- jsonrpc: "2.0",
125
+ jsonrpc: '2.0',
129
126
  id,
130
127
  method,
131
128
  };
@@ -143,7 +140,7 @@ class ClientImpl {
143
140
  catch (err) {
144
141
  clearTimeout(timer);
145
142
  this.pending.delete(id);
146
- reject(new CerastreamConnectionError("failed to write request", err, "lost"));
143
+ reject(new CerastreamConnectionError('failed to write request', err, 'lost'));
147
144
  }
148
145
  });
149
146
  }
@@ -157,18 +154,18 @@ class ClientImpl {
157
154
  }
158
155
  if (!isObject(msg))
159
156
  return;
160
- if (msg.method === "event") {
157
+ if (msg.method === 'event') {
161
158
  this.dispatchEvent(msg.params);
162
159
  return;
163
160
  }
164
- if (!("id" in msg))
161
+ if (!('id' in msg))
165
162
  return;
166
163
  const id = msg.id;
167
- if ("error" in msg) {
164
+ if ('error' in msg) {
168
165
  this.settleError(msg);
169
166
  return;
170
167
  }
171
- if ("result" in msg && id != null) {
168
+ if ('result' in msg && id != null) {
172
169
  const pending = this.pending.get(id);
173
170
  if (!pending)
174
171
  return;
@@ -210,7 +207,7 @@ class ClientImpl {
210
207
  this.socket = undefined;
211
208
  if (this.intentionalClose)
212
209
  return;
213
- const conn = new CerastreamConnectionError("control connection lost", err, "lost");
210
+ const conn = new CerastreamConnectionError('control connection lost', err, 'lost');
214
211
  this.rejectAllPending(conn);
215
212
  if (this.autoReconnect)
216
213
  void this.reconnectLoop();
@@ -253,7 +250,7 @@ class ClientImpl {
253
250
  topics.add(t);
254
251
  if (topics.size === 0)
255
252
  return;
256
- await this.rawRequest("subscribe-events", { topics: [...topics] });
253
+ await this.rawRequest('subscribe-events', { topics: [...topics] });
257
254
  }
258
255
  }
259
256
  function safeControlSocketPath() {
@@ -265,7 +262,7 @@ function safeControlSocketPath() {
265
262
  }
266
263
  }
267
264
  function isObject(value) {
268
- return typeof value === "object" && value !== null;
265
+ return typeof value === 'object' && value !== null;
269
266
  }
270
267
  // Classify a connect-time transport failure into a stable machine code. Bun's
271
268
  // `connect` collapses several distinct errors onto ENOENT and does not reliably
@@ -275,11 +272,11 @@ function isObject(value) {
275
272
  // won't accept is `refused` (a crashed/stale listener).
276
273
  function classifyConnectError(err, socketPath) {
277
274
  const raw = isObject(err) ? err.code : undefined;
278
- if (raw === "ECONNREFUSED")
279
- return "refused";
280
- if (raw === "EACCES" || raw === "EPERM")
281
- return "unreachable";
282
- return existsSync(socketPath) ? "refused" : "absent";
275
+ if (raw === 'ECONNREFUSED')
276
+ return 'refused';
277
+ if (raw === 'EACCES' || raw === 'EPERM')
278
+ return 'unreachable';
279
+ return existsSync(socketPath) ? 'refused' : 'absent';
283
280
  }
284
281
  function sleep(ms) {
285
282
  return new Promise((resolve) => setTimeout(resolve, ms));
package/dist/config.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type CerastreamConfig, type PartialCerastreamConfig } from "./types.js";
1
+ import { type CerastreamConfig, type PartialCerastreamConfig } from './types.js';
2
2
  /** Default on-device config path (systemd `StateDirectory=cerastream`). */
3
3
  export declare const DEFAULT_CONFIG_PATH = "/var/lib/cerastream/config.json";
4
4
  /** Validate and pretty-print a config to its canonical JSON form. */
package/dist/config.js CHANGED
@@ -1,11 +1,11 @@
1
- import { readFileSync, writeFileSync } from "node:fs";
2
- import { DEFAULT_BALANCER, DEFAULT_MAX_BITRATE, DEFAULT_MIN_BITRATE, DEFAULT_SRT_LATENCY, } from "./constants.js";
3
- import { cerastreamConfigSchema, } from "./types.js";
1
+ import { readFileSync, writeFileSync } from 'node:fs';
2
+ import { DEFAULT_BALANCER, DEFAULT_MAX_BITRATE, DEFAULT_MIN_BITRATE, DEFAULT_SRT_LATENCY, } from './constants.js';
3
+ import { cerastreamConfigSchema, } from './types.js';
4
4
  // Persisted-config helpers. The unified engine config IS the `start` params
5
5
  // (types.cerastreamConfigSchema), so a config written here is exactly what
6
6
  // `client.start()` accepts — wire shape and stored profile cannot drift.
7
7
  /** Default on-device config path (systemd `StateDirectory=cerastream`). */
8
- export const DEFAULT_CONFIG_PATH = "/var/lib/cerastream/config.json";
8
+ export const DEFAULT_CONFIG_PATH = '/var/lib/cerastream/config.json';
9
9
  /** Validate and pretty-print a config to its canonical JSON form. */
10
10
  export function serializeCerastreamConfig(config) {
11
11
  const parsed = cerastreamConfigSchema.parse(config);
@@ -18,7 +18,7 @@ export function writeCerastreamConfig(config, path = DEFAULT_CONFIG_PATH) {
18
18
  }
19
19
  /** Read + validate a config from disk. Throws on a missing file or bad shape. */
20
20
  export function readCerastreamConfig(path = DEFAULT_CONFIG_PATH) {
21
- return cerastreamConfigSchema.parse(JSON.parse(readFileSync(path, "utf8")));
21
+ return cerastreamConfigSchema.parse(JSON.parse(readFileSync(path, 'utf8')));
22
22
  }
23
23
  /**
24
24
  * Coerce a loose/legacy config object into a valid {@link CerastreamConfig},
@@ -27,8 +27,8 @@ export function readCerastreamConfig(path = DEFAULT_CONFIG_PATH) {
27
27
  * required `pipeline` + `srt.host`/`srt.port` cannot be recovered.
28
28
  */
29
29
  export function migrateCerastreamConfig(input) {
30
- if (typeof input !== "object" || input === null) {
31
- throw new TypeError("migrateCerastreamConfig: expected a config object");
30
+ if (typeof input !== 'object' || input === null) {
31
+ throw new TypeError('migrateCerastreamConfig: expected a config object');
32
32
  }
33
33
  const raw = input;
34
34
  const srt = asRecord(raw.srt);
@@ -48,7 +48,5 @@ export function migrateCerastreamConfig(input) {
48
48
  return cerastreamConfigSchema.parse(candidate);
49
49
  }
50
50
  function asRecord(value) {
51
- return typeof value === "object" && value !== null
52
- ? value
53
- : {};
51
+ return typeof value === 'object' && value !== null ? value : {};
54
52
  }
@@ -1,5 +1,5 @@
1
1
  /** JSON-RPC handshake protocol major. Bumped only on a breaking schema change. */
2
- export declare const PROTOCOL_VERSION: "cerastream-ipc/1";
2
+ export declare const PROTOCOL_VERSION: 'cerastream-ipc/1';
3
3
  /**
4
4
  * Wire-schema contract version, pinned cross-language with the Rust engine
5
5
  * (`crates/cerastream-ipc/src/constants.rs`) and the conformance fixtures. It
@@ -8,19 +8,19 @@ 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.11.0";
11
+ export declare const SCHEMA_VERSION: '0.11.0';
12
12
  /** Runtime dir holding both control + preview sockets. systemd `RuntimeDirectory=cerastream`. */
13
- export declare const DEFAULT_IPC_DIR: "/run/cerastream";
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}. */
15
- export declare const IPC_DIR_ENV: "CERASTREAM_IPC_DIR";
15
+ export declare const IPC_DIR_ENV: 'CERASTREAM_IPC_DIR';
16
16
  /** Control-plane socket basename (JSON-RPC 2.0 / NDJSON). */
17
- export declare const CONTROL_SOCKET_NAME: "control.sock";
17
+ export declare const CONTROL_SOCKET_NAME: 'control.sock';
18
18
  /** Preview socket basename (length-prefixed binary frames). */
19
- export declare const PREVIEW_SOCKET_NAME: "preview.sock";
19
+ export declare const PREVIEW_SOCKET_NAME: 'preview.sock';
20
20
  /** Default control-plane socket path. */
21
- export declare const CONTROL_SOCKET_PATH: "/run/cerastream/control.sock";
21
+ export declare const CONTROL_SOCKET_PATH: '/run/cerastream/control.sock';
22
22
  /** Default binary preview socket path. */
23
- export declare const PREVIEW_SOCKET_PATH: "/run/cerastream/preview.sock";
23
+ export declare const PREVIEW_SOCKET_PATH: '/run/cerastream/preview.sock';
24
24
  /** Per-line framing cap (ADR-0002 §1): an oversized line is a fatal protocol error. */
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`. */
@@ -42,31 +42,44 @@ export declare const LATENCY_MAX_MS = 5000;
42
42
  * applies it to `SRTO_PACKETFILTER` ONLY against a known FEC-capable receiver.
43
43
  * Mirrors the Rust `DEFAULT_FEC_CONFIG`.
44
44
  */
45
- export declare const DEFAULT_FEC_CONFIG: "fec,layout:staircase,rows:10,cols:10,arq:onreq";
45
+ export declare const DEFAULT_FEC_CONFIG: 'fec,layout:staircase,rows:10,cols:10,arq:onreq';
46
46
  /**
47
47
  * The v1 SRT receive-profile catalog: the preset ids `get-capabilities`
48
48
  * advertises in `supported_profiles`. A profile is a named preset CeraUI expands
49
49
  * to an SRT/bitrate config; the resolver and the Stream Tuning card read this list
50
50
  * to gate which presets the device offers. Mirrors the Rust `SUPPORTED_PROFILES`.
51
51
  */
52
- export declare const SUPPORTED_PROFILES: readonly ["balanced", "low-latency", "resilient", "classic", "low-latency-fec"];
52
+ export declare const SUPPORTED_PROFILES: readonly ['balanced', 'low-latency', 'resilient', 'classic', 'low-latency-fec'];
53
53
  /**
54
54
  * Version of the profile catalog {@link SUPPORTED_PROFILES} comes from (semver),
55
55
  * echoed by `get-capabilities` as `profile_catalog_version`. Bumped when the preset
56
56
  * set or any preset's meaning changes. Mirrors the Rust `PROFILE_CATALOG_VERSION`.
57
57
  */
58
- export declare const PROFILE_CATALOG_VERSION: "1.0.0";
58
+ export declare const PROFILE_CATALOG_VERSION: '1.0.0';
59
+ /**
60
+ * PipeWire-backed audio capture: the engine addresses capture nodes by
61
+ * `node.name`/`object.serial`, so a source with no ALSA card — a Bluetooth
62
+ * microphone is the first one — is selectable as an ordinary node. Unlike the
63
+ * other tokens this one describes the engine's RUNNING configuration, so an
64
+ * engine configured for ALSA omits it even though this catalog lists it. Mirrors
65
+ * the Rust `PIPEWIRE_CAPTURE_FEATURE`.
66
+ */
67
+ export declare const PIPEWIRE_CAPTURE_FEATURE: 'pipewire-capture';
59
68
  /**
60
69
  * Named engine features `get-capabilities` advertises in `features`. This is the
61
70
  * fail-closed negotiation contract: CeraUI sends a new out-of-schema field ONLY
62
71
  * when its feature is listed, so an engine that predates a feature (and silently
63
72
  * ignores the field) never applies a semantic the caller assumed. Mirrors the
64
73
  * Rust `ENGINE_FEATURES`.
74
+ *
75
+ * This is the full CATALOG. Gate on the token in the engine's own `features`
76
+ * array, never on membership here — a configuration-dependent token is filtered
77
+ * out of the response the engine actually sends.
65
78
  */
66
- export declare const ENGINE_FEATURES: readonly ["video-passthrough", "input-mode"];
79
+ export declare const ENGINE_FEATURES: readonly ['video-passthrough', 'input-mode', 'audio-pcm-spec', "pipewire-capture"];
67
80
  /** Engine binary name (systemd-owned; CeraUI never spawns it — ADR-0005). */
68
- export declare const CERASTREAM_BIN: "cerastream";
81
+ export declare const CERASTREAM_BIN: 'cerastream';
69
82
  export declare const DEFAULT_MIN_BITRATE = 300;
70
83
  export declare const DEFAULT_MAX_BITRATE = 6000;
71
84
  export declare const DEFAULT_SRT_LATENCY = 2000;
72
- export declare const DEFAULT_BALANCER: "adaptive";
85
+ export declare const DEFAULT_BALANCER: 'adaptive';
package/dist/constants.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // These are CONTRACT values (ADR-0002 / schema.md), not implementation logic —
3
3
  // they are the stable wire/runtime literals every consumer derives from.
4
4
  /** JSON-RPC handshake protocol major. Bumped only on a breaking schema change. */
5
- export const PROTOCOL_VERSION = "cerastream-ipc/1";
5
+ export const PROTOCOL_VERSION = 'cerastream-ipc/1';
6
6
  /**
7
7
  * Wire-schema contract version, pinned cross-language with the Rust engine
8
8
  * (`crates/cerastream-ipc/src/constants.rs`) and the conformance fixtures. It
@@ -11,19 +11,19 @@ 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.11.0";
14
+ export const SCHEMA_VERSION = '0.11.0';
15
15
  /** Runtime dir holding both control + preview sockets. systemd `RuntimeDirectory=cerastream`. */
16
- export const DEFAULT_IPC_DIR = "/run/cerastream";
16
+ export const DEFAULT_IPC_DIR = '/run/cerastream';
17
17
  /** Env override for the IPC dir (tests/dev). Defaults to {@link DEFAULT_IPC_DIR}. */
18
- export const IPC_DIR_ENV = "CERASTREAM_IPC_DIR";
18
+ export const IPC_DIR_ENV = 'CERASTREAM_IPC_DIR';
19
19
  /** Control-plane socket basename (JSON-RPC 2.0 / NDJSON). */
20
- export const CONTROL_SOCKET_NAME = "control.sock";
20
+ export const CONTROL_SOCKET_NAME = 'control.sock';
21
21
  /** Preview socket basename (length-prefixed binary frames). */
22
- export const PREVIEW_SOCKET_NAME = "preview.sock";
22
+ export const PREVIEW_SOCKET_NAME = 'preview.sock';
23
23
  /** Default control-plane socket path. */
24
- export const CONTROL_SOCKET_PATH = "/run/cerastream/control.sock";
24
+ export const CONTROL_SOCKET_PATH = '/run/cerastream/control.sock';
25
25
  /** Default binary preview socket path. */
26
- export const PREVIEW_SOCKET_PATH = "/run/cerastream/preview.sock";
26
+ export const PREVIEW_SOCKET_PATH = '/run/cerastream/preview.sock';
27
27
  /** Per-line framing cap (ADR-0002 §1): an oversized line is a fatal protocol error. */
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`. */
@@ -45,7 +45,7 @@ export const LATENCY_MAX_MS = 5000;
45
45
  * applies it to `SRTO_PACKETFILTER` ONLY against a known FEC-capable receiver.
46
46
  * Mirrors the Rust `DEFAULT_FEC_CONFIG`.
47
47
  */
48
- export const DEFAULT_FEC_CONFIG = "fec,layout:staircase,rows:10,cols:10,arq:onreq";
48
+ export const DEFAULT_FEC_CONFIG = 'fec,layout:staircase,rows:10,cols:10,arq:onreq';
49
49
  /**
50
50
  * The v1 SRT receive-profile catalog: the preset ids `get-capabilities`
51
51
  * advertises in `supported_profiles`. A profile is a named preset CeraUI expands
@@ -53,30 +53,48 @@ export const DEFAULT_FEC_CONFIG = "fec,layout:staircase,rows:10,cols:10,arq:onre
53
53
  * to gate which presets the device offers. Mirrors the Rust `SUPPORTED_PROFILES`.
54
54
  */
55
55
  export const SUPPORTED_PROFILES = [
56
- "balanced",
57
- "low-latency",
58
- "resilient",
59
- "classic",
60
- "low-latency-fec",
56
+ 'balanced',
57
+ 'low-latency',
58
+ 'resilient',
59
+ 'classic',
60
+ 'low-latency-fec',
61
61
  ];
62
62
  /**
63
63
  * Version of the profile catalog {@link SUPPORTED_PROFILES} comes from (semver),
64
64
  * echoed by `get-capabilities` as `profile_catalog_version`. Bumped when the preset
65
65
  * set or any preset's meaning changes. Mirrors the Rust `PROFILE_CATALOG_VERSION`.
66
66
  */
67
- export const PROFILE_CATALOG_VERSION = "1.0.0";
67
+ export const PROFILE_CATALOG_VERSION = '1.0.0';
68
+ /**
69
+ * PipeWire-backed audio capture: the engine addresses capture nodes by
70
+ * `node.name`/`object.serial`, so a source with no ALSA card — a Bluetooth
71
+ * microphone is the first one — is selectable as an ordinary node. Unlike the
72
+ * other tokens this one describes the engine's RUNNING configuration, so an
73
+ * engine configured for ALSA omits it even though this catalog lists it. Mirrors
74
+ * the Rust `PIPEWIRE_CAPTURE_FEATURE`.
75
+ */
76
+ export const PIPEWIRE_CAPTURE_FEATURE = 'pipewire-capture';
68
77
  /**
69
78
  * Named engine features `get-capabilities` advertises in `features`. This is the
70
79
  * fail-closed negotiation contract: CeraUI sends a new out-of-schema field ONLY
71
80
  * when its feature is listed, so an engine that predates a feature (and silently
72
81
  * ignores the field) never applies a semantic the caller assumed. Mirrors the
73
82
  * Rust `ENGINE_FEATURES`.
83
+ *
84
+ * This is the full CATALOG. Gate on the token in the engine's own `features`
85
+ * array, never on membership here — a configuration-dependent token is filtered
86
+ * out of the response the engine actually sends.
74
87
  */
75
- export const ENGINE_FEATURES = ["video-passthrough", "input-mode"];
88
+ export const ENGINE_FEATURES = [
89
+ 'video-passthrough',
90
+ 'input-mode',
91
+ 'audio-pcm-spec',
92
+ PIPEWIRE_CAPTURE_FEATURE,
93
+ ];
76
94
  /** Engine binary name (systemd-owned; CeraUI never spawns it — ADR-0005). */
77
- export const CERASTREAM_BIN = "cerastream";
95
+ export const CERASTREAM_BIN = 'cerastream';
78
96
  // ---- config defaults (mirror ceracoder, the engine being replaced) ----
79
97
  export const DEFAULT_MIN_BITRATE = 300; // kbps
80
98
  export const DEFAULT_MAX_BITRATE = 6000; // kbps
81
99
  export const DEFAULT_SRT_LATENCY = 2000; // ms
82
- export const DEFAULT_BALANCER = "adaptive";
100
+ export const DEFAULT_BALANCER = 'adaptive';
@@ -1,4 +1,4 @@
1
- import { z } from "zod";
1
+ import { z } from 'zod';
2
2
  export declare const jsonrpcVersion: z.ZodLiteral<"2.0">;
3
3
  export declare const requestId: z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>;
4
4
  export type RequestId = z.infer<typeof requestId>;
package/dist/envelope.js CHANGED
@@ -1,9 +1,9 @@
1
- import { z } from "zod";
2
- import { PROTOCOL_VERSION } from "./constants.js";
1
+ import { z } from 'zod';
2
+ import { PROTOCOL_VERSION } from './constants.js';
3
3
  // JSON-RPC 2.0 envelope, newline-delimited over the control UDS (ADR-0002 §2,
4
4
  // schema.md "Envelope"). The JSON shape on the wire is the contract — not any
5
5
  // Rust serde type.
6
- export const jsonrpcVersion = z.literal("2.0");
6
+ export const jsonrpcVersion = z.literal('2.0');
7
7
  export const requestId = z.union([z.number().int(), z.string()]);
8
8
  // ---- request: client → server ----
9
9
  export const rpcRequestSchema = z.object({
@@ -32,7 +32,7 @@ export const rpcErrorSchema = z.object({
32
32
  // ---- event: server → client, no id ----
33
33
  export const rpcEventSchema = z.object({
34
34
  jsonrpc: jsonrpcVersion,
35
- method: z.literal("event"),
35
+ method: z.literal('event'),
36
36
  params: z
37
37
  .object({
38
38
  type: z.string(), // event type (see events.ts)
package/dist/errors.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { z } from "zod";
1
+ import { z } from 'zod';
2
2
  /**
3
3
  * Thrown by every contract-stub function body (Task 17). The schema in this
4
4
  * package is real and frozen; the IPC client/transport is implemented in Task 31.
@@ -43,7 +43,7 @@ export declare class CerastreamRpcError extends Error {
43
43
  * - `closed` — the client was closed, or a request was issued on a
44
44
  * not-open connection.
45
45
  */
46
- export declare const CERASTREAM_CONNECT_ERROR_CODES: readonly ["absent", "refused", "unreachable", "lost", "closed"];
46
+ export declare const CERASTREAM_CONNECT_ERROR_CODES: readonly ['absent', 'refused', 'unreachable', 'lost', 'closed'];
47
47
  export type CerastreamConnectErrorCode = (typeof CERASTREAM_CONNECT_ERROR_CODES)[number];
48
48
  /**
49
49
  * Thrown when the control connection is lost (socket closed/errored) while a
@@ -63,15 +63,15 @@ export declare class CerastreamTimeoutError extends Error {
63
63
  constructor(method: string, timeoutMs: number);
64
64
  }
65
65
  export declare const rpcErrorCodeSchema: z.ZodEnum<{
66
- "cerastream.protocol.unsupported_version": "cerastream.protocol.unsupported_version";
67
- "cerastream.params.invalid": "cerastream.params.invalid";
68
- "cerastream.state.not_streaming": "cerastream.state.not_streaming";
69
- "cerastream.state.already_streaming": "cerastream.state.already_streaming";
70
- "cerastream.device.not_found": "cerastream.device.not_found";
71
66
  "cerastream.audio.device_not_found": "cerastream.audio.device_not_found";
72
67
  "cerastream.bitrate.out_of_range": "cerastream.bitrate.out_of_range";
73
- "cerastream.preview.unsupported_tier": "cerastream.preview.unsupported_tier";
68
+ "cerastream.device.not_found": "cerastream.device.not_found";
74
69
  "cerastream.internal": "cerastream.internal";
70
+ "cerastream.params.invalid": "cerastream.params.invalid";
71
+ "cerastream.preview.unsupported_tier": "cerastream.preview.unsupported_tier";
72
+ "cerastream.protocol.unsupported_version": "cerastream.protocol.unsupported_version";
73
+ "cerastream.state.already_streaming": "cerastream.state.already_streaming";
74
+ "cerastream.state.not_streaming": "cerastream.state.not_streaming";
75
75
  }>;
76
76
  export type RpcErrorCode = z.infer<typeof rpcErrorCodeSchema>;
77
77
  /**
@@ -81,14 +81,14 @@ export type RpcErrorCode = z.infer<typeof rpcErrorCodeSchema>;
81
81
  */
82
82
  export declare const RPC_ERROR_NUMERIC: Readonly<Record<RpcErrorCode, number>>;
83
83
  export declare const processErrorCodeSchema: z.ZodEnum<{
84
- srtla_initial_connect_failed: "srtla_initial_connect_failed";
85
- srtla_no_connections: "srtla_no_connections";
86
84
  capture_audio_error: "capture_audio_error";
85
+ capture_unrecoverable: "capture_unrecoverable";
87
86
  capture_video_error: "capture_video_error";
88
87
  pipeline_stall: "pipeline_stall";
89
88
  srt_connect_failed: "srt_connect_failed";
90
89
  srt_connection_lost: "srt_connection_lost";
91
- capture_unrecoverable: "capture_unrecoverable";
90
+ srtla_initial_connect_failed: "srtla_initial_connect_failed";
91
+ srtla_no_connections: "srtla_no_connections";
92
92
  }>;
93
93
  export type ProcessErrorCode = z.infer<typeof processErrorCodeSchema>;
94
94
  /**
@@ -97,15 +97,15 @@ export type ProcessErrorCode = z.infer<typeof processErrorCodeSchema>;
97
97
  */
98
98
  export declare const captureUnrecoverableReasonSchema: z.ZodEnum<{
99
99
  node_absent_reprobe_disabled: "node_absent_reprobe_disabled";
100
- reprobe_no_reenumeration: "reprobe_no_reenumeration";
101
100
  reprobe_identity_changed: "reprobe_identity_changed";
101
+ reprobe_no_reenumeration: "reprobe_no_reenumeration";
102
102
  reprobe_node_still_absent: "reprobe_node_still_absent";
103
103
  reprobe_unavailable: "reprobe_unavailable";
104
104
  }>;
105
105
  export type CaptureUnrecoverableReason = z.infer<typeof captureUnrecoverableReasonSchema>;
106
106
  /** Origin of a Tier 2 runtime error (the notification channel CeraUI routes on). */
107
107
  export declare const processErrorSourceSchema: z.ZodEnum<{
108
- srtla: "srtla";
109
108
  engine: "engine";
109
+ srtla: "srtla";
110
110
  }>;
111
111
  export type ProcessErrorSource = z.infer<typeof processErrorSourceSchema>;