@breeze.blue/sdk 0.21.1 → 0.22.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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.22.0
4
+
5
+ - Select PCM or MP3 for realtime TTS sessions and preserve the format across managed connections.
6
+ - Export output-format choices shared with the public API while retaining historical conversion profiles.
7
+ - Breaking: remove `visibility` and `primaryCategoryCode` from `voices.savePreview(...)` and `voices.edit(...)`, and remove reference-sample upload arguments from `voices.edit(...)`.
8
+ - 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.
9
+ - Voice Clone accepts `referenceLanguageCode: "zh"` to use Qwen ASR for a Chinese reference sample. Omitting it keeps automatic language detection.
10
+ - Check complete Voice and History request fields against public OpenAPI with a shared, operation-specific historical compatibility whitelist.
11
+
3
12
  ## 0.21.1
4
13
 
5
14
  - 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
 
@@ -564,7 +565,9 @@ const saved = await client.voices.savePreview({
564
565
  });
565
566
  ```
566
567
 
567
- Edit or delete a saved voice:
568
+ Saved previews are private to your account. Editing a voice's metadata preserves its visibility.
569
+
570
+ Edit a saved voice's name, description, tags, or Voice Metadata, or delete it:
568
571
 
569
572
  ```ts
570
573
  await client.voices.edit(saved.voiceId, {
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)) {
@@ -1634,8 +1638,6 @@ class VoicesResource {
1634
1638
  voiceName: request.voiceName,
1635
1639
  voiceDescription: request.voiceDescription,
1636
1640
  tags: request.tags,
1637
- primaryCategoryCode: request.primaryCategoryCode,
1638
- visibility: request.visibility,
1639
1641
  languageCode: request.languageCode,
1640
1642
  gender: request.gender,
1641
1643
  age: request.age,
@@ -1789,6 +1791,7 @@ function clonePreviewForm(request) {
1789
1791
  const form = new FormData();
1790
1792
  appendOptional(form, "name", request.name ?? undefined);
1791
1793
  appendOptional(form, "description", request.description);
1794
+ appendOptional(form, "reference_language_code", request.referenceLanguageCode);
1792
1795
  appendOptional(form, "remove_background_noise", request.removeBackgroundNoise ?? false);
1793
1796
  for (const file of normalizeFiles(request.file, request.files, { required: true })) {
1794
1797
  appendFile(form, "files", file);
@@ -1803,8 +1806,6 @@ function voiceEditForm(request) {
1803
1806
  for (const tag of request.tags)
1804
1807
  form.append("tags", tag);
1805
1808
  }
1806
- appendOptional(form, "primary_category_code", request.primaryCategoryCode);
1807
- appendOptional(form, "visibility", request.visibility);
1808
1809
  appendOptional(form, "language_code", request.languageCode);
1809
1810
  appendNullable(form, "gender", request.gender);
1810
1811
  appendNullable(form, "age", request.age);
@@ -1818,9 +1819,6 @@ function voiceEditForm(request) {
1818
1819
  }
1819
1820
  }
1820
1821
  appendNullable(form, "accent", request.accent);
1821
- for (const file of normalizeFiles(request.file, request.files, { required: false })) {
1822
- appendFile(form, "files", file);
1823
- }
1824
1822
  return form;
1825
1823
  }
1826
1824
  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.0";
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.0";
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.0",
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>",