@sonara/client 0.32.12 → 0.32.13

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/README.md CHANGED
@@ -19,6 +19,7 @@ await sonara.close();
19
19
  - `control(action)`: `play`, `pause`, `toggle`, `stop`, `skip`, `previous`, `next`, `restart`, `mute`, `unmute`.
20
20
  - `set(key, value)` / `get(key)` for `volume` (0..100), `rate` (100..400 wpm), `voice`, `engine`; `voices(engine?)`.
21
21
  - `onState`, `onItem`, `onLog` return an unsubscribe function; events arrive on a second connection opened by the first listener. Every state listener, also one added later, gets the current state first. `onClose` fires when the runtime goes away.
22
+ - `request(type, fields, { timeoutMs })` sends any message; with `timeoutMs` it rejects with `E_TIMEOUT` and the client stays open (no bound by default; `engine_test` may take a minute). A request over 1 MiB of UTF-8 is refused with `E_BAD_REQUEST` and the client stays open.
22
23
  - `channels`, `agent`, `system`: extension namespaces that send the protocol's extension messages as they are.
23
24
  - Errors are `SonaraError` with a `code` (`E_BUSY`, `E_NOT_RUNNING`, ...).
24
25
 
@@ -1,7 +1,7 @@
1
1
  import { Connection } from "./connection.js";
2
2
  import { EnginesApi } from "./engines.js";
3
3
  import { AgentApi, ChannelsApi, SystemApi } from "./extensions.js";
4
- import type { ControlAction, HelloInfo, ItemEvent, LogEvent, Reply, RuntimeInfo, SettingKey, SpeakOptions, State, Voice } from "./types.js";
4
+ import type { ControlAction, HelloInfo, ItemEvent, LogEvent, Reply, RequestOptions, RuntimeInfo, SettingKey, SpeakOptions, State, Voice } from "./types.js";
5
5
  export type Unsubscribe = () => void;
6
6
  type Listener<T> = (value: T) => void;
7
7
  /** Opens and greets one more connection (the event connection). */
@@ -39,8 +39,11 @@ export declare class SonaraClient {
39
39
  constructor(conn: Connection, runtime: RuntimeInfo, info: HelloInfo, dial: Dial);
40
40
  /** True once the connection closed (close(), a takeover or the runtime exited). */
41
41
  get closed(): boolean;
42
- /** Send any protocol message; resolves with the `ok: true` reply. */
43
- request(type: string, fields?: Record<string, unknown>): Promise<Reply>;
42
+ /**
43
+ * Send any protocol message; resolves with the `ok: true` reply.
44
+ * `opts.timeoutMs` bounds this one request (`E_TIMEOUT`; default: none).
45
+ */
46
+ request(type: string, fields?: Record<string, unknown>, opts?: RequestOptions): Promise<Reply>;
44
47
  /** Add `text` as one item; resolves with its item id. */
45
48
  speak(text: string, opts?: SpeakOptions): Promise<number>;
46
49
  /**
@@ -40,9 +40,12 @@ class SonaraClient {
40
40
  get closed() {
41
41
  return this.conn.closed;
42
42
  }
43
- /** Send any protocol message; resolves with the `ok: true` reply. */
44
- request(type, fields = {}) {
45
- return this.conn.request(type, fields);
43
+ /**
44
+ * Send any protocol message; resolves with the `ok: true` reply.
45
+ * `opts.timeoutMs` bounds this one request (`E_TIMEOUT`; default: none).
46
+ */
47
+ request(type, fields = {}, opts = {}) {
48
+ return this.conn.request(type, fields, opts);
46
49
  }
47
50
  /** Add `text` as one item; resolves with its item id. */
48
51
  async speak(text, opts = {}) {
@@ -1,4 +1,6 @@
1
- import type { Reply } from "./types.js";
1
+ import type { Reply, RequestOptions } from "./types.js";
2
+ /** Longest line the runtime accepts (bytes, newline included); a longer one closes the connection. */
3
+ export declare const MAX_LINE: number;
2
4
  /**
3
5
  * One TCP JSON-lines connection to the runtime. Requests carry an `id`;
4
6
  * replies (with `ok`) settle the matching promise, events (with `event`) go
@@ -17,7 +19,7 @@ export declare class Connection {
17
19
  static open(port: number, timeoutMs: number): Promise<Connection>;
18
20
  get closed(): boolean;
19
21
  /** Send `{type, ...fields}`; resolves with the `ok: true` reply, rejects with a SonaraError. */
20
- request(type: string, fields?: Record<string, unknown>): Promise<Reply>;
22
+ request(type: string, fields?: Record<string, unknown>, opts?: RequestOptions): Promise<Reply>;
21
23
  close(): void;
22
24
  private onData;
23
25
  private onLine;
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Connection = void 0;
3
+ exports.Connection = exports.MAX_LINE = void 0;
4
4
  const net = require("node:net");
5
5
  const errors_js_1 = require("./errors.js");
6
+ /** Longest line the runtime accepts (bytes, newline included); a longer one closes the connection. */
7
+ exports.MAX_LINE = 1 << 20;
6
8
  /**
7
9
  * One TCP JSON-lines connection to the runtime. Requests carry an `id`;
8
10
  * replies (with `ok`) settle the matching promise, events (with `event`) go
@@ -48,15 +50,42 @@ class Connection {
48
50
  return this.closedFlag;
49
51
  }
50
52
  /** Send `{type, ...fields}`; resolves with the `ok: true` reply, rejects with a SonaraError. */
51
- request(type, fields = {}) {
53
+ request(type, fields = {}, opts = {}) {
52
54
  if (this.closedFlag) {
53
55
  return Promise.reject(new errors_js_1.SonaraError("E_CLOSED", "the connection is closed"));
54
56
  }
55
57
  const id = this.nextId++;
56
- const msg = { ...fields, type, id };
58
+ const line = JSON.stringify({ ...fields, type, id }) + "\n";
59
+ const bytes = Buffer.byteLength(line, "utf8");
60
+ if (bytes > exports.MAX_LINE) {
61
+ // Refused here, so the shared connection stays open (#54).
62
+ return Promise.reject(new errors_js_1.SonaraError("E_BAD_REQUEST", `line too long: ${bytes} bytes, at most ${exports.MAX_LINE}`));
63
+ }
57
64
  return new Promise((resolve, reject) => {
58
- this.pending.set(id, { resolve, reject });
59
- this.sock.write(JSON.stringify(msg) + "\n");
65
+ let timer;
66
+ const done = () => {
67
+ if (timer !== undefined)
68
+ clearTimeout(timer);
69
+ };
70
+ this.pending.set(id, {
71
+ resolve: (r) => {
72
+ done();
73
+ resolve(r);
74
+ },
75
+ reject: (e) => {
76
+ done();
77
+ reject(e);
78
+ },
79
+ });
80
+ if (opts.timeoutMs !== undefined) {
81
+ timer = setTimeout(() => {
82
+ // Replies carry their id, so a late one is dropped (onLine).
83
+ if (this.pending.delete(id)) {
84
+ reject(new errors_js_1.SonaraError("E_TIMEOUT", `no reply to ${type} within ${opts.timeoutMs} ms`));
85
+ }
86
+ }, opts.timeoutMs);
87
+ }
88
+ this.sock.write(line);
60
89
  });
61
90
  }
62
91
  close() {
@@ -94,7 +123,10 @@ class Connection {
94
123
  const id = typeof m.id === "number" ? m.id : undefined;
95
124
  // Replies come in request order, so a reply without our id (the runtime
96
125
  // could not parse the request) belongs to the oldest pending request.
97
- const key = id !== undefined && this.pending.has(id) ? id : this.pending.keys().next().value;
126
+ // One with an id no longer pending answers a request that timed out.
127
+ if (id !== undefined && !this.pending.has(id))
128
+ return;
129
+ const key = id !== undefined ? id : this.pending.keys().next().value;
98
130
  if (key === undefined)
99
131
  return;
100
132
  const p = this.pending.get(key);
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Error codes. The `E_*` codes of protocol v1 come from the runtime as is;
3
- * the client adds three of its own for what happens before or after a reply.
3
+ * the client adds four of its own for what happens before or after a reply.
4
4
  */
5
5
  export type ErrorCode = "E_AUTH" | "E_BAD_REQUEST" | "E_UNKNOWN_TYPE" | "E_UNSUPPORTED" | "E_INCOMPATIBLE" | "E_BUSY" | "E_ENGINE" | "E_NOT_FOUND"
6
6
  /** Protocol 1.3: never allowed over the protocol (adding or changing a `command` engine). */
@@ -10,7 +10,9 @@ export type ErrorCode = "E_AUTH" | "E_BAD_REQUEST" | "E_UNKNOWN_TYPE" | "E_UNSUP
10
10
  /** The bundled runtime did not start or wrote no runtime.json within the wait. */
11
11
  | "E_START_FAILED"
12
12
  /** The connection closed before the reply (the runtime exited or close() was called). */
13
- | "E_CLOSED" | (string & {});
13
+ | "E_CLOSED"
14
+ /** No reply within the request's `timeoutMs`; the connection stays open. */
15
+ | "E_TIMEOUT" | (string & {});
14
16
  /** Any failure of a Sonara call: a coded protocol error or a client-side one. */
15
17
  export declare class SonaraError extends Error {
16
18
  readonly code: ErrorCode;
@@ -65,7 +65,10 @@ export declare class AgentApi {
65
65
  /**
66
66
  * `ask`: a question, permission or plan, spoken with priority. A question
67
67
  * of a set (protocol 1.6, runtime 0.22.0) carries `set_index` (0-based)
68
- * and `set_size` in `extra`: only the first is read, "Question 1 of N.".
68
+ * and `set_size` in `extra`. By default (agent key `question_step` `"off"`,
69
+ * protocol 1.11, runtime 0.32.0) every question of the set is read in
70
+ * order, "Question k of N."; with `set question_step "on"` only question 1
71
+ * is read and the others wait for `nextQuestion`.
69
72
  */
70
73
  ask(channel: string, kind: AskKind, text: string, options?: unknown[], extra?: Extra): Promise<Reply>;
71
74
  /**
@@ -73,7 +73,10 @@ class AgentApi {
73
73
  /**
74
74
  * `ask`: a question, permission or plan, spoken with priority. A question
75
75
  * of a set (protocol 1.6, runtime 0.22.0) carries `set_index` (0-based)
76
- * and `set_size` in `extra`: only the first is read, "Question 1 of N.".
76
+ * and `set_size` in `extra`. By default (agent key `question_step` `"off"`,
77
+ * protocol 1.11, runtime 0.32.0) every question of the set is read in
78
+ * order, "Question k of N."; with `set question_step "on"` only question 1
79
+ * is read and the others wait for `nextQuestion`.
77
80
  */
78
81
  ask(channel, kind, text, options, extra = {}) {
79
82
  return this.send("ask", defined({ ...extra, channel, kind, text, options }));
@@ -18,4 +18,4 @@ export type { EngineAddOptions, EngineModelsDraft, EngineProfile, SendMode, Engi
18
18
  export type { AskKind, AudioMode, ChannelOpenOptions, ChannelPolicy, StreamMessage } from "./extensions.js";
19
19
  export { readRuntime, resolveHome } from "./discovery.js";
20
20
  export { PROTOCOL, VERSION } from "./version.js";
21
- export type { ControlAction, EngineStatus, HelloInfo, ItemEvent, ItemPhase, LogEvent, NowPlaying, Reply, RuntimeInfo, SettingKey, SpeakMode, SpeakOptions, State, Voice, } from "./types.js";
21
+ export type { ControlAction, EngineStatus, HelloInfo, ItemEvent, ItemPhase, LogEvent, NowPlaying, Reply, RequestOptions, RuntimeInfo, SettingKey, SpeakMode, SpeakOptions, State, Voice, } from "./types.js";
@@ -14,6 +14,15 @@ export interface SpeakOptions {
14
14
  /** Shown in `state.now_playing.label`. */
15
15
  label?: string;
16
16
  }
17
+ /** Options of one `request`. */
18
+ export interface RequestOptions {
19
+ /**
20
+ * Reject with `E_TIMEOUT` when no reply came within this many ms (default:
21
+ * no bound). The connection stays open and a late reply is dropped.
22
+ * `engine_test` may take up to a profile's `timeout_ms` (60 s for Gemini).
23
+ */
24
+ timeoutMs?: number;
25
+ }
17
26
  export interface NowPlaying {
18
27
  item_id: number;
19
28
  label: string | null;
@@ -1,5 +1,5 @@
1
1
  /** Version of this package, sent as `client.version` in `hello`. */
2
- export declare const VERSION = "0.32.12";
2
+ export declare const VERSION = "0.32.13";
3
3
  /** Protocol this client speaks. */
4
4
  export declare const PROTOCOL: {
5
5
  readonly major: 1;
@@ -2,6 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PROTOCOL = exports.VERSION = void 0;
4
4
  /** Version of this package, sent as `client.version` in `hello`. */
5
- exports.VERSION = "0.32.12";
5
+ exports.VERSION = "0.32.13";
6
6
  /** Protocol this client speaks. */
7
7
  exports.PROTOCOL = { major: 1, minor: 0 };
@@ -1,7 +1,7 @@
1
1
  import { Connection } from "./connection.js";
2
2
  import { EnginesApi } from "./engines.js";
3
3
  import { AgentApi, ChannelsApi, SystemApi } from "./extensions.js";
4
- import type { ControlAction, HelloInfo, ItemEvent, LogEvent, Reply, RuntimeInfo, SettingKey, SpeakOptions, State, Voice } from "./types.js";
4
+ import type { ControlAction, HelloInfo, ItemEvent, LogEvent, Reply, RequestOptions, RuntimeInfo, SettingKey, SpeakOptions, State, Voice } from "./types.js";
5
5
  export type Unsubscribe = () => void;
6
6
  type Listener<T> = (value: T) => void;
7
7
  /** Opens and greets one more connection (the event connection). */
@@ -39,8 +39,11 @@ export declare class SonaraClient {
39
39
  constructor(conn: Connection, runtime: RuntimeInfo, info: HelloInfo, dial: Dial);
40
40
  /** True once the connection closed (close(), a takeover or the runtime exited). */
41
41
  get closed(): boolean;
42
- /** Send any protocol message; resolves with the `ok: true` reply. */
43
- request(type: string, fields?: Record<string, unknown>): Promise<Reply>;
42
+ /**
43
+ * Send any protocol message; resolves with the `ok: true` reply.
44
+ * `opts.timeoutMs` bounds this one request (`E_TIMEOUT`; default: none).
45
+ */
46
+ request(type: string, fields?: Record<string, unknown>, opts?: RequestOptions): Promise<Reply>;
44
47
  /** Add `text` as one item; resolves with its item id. */
45
48
  speak(text: string, opts?: SpeakOptions): Promise<number>;
46
49
  /**
@@ -37,9 +37,12 @@ export class SonaraClient {
37
37
  get closed() {
38
38
  return this.conn.closed;
39
39
  }
40
- /** Send any protocol message; resolves with the `ok: true` reply. */
41
- request(type, fields = {}) {
42
- return this.conn.request(type, fields);
40
+ /**
41
+ * Send any protocol message; resolves with the `ok: true` reply.
42
+ * `opts.timeoutMs` bounds this one request (`E_TIMEOUT`; default: none).
43
+ */
44
+ request(type, fields = {}, opts = {}) {
45
+ return this.conn.request(type, fields, opts);
43
46
  }
44
47
  /** Add `text` as one item; resolves with its item id. */
45
48
  async speak(text, opts = {}) {
@@ -1,4 +1,6 @@
1
- import type { Reply } from "./types.js";
1
+ import type { Reply, RequestOptions } from "./types.js";
2
+ /** Longest line the runtime accepts (bytes, newline included); a longer one closes the connection. */
3
+ export declare const MAX_LINE: number;
2
4
  /**
3
5
  * One TCP JSON-lines connection to the runtime. Requests carry an `id`;
4
6
  * replies (with `ok`) settle the matching promise, events (with `event`) go
@@ -17,7 +19,7 @@ export declare class Connection {
17
19
  static open(port: number, timeoutMs: number): Promise<Connection>;
18
20
  get closed(): boolean;
19
21
  /** Send `{type, ...fields}`; resolves with the `ok: true` reply, rejects with a SonaraError. */
20
- request(type: string, fields?: Record<string, unknown>): Promise<Reply>;
22
+ request(type: string, fields?: Record<string, unknown>, opts?: RequestOptions): Promise<Reply>;
21
23
  close(): void;
22
24
  private onData;
23
25
  private onLine;
@@ -1,5 +1,7 @@
1
1
  import * as net from "node:net";
2
2
  import { SonaraError } from "./errors.js";
3
+ /** Longest line the runtime accepts (bytes, newline included); a longer one closes the connection. */
4
+ export const MAX_LINE = 1 << 20;
3
5
  /**
4
6
  * One TCP JSON-lines connection to the runtime. Requests carry an `id`;
5
7
  * replies (with `ok`) settle the matching promise, events (with `event`) go
@@ -45,15 +47,42 @@ export class Connection {
45
47
  return this.closedFlag;
46
48
  }
47
49
  /** Send `{type, ...fields}`; resolves with the `ok: true` reply, rejects with a SonaraError. */
48
- request(type, fields = {}) {
50
+ request(type, fields = {}, opts = {}) {
49
51
  if (this.closedFlag) {
50
52
  return Promise.reject(new SonaraError("E_CLOSED", "the connection is closed"));
51
53
  }
52
54
  const id = this.nextId++;
53
- const msg = { ...fields, type, id };
55
+ const line = JSON.stringify({ ...fields, type, id }) + "\n";
56
+ const bytes = Buffer.byteLength(line, "utf8");
57
+ if (bytes > MAX_LINE) {
58
+ // Refused here, so the shared connection stays open (#54).
59
+ return Promise.reject(new SonaraError("E_BAD_REQUEST", `line too long: ${bytes} bytes, at most ${MAX_LINE}`));
60
+ }
54
61
  return new Promise((resolve, reject) => {
55
- this.pending.set(id, { resolve, reject });
56
- this.sock.write(JSON.stringify(msg) + "\n");
62
+ let timer;
63
+ const done = () => {
64
+ if (timer !== undefined)
65
+ clearTimeout(timer);
66
+ };
67
+ this.pending.set(id, {
68
+ resolve: (r) => {
69
+ done();
70
+ resolve(r);
71
+ },
72
+ reject: (e) => {
73
+ done();
74
+ reject(e);
75
+ },
76
+ });
77
+ if (opts.timeoutMs !== undefined) {
78
+ timer = setTimeout(() => {
79
+ // Replies carry their id, so a late one is dropped (onLine).
80
+ if (this.pending.delete(id)) {
81
+ reject(new SonaraError("E_TIMEOUT", `no reply to ${type} within ${opts.timeoutMs} ms`));
82
+ }
83
+ }, opts.timeoutMs);
84
+ }
85
+ this.sock.write(line);
57
86
  });
58
87
  }
59
88
  close() {
@@ -91,7 +120,10 @@ export class Connection {
91
120
  const id = typeof m.id === "number" ? m.id : undefined;
92
121
  // Replies come in request order, so a reply without our id (the runtime
93
122
  // could not parse the request) belongs to the oldest pending request.
94
- const key = id !== undefined && this.pending.has(id) ? id : this.pending.keys().next().value;
123
+ // One with an id no longer pending answers a request that timed out.
124
+ if (id !== undefined && !this.pending.has(id))
125
+ return;
126
+ const key = id !== undefined ? id : this.pending.keys().next().value;
95
127
  if (key === undefined)
96
128
  return;
97
129
  const p = this.pending.get(key);
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Error codes. The `E_*` codes of protocol v1 come from the runtime as is;
3
- * the client adds three of its own for what happens before or after a reply.
3
+ * the client adds four of its own for what happens before or after a reply.
4
4
  */
5
5
  export type ErrorCode = "E_AUTH" | "E_BAD_REQUEST" | "E_UNKNOWN_TYPE" | "E_UNSUPPORTED" | "E_INCOMPATIBLE" | "E_BUSY" | "E_ENGINE" | "E_NOT_FOUND"
6
6
  /** Protocol 1.3: never allowed over the protocol (adding or changing a `command` engine). */
@@ -10,7 +10,9 @@ export type ErrorCode = "E_AUTH" | "E_BAD_REQUEST" | "E_UNKNOWN_TYPE" | "E_UNSUP
10
10
  /** The bundled runtime did not start or wrote no runtime.json within the wait. */
11
11
  | "E_START_FAILED"
12
12
  /** The connection closed before the reply (the runtime exited or close() was called). */
13
- | "E_CLOSED" | (string & {});
13
+ | "E_CLOSED"
14
+ /** No reply within the request's `timeoutMs`; the connection stays open. */
15
+ | "E_TIMEOUT" | (string & {});
14
16
  /** Any failure of a Sonara call: a coded protocol error or a client-side one. */
15
17
  export declare class SonaraError extends Error {
16
18
  readonly code: ErrorCode;
@@ -65,7 +65,10 @@ export declare class AgentApi {
65
65
  /**
66
66
  * `ask`: a question, permission or plan, spoken with priority. A question
67
67
  * of a set (protocol 1.6, runtime 0.22.0) carries `set_index` (0-based)
68
- * and `set_size` in `extra`: only the first is read, "Question 1 of N.".
68
+ * and `set_size` in `extra`. By default (agent key `question_step` `"off"`,
69
+ * protocol 1.11, runtime 0.32.0) every question of the set is read in
70
+ * order, "Question k of N."; with `set question_step "on"` only question 1
71
+ * is read and the others wait for `nextQuestion`.
69
72
  */
70
73
  ask(channel: string, kind: AskKind, text: string, options?: unknown[], extra?: Extra): Promise<Reply>;
71
74
  /**
@@ -69,7 +69,10 @@ export class AgentApi {
69
69
  /**
70
70
  * `ask`: a question, permission or plan, spoken with priority. A question
71
71
  * of a set (protocol 1.6, runtime 0.22.0) carries `set_index` (0-based)
72
- * and `set_size` in `extra`: only the first is read, "Question 1 of N.".
72
+ * and `set_size` in `extra`. By default (agent key `question_step` `"off"`,
73
+ * protocol 1.11, runtime 0.32.0) every question of the set is read in
74
+ * order, "Question k of N."; with `set question_step "on"` only question 1
75
+ * is read and the others wait for `nextQuestion`.
73
76
  */
74
77
  ask(channel, kind, text, options, extra = {}) {
75
78
  return this.send("ask", defined({ ...extra, channel, kind, text, options }));
@@ -18,4 +18,4 @@ export type { EngineAddOptions, EngineModelsDraft, EngineProfile, SendMode, Engi
18
18
  export type { AskKind, AudioMode, ChannelOpenOptions, ChannelPolicy, StreamMessage } from "./extensions.js";
19
19
  export { readRuntime, resolveHome } from "./discovery.js";
20
20
  export { PROTOCOL, VERSION } from "./version.js";
21
- export type { ControlAction, EngineStatus, HelloInfo, ItemEvent, ItemPhase, LogEvent, NowPlaying, Reply, RuntimeInfo, SettingKey, SpeakMode, SpeakOptions, State, Voice, } from "./types.js";
21
+ export type { ControlAction, EngineStatus, HelloInfo, ItemEvent, ItemPhase, LogEvent, NowPlaying, Reply, RequestOptions, RuntimeInfo, SettingKey, SpeakMode, SpeakOptions, State, Voice, } from "./types.js";
@@ -14,6 +14,15 @@ export interface SpeakOptions {
14
14
  /** Shown in `state.now_playing.label`. */
15
15
  label?: string;
16
16
  }
17
+ /** Options of one `request`. */
18
+ export interface RequestOptions {
19
+ /**
20
+ * Reject with `E_TIMEOUT` when no reply came within this many ms (default:
21
+ * no bound). The connection stays open and a late reply is dropped.
22
+ * `engine_test` may take up to a profile's `timeout_ms` (60 s for Gemini).
23
+ */
24
+ timeoutMs?: number;
25
+ }
17
26
  export interface NowPlaying {
18
27
  item_id: number;
19
28
  label: string | null;
@@ -1,5 +1,5 @@
1
1
  /** Version of this package, sent as `client.version` in `hello`. */
2
- export declare const VERSION = "0.32.12";
2
+ export declare const VERSION = "0.32.13";
3
3
  /** Protocol this client speaks. */
4
4
  export declare const PROTOCOL: {
5
5
  readonly major: 1;
@@ -1,4 +1,4 @@
1
1
  /** Version of this package, sent as `client.version` in `hello`. */
2
- export const VERSION = "0.32.12";
2
+ export const VERSION = "0.32.13";
3
3
  /** Protocol this client speaks. */
4
4
  export const PROTOCOL = { major: 1, minor: 0 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sonara/client",
3
- "version": "0.32.12",
3
+ "version": "0.32.13",
4
4
  "description": "Client for the Sonara text-to-speech runtime (protocol v1): connect, speak, control, live state. Zero dependencies.",
5
5
  "license": "MIT",
6
6
  "repository": {