@breeze.blue/sdk 0.21.1 → 0.22.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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.22.1 - 2026-10-29
4
+
5
+ - Document supported Voice Clone reference audio formats and the single-file, 5 MB, synchronous API contract.
6
+ - Align the package release with the Python SDK upload content-type fix.
7
+
8
+ ## 0.22.0
9
+
10
+ - Select PCM or MP3 for realtime TTS sessions and preserve the format across managed connections.
11
+ - Export output-format choices shared with the public API while retaining historical conversion profiles.
12
+ - Breaking: remove `visibility` and `primaryCategoryCode` from `voices.savePreview(...)` and `voices.edit(...)`, and remove reference-sample upload arguments from `voices.edit(...)`.
13
+ - Keep official catalog assignment, publication and reference-sample replacement available through authorized low-level HTTP requests or the CLI. Category search and Clone uploads remain available.
14
+ - Voice Clone accepts `referenceLanguageCode: "zh"` to use Qwen ASR for a Chinese reference sample. Omitting it keeps automatic language detection.
15
+ - Check complete Voice and History request fields against public OpenAPI with a shared, operation-specific historical compatibility whitelist.
16
+
3
17
  ## 0.21.1
4
18
 
5
19
  - Document Voice Design guidance: omitted or null samples 1–4 per preview; explicit values still accept 1–10.
package/README.md CHANGED
@@ -107,8 +107,10 @@ If the job is still active, `downloadAudio(...)` rejects with
107
107
  `BreezeBlueGenerationNotReadyError`; read `error.retryAfter` before retrying.
108
108
 
109
109
  Use realtime text-to-speech when one WebSocket connection should handle multiple
110
- conversation turns. Realtime audio is fixed to raw `pcm_s16le`, 24000 Hz, mono,
111
- 16-bit frames.
110
+ conversation turns. Realtime supports PCM (default) or MP3 at 24 kHz mono.
111
+ PCM uses raw signed 16-bit little-endian samples. Pass `outputFormat: "mp3"` to
112
+ `realtime.createSession`, `realtime.connect`, or `realtime.connectManaged` to select MP3.
113
+ Each turn's final MP3 bytes arrive before `turn.done`.
112
114
 
113
115
  Realtime needs a `WebSocket` implementation. Browsers, edge runtimes, and
114
116
  Node 22+ provide a global one; on Node 20, pass a constructor (for example the
@@ -396,8 +398,7 @@ Streaming text-to-speech defaults to `pcm` to reduce time to first audio. Pass
396
398
  format explicitly.
397
399
 
398
400
  Sync and async text-to-speech also take a sample rate and, for the lossy encodings, a bitrate, such as
399
- `{ outputFormat: "wav_48000" }`. Breeze resamples its native 24000 Hz output for
400
- downstream compatibility; profiles carrying a sample rate are not available for streaming.
401
+ `{ outputFormat: "wav_24000" }`. Profiles carrying a sample rate apply to sync and async conversion; streaming uses bare encoding names.
401
402
 
402
403
  ## Voices
403
404
 
@@ -445,6 +446,10 @@ Breeze voice creation is always two steps: produce a **preview**, let the
445
446
  user accept it, then **save the preview** as a real voice. Three ways to
446
447
  produce a preview:
447
448
 
449
+ Clone samples accept MP3, WAV, M4A, FLAC, AAC, OGG, Opus, WebM audio, WMA,
450
+ or AIFF, at least 3 seconds and up to 5 MB. Clone calls are synchronous.
451
+ Supply a matching `filename` or `contentType` with the upload.
452
+
448
453
  ```ts
449
454
  import { readFile } from "node:fs/promises";
450
455
 
@@ -564,7 +569,9 @@ const saved = await client.voices.savePreview({
564
569
  });
565
570
  ```
566
571
 
567
- Edit or delete a saved voice:
572
+ Saved previews are private to your account. Editing a voice's metadata preserves its visibility.
573
+
574
+ Edit a saved voice's name, description, tags, or Voice Metadata, or delete it:
568
575
 
569
576
  ```ts
570
577
  await client.voices.edit(saved.voiceId, {
package/dist/client.d.ts CHANGED
@@ -237,6 +237,8 @@ declare class VoicesResource {
237
237
  * Generate a clone preview from a single audio sample. Returns a
238
238
  * `generatedVoiceId`; call {@link savePreview} after the user accepts
239
239
  * the preview to persist it as a real voice.
240
+ * Accepts MP3, WAV, M4A, FLAC, AAC, OGG, Opus, WebM audio, WMA, or AIFF,
241
+ * at least 3 seconds and up to 5 MB. Supply a matching filename or contentType.
240
242
  */
241
243
  createClonePreview(request: VoiceClonePreviewRequest, options?: RequestOptions): Promise<VoiceClonePreview>;
242
244
  /**
package/dist/client.js CHANGED
@@ -163,6 +163,7 @@ class RealtimeTextToSpeechResource {
163
163
  voiceSettings: request.voiceSettings == null ? request.voiceSettings : { guidanceScale: request.voiceSettings.guidanceScale, useSpeakerBoost: request.voiceSettings.useSpeakerBoost },
164
164
  inactivityTimeoutSeconds: request.inactivityTimeoutSeconds,
165
165
  enableLogging: request.enableLogging,
166
+ outputFormat: request.outputFormat,
166
167
  }, options);
167
168
  }
168
169
  async connect(voiceId, options = {}) {
@@ -170,7 +171,7 @@ class RealtimeTextToSpeechResource {
170
171
  options.websocketUrl !== undefined ||
171
172
  options.directWebsocketUrl !== undefined) && hasRealtimeSessionParams(options)) {
172
173
  console.warn("@breeze.blue/sdk: realtime.connect ignores modelId, languageCode, instructions, voiceSettings, " +
173
- "inactivityTimeoutSeconds, and enableLogging when session credentials are provided. " +
174
+ "inactivityTimeoutSeconds, outputFormat, and enableLogging when session credentials are provided. " +
174
175
  "Configure these initial values when creating the realtime session instead. " +
175
176
  "To change instructions between turns, call connection.updateInstructions() and wait for session.updated.");
176
177
  }
@@ -185,6 +186,7 @@ class RealtimeTextToSpeechResource {
185
186
  voiceSettings: options.voiceSettings,
186
187
  inactivityTimeoutSeconds: options.inactivityTimeoutSeconds,
187
188
  enableLogging: options.enableLogging,
189
+ outputFormat: options.outputFormat,
188
190
  }, {
189
191
  signal: options.signal,
190
192
  timeout: options.timeout,
@@ -226,7 +228,7 @@ class RealtimeTextToSpeechResource {
226
228
  async connectManaged(voiceId, options = {}) {
227
229
  if (options.sessionFactory !== undefined && hasRealtimeSessionParams(options)) {
228
230
  console.warn("@breeze.blue/sdk: realtime.connectManaged cannot apply modelId, languageCode, instructions, " +
229
- "voiceSettings, inactivityTimeoutSeconds, or enableLogging when sessionFactory is provided. " +
231
+ "voiceSettings, inactivityTimeoutSeconds, outputFormat, or enableLogging when sessionFactory is provided. " +
230
232
  "Configure these when the factory creates each realtime session. After connecting, confirmed " +
231
233
  "updateInstructions() values are carried across managed physical sessions.");
232
234
  }
@@ -237,6 +239,7 @@ class RealtimeTextToSpeechResource {
237
239
  voiceSettings: options.voiceSettings,
238
240
  inactivityTimeoutSeconds: options.inactivityTimeoutSeconds,
239
241
  enableLogging: options.enableLogging,
242
+ outputFormat: options.outputFormat,
240
243
  };
241
244
  const connectionTimeout = options.timeout ?? this.client.timeout ?? DEFAULT_REALTIME_HANDSHAKE_TIMEOUT_MS;
242
245
  const createConnection = async (signal) => {
@@ -272,7 +275,8 @@ function hasRealtimeSessionParams(options) {
272
275
  options.instructions !== undefined ||
273
276
  options.voiceSettings !== undefined ||
274
277
  options.inactivityTimeoutSeconds !== undefined ||
275
- options.enableLogging !== undefined);
278
+ options.enableLogging !== undefined ||
279
+ options.outputFormat !== undefined);
276
280
  }
277
281
  function realtimeClientSecretSubprotocols(clientSecret) {
278
282
  if (!/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]{43}$/.test(clientSecret)) {
@@ -1569,6 +1573,8 @@ class VoicesResource {
1569
1573
  * Generate a clone preview from a single audio sample. Returns a
1570
1574
  * `generatedVoiceId`; call {@link savePreview} after the user accepts
1571
1575
  * the preview to persist it as a real voice.
1576
+ * Accepts MP3, WAV, M4A, FLAC, AAC, OGG, Opus, WebM audio, WMA, or AIFF,
1577
+ * at least 3 seconds and up to 5 MB. Supply a matching filename or contentType.
1572
1578
  */
1573
1579
  async createClonePreview(request, options) {
1574
1580
  return this.client.requestJson("POST", "/v1/voice-previews/clone", undefined, clonePreviewForm(request), options);
@@ -1634,8 +1640,6 @@ class VoicesResource {
1634
1640
  voiceName: request.voiceName,
1635
1641
  voiceDescription: request.voiceDescription,
1636
1642
  tags: request.tags,
1637
- primaryCategoryCode: request.primaryCategoryCode,
1638
- visibility: request.visibility,
1639
1643
  languageCode: request.languageCode,
1640
1644
  gender: request.gender,
1641
1645
  age: request.age,
@@ -1789,6 +1793,7 @@ function clonePreviewForm(request) {
1789
1793
  const form = new FormData();
1790
1794
  appendOptional(form, "name", request.name ?? undefined);
1791
1795
  appendOptional(form, "description", request.description);
1796
+ appendOptional(form, "reference_language_code", request.referenceLanguageCode);
1792
1797
  appendOptional(form, "remove_background_noise", request.removeBackgroundNoise ?? false);
1793
1798
  for (const file of normalizeFiles(request.file, request.files, { required: true })) {
1794
1799
  appendFile(form, "files", file);
@@ -1803,8 +1808,6 @@ function voiceEditForm(request) {
1803
1808
  for (const tag of request.tags)
1804
1809
  form.append("tags", tag);
1805
1810
  }
1806
- appendOptional(form, "primary_category_code", request.primaryCategoryCode);
1807
- appendOptional(form, "visibility", request.visibility);
1808
1811
  appendOptional(form, "language_code", request.languageCode);
1809
1812
  appendNullable(form, "gender", request.gender);
1810
1813
  appendNullable(form, "age", request.age);
@@ -1818,9 +1821,6 @@ function voiceEditForm(request) {
1818
1821
  }
1819
1822
  }
1820
1823
  appendNullable(form, "accent", request.accent);
1821
- for (const file of normalizeFiles(request.file, request.files, { required: false })) {
1822
- appendFile(form, "files", file);
1823
- }
1824
1824
  return form;
1825
1825
  }
1826
1826
  function stripHiddenVoiceFields(voice) {
package/dist/index.d.ts CHANGED
@@ -8,3 +8,4 @@ export { SpeechTimingStream } from "./timestamps.js";
8
8
  export type { SpeechTimingChunk, SpeechWithTimestamps, WordTimestamp } from "./timestamps.js";
9
9
  export * from "./studio.js";
10
10
  export type * from "./studio-types.js";
11
+ export * from "./output-formats.js";
package/dist/index.js CHANGED
@@ -5,3 +5,4 @@ export { SDK_NAME, SDK_VERSION } from "./version.js";
5
5
  export * from "./voice-metadata.js";
6
6
  export { SpeechTimingStream } from "./timestamps.js";
7
7
  export * from "./studio.js";
8
+ export * from "./output-formats.js";
@@ -0,0 +1,10 @@
1
+ export declare const AUDIO_ENCODINGS: readonly ["mp3", "wav", "flac", "pcm", "aac", "opus"];
2
+ export declare const TTS_OUTPUT_FORMATS: readonly ["mp3", "wav", "flac", "pcm", "aac", "opus", "mp3_24000_64", "mp3_24000_96", "mp3_24000_128", "mp3_24000_160", "wav_24000", "pcm_24000", "flac_24000", "aac_24000_128"];
3
+ export declare const STREAMING_OUTPUT_FORMATS: readonly ["pcm", "mp3", "wav"];
4
+ export declare const REALTIME_OUTPUT_FORMATS: readonly ["pcm", "mp3"];
5
+ export type TtsOutputFormat = typeof TTS_OUTPUT_FORMATS[number] | (string & {});
6
+ export type StreamingOutputFormat = typeof STREAMING_OUTPUT_FORMATS[number];
7
+ export type RealtimeOutputFormat = typeof REALTIME_OUTPUT_FORMATS[number];
8
+ export declare const DEFAULT_TTS_OUTPUT_FORMAT = "mp3";
9
+ export declare const DEFAULT_STREAM_OUTPUT_FORMAT = "pcm";
10
+ export declare const DEFAULT_REALTIME_OUTPUT_FORMAT = "pcm";
@@ -0,0 +1,8 @@
1
+ // Generated from generation_runtime.output_formats; do not edit by hand.
2
+ export const AUDIO_ENCODINGS = ["mp3", "wav", "flac", "pcm", "aac", "opus"];
3
+ export const TTS_OUTPUT_FORMATS = ["mp3", "wav", "flac", "pcm", "aac", "opus", "mp3_24000_64", "mp3_24000_96", "mp3_24000_128", "mp3_24000_160", "wav_24000", "pcm_24000", "flac_24000", "aac_24000_128"];
4
+ export const STREAMING_OUTPUT_FORMATS = ["pcm", "mp3", "wav"];
5
+ export const REALTIME_OUTPUT_FORMATS = ["pcm", "mp3"];
6
+ export const DEFAULT_TTS_OUTPUT_FORMAT = "mp3";
7
+ export const DEFAULT_STREAM_OUTPUT_FORMAT = "pcm";
8
+ export const DEFAULT_REALTIME_OUTPUT_FORMAT = "pcm";
package/dist/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { TtsOutputFormat, RealtimeOutputFormat } from "./output-formats.js";
1
2
  import type { WordTimestamp } from "./timestamps.js";
2
3
  import type { VoiceAccent, VoiceWritableAccent, VoiceAge, VoiceGender, VoiceLanguageCode, VoiceTone } from "./voice-metadata.js";
3
4
  export type JsonObject = Record<string, unknown>;
@@ -20,7 +21,7 @@ export interface RequestOptions {
20
21
  timeout?: number;
21
22
  }
22
23
  export interface AudioRequestOptions extends RequestOptions {
23
- outputFormat?: string;
24
+ outputFormat?: TtsOutputFormat;
24
25
  }
25
26
  export interface StreamTextToSpeechOptions extends AudioRequestOptions {
26
27
  enableLogging?: boolean;
@@ -38,6 +39,7 @@ export interface BreezeBlueWebSocket {
38
39
  close(code?: number, reason?: string): void;
39
40
  }
40
41
  export interface RealtimeTextToSpeechSessionRequest {
42
+ outputFormat?: RealtimeOutputFormat;
41
43
  modelId?: string;
42
44
  languageCode?: string;
43
45
  instructions?: string;
@@ -49,7 +51,8 @@ export interface RealtimeTextToSpeechAudioFormat {
49
51
  codec: "pcm_s16le" | string;
50
52
  sampleRate: number;
51
53
  channels: number;
52
- sampleWidthBits: number;
54
+ sampleWidthBits?: number | null;
55
+ bitrateKbps?: number;
53
56
  }
54
57
  export interface RealtimeTextToSpeechSession {
55
58
  clientSecret: string;
@@ -386,6 +389,7 @@ export interface UploadFile {
386
389
  contentType?: string;
387
390
  }
388
391
  export interface VoiceClonePreviewRequest {
392
+ referenceLanguageCode?: "zh";
389
393
  name?: string | null;
390
394
  file?: UploadData | UploadFile;
391
395
  files?: Array<UploadData | UploadFile>;
@@ -400,15 +404,11 @@ export interface VoiceEditRequest {
400
404
  name?: string;
401
405
  description?: string;
402
406
  tags?: string[];
403
- primaryCategoryCode?: string;
404
- visibility?: "private" | "public" | string;
405
407
  languageCode?: VoiceLanguageCode;
406
408
  gender?: VoiceGender | null;
407
409
  age?: VoiceAge | null;
408
410
  tone?: VoiceTone[];
409
411
  accent?: VoiceWritableAccent | null;
410
- file?: UploadData | UploadFile;
411
- files?: Array<UploadData | UploadFile>;
412
412
  }
413
413
  export interface VoiceDesignRequest {
414
414
  voiceDescription: string;
@@ -509,8 +509,6 @@ export interface SaveVoiceRequest {
509
509
  voiceName?: string | null;
510
510
  voiceDescription?: string | null;
511
511
  tags?: string[];
512
- primaryCategoryCode?: string;
513
- visibility?: "private" | "public" | string;
514
512
  languageCode: VoiceLanguageCode;
515
513
  gender?: VoiceGender | null;
516
514
  age?: VoiceAge | null;
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const SDK_VERSION = "0.21.1";
1
+ export declare const SDK_VERSION = "0.22.1";
2
2
  export declare const SDK_NAME = "@breeze.blue/sdk";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
- export const SDK_VERSION = "0.21.1";
1
+ export const SDK_VERSION = "0.22.1";
2
2
  export const SDK_NAME = "@breeze.blue/sdk";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@breeze.blue/sdk",
3
- "version": "0.21.1",
3
+ "version": "0.22.1",
4
4
  "description": "ESM-first TypeScript SDK for the Breeze Blue Developer API.",
5
5
  "license": "MIT",
6
6
  "author": "Breeze Blue <support@breezeblue.ai>",