@rimelabs/sdk 0.1.0-alpha.1 → 0.1.0-alpha.2

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/CHANGELOG.md CHANGED
@@ -1,16 +1,21 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.0-alpha.1
3
+ ## [0.1.0-alpha.2](https://github.com/rimelabs/rime-sdk/compare/typescript-v0.1.0-alpha.1...typescript-v0.1.0-alpha.2) (2026-09-28)
4
+
5
+ - Add `model: "mistv3"` for Mist v3 speech, voice discovery, and language discovery.
6
+ The model selects its standard endpoint and default voice. Custom endpoints
7
+ retain the model's default voice. Coda remains the default model.
8
+ - Reorganize the usage guide around examples and option tables. Clarify audio
9
+ output, timeout defaults, error handling, and cancellation.
4
10
 
5
- Initial local alpha for Node.js 22+ and ESM. Adds Coda synthesis, discovery,
6
- API-key authentication, sentence buffering, PCM and mu-law profiles, typed errors,
7
- deadlines, and cancellation. The Themis wire contract is assumed and needs
8
- deployment validation.
11
+ ## 0.1.0-alpha.1
9
12
 
10
- Review fixes preserve zero-width spaces and BOM characters during sentence
11
- mapping, distinguish token-exchange rate limits and service failures from
12
- rejected credentials, and cancel failed HTTP response bodies.
13
+ Initial public alpha for Node.js 22 and later, with ESM and TypeScript types:
13
14
 
14
- Further review fixes stop pending reads after cancellation, preserve errors from
15
- responses without audio metadata, handle responses with only trailers, and
16
- collect discovery request IDs from headers and trailers.
15
+ - Stream Coda speech from a string or an async text source with API-key authentication.
16
+ - Discover voices and languages, and select a custom deployment endpoint.
17
+ - Receive raw 24 kHz PCM or 8 kHz mu-law audio with sentence buffering.
18
+ - Set operation deadlines, cancel streams, and handle typed errors with request IDs.
19
+ - Preserve original text during sentence detection, including zero-width spaces
20
+ and byte order marks.
21
+ - Report server errors even when no audio metadata arrives or input writes fail.
package/README.md CHANGED
@@ -1,23 +1,28 @@
1
1
  # Rime SDK for Node.js
2
2
 
3
- Requires Node.js 22 or later. The package uses ESM and includes TypeScript types.
4
- Browser use is not supported. This is an alpha release.
5
- Install it from npm using the `next` tag:
3
+ Stream speech from a string or async text source with Rime.
4
+
5
+ ## Install
6
+
7
+ Requires Node.js 22 or later. This alpha package uses ESM and includes TypeScript
8
+ types. Browser use is not supported.
6
9
 
7
10
  ```sh
8
11
  npm install @rimelabs/sdk@next
12
+ export RIME_API_KEY="your-api-key"
9
13
  ```
10
14
 
15
+ ## Quick start
16
+
17
+ Save this as `speech.mjs` and run `node speech.mjs`:
18
+
11
19
  ```javascript
12
20
  import { writeFile } from "node:fs/promises";
13
- import { Rime, AudioFormat } from "@rimelabs/sdk";
21
+ import { Rime } from "@rimelabs/sdk";
14
22
 
15
- const client = new Rime({ apiKey: "your-api-key" });
23
+ const client = new Rime();
16
24
  try {
17
- const audio = client.tts.stream("Hello. This is Rime.", {
18
- voice: "clementine",
19
- audioFormat: AudioFormat.PCM_24000,
20
- });
25
+ const audio = client.tts.stream("Hello. This is Rime.");
21
26
  await writeFile("speech.pcm", audio);
22
27
  console.log(audio.requestId);
23
28
  } finally {
@@ -25,69 +30,137 @@ try {
25
30
  }
26
31
  ```
27
32
 
28
- Omit `apiKey` to read `RIME_API_KEY`. The default model is `coda`.
29
- The SDK selects its standard endpoint. Only `coda` is currently supported.
30
- For a custom deployment of that model, set `endpoint`:
33
+ Output is raw mono 24 kHz signed 16-bit little-endian PCM. Configure your player
34
+ for this format; there is no WAV header.
35
+
36
+ ## Stream incoming text
37
+
38
+ Add this async text source before the client declaration in the quick start:
31
39
 
32
40
  ```javascript
33
- const client = new Rime({ model: "coda", endpoint: "coda.api.customer-name.rime.ai" });
41
+ async function* text() {
42
+ yield "Hello. ";
43
+ yield "This text arrives in separate chunks.";
44
+ }
34
45
  ```
35
46
 
36
- Use a hostname with an optional port, such as `host:8443`. Omit the scheme and path.
37
- Connections always use TLS; the default port is `443`.
38
- The endpoint applies to speech, voices, and languages for this client.
47
+ Use `client.tts.stream(text())` with the same file write and cleanup.
48
+ The SDK handles sentence boundaries. Do not await `tts.stream()`; the first
49
+ iterator read starts work. `writeFile` consumes the stream for you.
39
50
 
40
- The default voice is `clementine`; the default language is `en`.
41
- `tts.stream()` also accepts `AsyncIterable<string>`. Do not await the factory.
42
- The first iterator read starts work. A `for await` loop exit cancels the stream.
43
- Use `await audio.cancel()` in a `finally` block if you read the iterator manually.
51
+ ## Configuration
44
52
 
45
- `await client.voices.list({ language: "en" })` returns voice names.
46
- `await client.languages.list()` returns language codes.
47
- Both accept an options object with `timeout` in seconds.
53
+ Select Mist v3 with `new Rime({ model: "mistv3" })`. Mist v1 and v2 are not supported.
48
54
 
49
- `new Rime({ timeout: 30 })` sets an overall timeout. An operation can replace
50
- it with `{ timeout: 10 }` or disable it with `{ timeout: null }`.
51
- An omitted or `undefined` option inherits the client setting. Internal connection
52
- and progress limits still apply. An overall timeout continues during caller pauses.
55
+ | Model | Standard endpoint | Default voice |
56
+ | --- | --- | --- |
57
+ | `coda` | `coda.api.rime.ai:443` | `clementine` |
58
+ | `mistv3` | `mist.api.rime.ai:443` | `astra` |
53
59
 
54
- `audio.format` is a read-only `AudioFormat` with `encoding`, `sampleRate`, and
55
- `channels`. `PCM_24000` is raw signed 16-bit little-endian mono PCM at 24 kHz.
56
- `MULAW_8000` is raw mono G.711 mu-law at 8 kHz. Neither includes a file header.
57
- The iterator yields `Uint8Array` chunks with complete sample frames.
58
- Chunk sizes are not fixed.
60
+ ### Client options
59
61
 
60
- `await audio.cancel()` cancels one operation. `await client.close()` cancels all
61
- client work. Both are idempotent. Both objects support `Symbol.asyncDispose`.
62
- Normal iterator completion means that the final service status was successful.
63
- Partial audio can precede a typed error. Synthesis is never replayed.
62
+ | `new Rime({ ... })` option | Default | Meaning |
63
+ | --- | --- | --- |
64
+ | `apiKey` | `RIME_API_KEY` | API key; an explicit value overrides the environment |
65
+ | `model` | `"coda"` | Model for speech and discovery |
66
+ | `endpoint` | Model's standard endpoint | Custom hostname and optional port for speech and discovery |
67
+ | `timeout` | No overall deadline | Positive seconds; `null` disables the overall deadline |
64
68
 
65
- Catch `RimeError` or one of `RimeAuthenticationError`, `RimePermissionError`,
66
- `RimeInputError`, `RimeResourceLimitError`, `RimeUnavailableError`,
67
- `RimeTimeoutError`, `RimeAudioFormatError`, `RimeCancelledError`, or
68
- `RimeStreamError`. Errors expose a message and optional `requestId`.
69
- Cancellation cannot stop application code that waits on an unrelated promise.
70
- The SDK stops its RPC and limits how long it waits for source cleanup.
69
+ Authentication uses bearer tokens over TLS. The SDK does not load `.env` files.
71
70
 
72
- The SDK sends the API key as a bearer token over TLS.
71
+ Custom deployments use `new Rime({ model: "coda", endpoint: "host:8443" })`.
72
+ Omit the scheme and path. TLS is required; the default port is `443`.
73
+ Model defaults still apply.
73
74
 
74
- ## Development for contributors
75
+ ### Synthesis options
75
76
 
76
- These instructions require access to the source repository.
77
- Run the commands from its `typescript/` directory:
77
+ Pass these options to `client.tts.stream(text, { ... })`:
78
78
 
79
- ```sh
80
- npm ci
81
- npm run check
82
- npm run lint
83
- npm test
84
- npm pack
79
+ | Option | Default | Meaning |
80
+ | --- | --- | --- |
81
+ | `voice` | Model's default voice | Voice name from `client.voices.list()` |
82
+ | `language` | `"en"` | Language code |
83
+ | `audioFormat` | `AudioFormat.PCM_24000` | Output profile, imported from `@rimelabs/sdk` |
84
+ | `timeout` | Client setting | Seconds; pass `null` to disable the overall deadline |
85
+
86
+ ### Audio formats
87
+
88
+ Both profiles return raw audio without a file header.
89
+
90
+ | `AudioFormat` profile | Encoding | Sample rate | Channels |
91
+ | --- | --- | --- | --- |
92
+ | `PCM_24000` | Signed 16-bit little-endian PCM | 24 kHz | Mono |
93
+ | `MULAW_8000` | G.711 mu-law | 8 kHz | Mono |
94
+
95
+ Chunks are `Uint8Array` values with complete sample frames; sizes vary. Inspect the
96
+ read-only `audio.format.encoding`, `audio.format.sampleRate`, and `audio.format.channels`.
97
+
98
+ ### Timeouts
99
+
100
+ An overall deadline includes pauses between reads. Disabling it leaves internal
101
+ connection and progress limits active. Discovery allows at most 10 seconds;
102
+ a shorter supplied timeout takes precedence. Omit an operation's `timeout` or
103
+ pass `undefined` to inherit the client setting.
104
+
105
+ ## Discover voices and languages
106
+
107
+ List voices and languages inside the quick start's `try` block:
108
+
109
+ ```javascript
110
+ const voices = await client.voices.list({ language: "en" });
111
+ const languages = await client.languages.list();
112
+ console.log(voices, languages);
113
+ ```
114
+
115
+ Both return string arrays and accept `timeout`. Omit `language` to disable filtering.
116
+
117
+ ## Errors and cancellation
118
+
119
+ Report SDK errors and request IDs while closing the client on failure:
120
+
121
+ ```javascript
122
+ import { writeFile } from "node:fs/promises";
123
+ import { Rime, RimeError } from "@rimelabs/sdk";
124
+
125
+ let client;
126
+ try {
127
+ client = new Rime();
128
+ await writeFile("speech.pcm", client.tts.stream("Hello. This is Rime."));
129
+ } catch (error) {
130
+ if (error instanceof RimeError) {
131
+ console.error(`Speech failed: ${error.message}; requestId=${error.requestId}`);
132
+ }
133
+ throw error;
134
+ } finally {
135
+ await client?.close();
136
+ }
85
137
  ```
86
138
 
87
- The package includes a pinned Microsoft BlingFire WASM binary and its license.
88
- It does not download code at runtime. See [vendor provenance](vendor/README.md).
139
+ Each SDK error inherits from `RimeError`:
140
+
141
+ | Error | Meaning |
142
+ | --- | --- |
143
+ | `RimeAuthenticationError` | Missing or rejected credentials |
144
+ | `RimePermissionError` | Access denied |
145
+ | `RimeInputError` | Invalid input or client use |
146
+ | `RimeResourceLimitError` | Service resource limit reached |
147
+ | `RimeUnavailableError` | Service unavailable |
148
+ | `RimeTimeoutError` | Overall or internal deadline reached |
149
+ | `RimeAudioFormatError` | Unsupported or unexpected audio format |
150
+ | `RimeCancelledError` | Operation cancelled |
151
+ | `RimeStreamError` | Other stream or transport failure |
152
+
153
+ Partial audio can arrive before an error. Output is complete only after successful
154
+ iteration. Synthesis is not retried automatically.
155
+
156
+ Keep cleanup when stopping early. A `for await` loop exit cancels the stream.
157
+ For manual reads, call `await audio.cancel()` in `finally`. `await client.close()`
158
+ stops all client work. Both calls are safe to repeat; both objects support
159
+ `Symbol.asyncDispose`. Cancellation stops the RPC and limits cleanup time, but
160
+ cannot force your text source to finish an unrelated promise.
89
161
 
90
162
  ## License
91
163
 
92
- The SDK is licensed under the [MIT License](LICENSE).
93
- BlingFire retains its [upstream license](vendor/LICENSE.blingfire).
164
+ The SDK uses the [MIT License](LICENSE). BlingFire retains its
165
+ [upstream license](vendor/LICENSE.blingfire). The package includes its WASM runtime
166
+ and downloads no code or models at runtime. See [vendor provenance](vendor/README.md).
package/dist/client.d.ts CHANGED
@@ -2,6 +2,7 @@ import { AudioFormat } from "./audio.js";
2
2
  import { AudioStream, type TextSource } from "./stream.js";
3
3
  export interface RimeOptions {
4
4
  apiKey?: string | null;
5
+ /** Select "coda" (default) or "mistv3" for speech and discovery. */
5
6
  model?: string;
6
7
  endpoint?: string | null;
7
8
  timeout?: number | null;
package/dist/client.js CHANGED
@@ -58,7 +58,7 @@ export class Rime {
58
58
  else if (!text || typeof text[Symbol.asyncIterator] !== "function")
59
59
  throw new RimeInputError("text must be a string or an async iterable of strings");
60
60
  const voice = options.voice === undefined || options.voice === null
61
- ? "clementine"
61
+ ? this.deployment.defaultVoice
62
62
  : nonempty(options.voice, "voice");
63
63
  const language = nonempty(options.language ?? "en", "language");
64
64
  const format = options.audioFormat ?? AudioFormat.PCM_24000;
package/dist/policy.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export declare const policy: {
2
2
  target: string;
3
3
  audience: string;
4
+ defaultVoice: string;
4
5
  exchangeUrl: string;
5
6
  sentenceBytes: number;
6
7
  sourceChars: number;
package/dist/policy.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import { RimeInputError } from "./errors.js";
2
+ const codaHostname = "coda.api.rime.ai";
2
3
  export const policy = {
3
- target: "coda.api.rime.ai:443",
4
- audience: "coda.api.rime.ai",
4
+ target: `${codaHostname}:443`,
5
+ audience: codaHostname,
6
+ defaultVoice: "clementine",
5
7
  exchangeUrl: "https://themis.api.rime.ai/v1/token",
6
8
  sentenceBytes: 65536,
7
9
  sourceChars: 1024,
@@ -16,11 +18,18 @@ export const policy = {
16
18
  cleanupTimeout: 2,
17
19
  };
18
20
  export function resolve(model, endpoint) {
19
- // Add model defaults here only when its transport contract is supported.
20
- if (model !== "coda")
21
- throw new RimeInputError("This SDK supports model='coda'");
21
+ const deployment = { ...policy };
22
+ if (model === "mistv3") {
23
+ const hostname = "mist.api.rime.ai";
24
+ deployment.target = `${hostname}:443`;
25
+ deployment.audience = hostname;
26
+ deployment.defaultVoice = "astra";
27
+ }
28
+ else if (model !== "coda") {
29
+ throw new RimeInputError("model must be 'coda' or 'mistv3'");
30
+ }
22
31
  if (endpoint === undefined || endpoint === null)
23
- return { ...policy };
32
+ return deployment;
24
33
  const error = "endpoint must be a hostname with an optional port (1-65535), without a scheme or path";
25
34
  if (typeof endpoint !== "string" || /\s/.test(endpoint))
26
35
  throw new RimeInputError(error);
@@ -35,7 +44,7 @@ export function resolve(model, endpoint) {
35
44
  (!/^[0-9]{1,5}$/.test(port) || Number(port) < 1 || Number(port) > 65535)))
36
45
  throw new RimeInputError(error);
37
46
  return {
38
- ...policy,
47
+ ...deployment,
39
48
  target: `${host.toLowerCase()}:${port === undefined ? 443 : Number(port)}`,
40
49
  audience: host.toLowerCase(),
41
50
  };
package/dist/transport.js CHANGED
@@ -72,7 +72,7 @@ function nativeError(error, id) {
72
72
  const metadata = "metadata" in error ? error.metadata : null;
73
73
  return rpcError(error.code, id ?? (metadata instanceof grpc.Metadata ? requestId(metadata) : null));
74
74
  }
75
- return new errors.RimeStreamError("Coda transport failed", id, {
75
+ return new errors.RimeStreamError("Rime transport failed", id, {
76
76
  cause: error,
77
77
  });
78
78
  }
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "@rimelabs/sdk",
3
- "version": "0.1.0-alpha.1",
3
+ "version": "0.1.0-alpha.2",
4
4
  "description": "Rime streaming text-to-speech SDK for Node.js",
5
5
  "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/rimelabs/rime-sdk.git",
9
+ "directory": "typescript"
10
+ },
6
11
  "type": "module",
7
12
  "engines": {
8
13
  "node": ">=22"