@breeze.blue/sdk 0.3.0 → 0.4.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,24 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.0
4
+
5
+ - Added `client.textToSpeech.aiRewrite(...)` for instruction-only
6
+ text-to-speech AI Rewrite.
7
+ - Added `client.voices.random()` for fetching one visible voice to use as a
8
+ text-to-speech reference voice.
9
+ - Added account usage filters for API key, status class, client type, and date
10
+ range, plus usage log fields for API key attribution, request duration, first
11
+ audio chunk latency, and client telemetry.
12
+ - Improved typed error mapping for generation timeouts and fallback 429 rate
13
+ limit responses.
14
+
15
+ ## 0.3.1
16
+
17
+ - Added SDK-side validation for `voices.createClonePreview(...)` and
18
+ `voices.edit(...)` reference audio inputs so `file` and single-item `files`
19
+ forms are accepted, while missing or multiple clone samples are rejected
20
+ before sending a request.
21
+
3
22
  ## 0.3.0
4
23
 
5
24
  - Added async text-to-speech helpers: `client.textToSpeech.createJob(...)`,
package/README.md CHANGED
@@ -73,6 +73,11 @@ const audio = await client.textToSpeech.convert("voc_...", {
73
73
  const audioStream = await client.textToSpeech.stream("voc_...", {
74
74
  text: "Stream this line.",
75
75
  });
76
+
77
+ const rewritten = await client.textToSpeech.aiRewrite({
78
+ instruction: "Calm, warm, bedtime narration.",
79
+ languageCode: "en",
80
+ });
76
81
  ```
77
82
 
78
83
  Use async text-to-speech for long text, reference-heavy voices, or batch
@@ -135,6 +140,9 @@ const firstVoiceId = voices.voices[0].voiceId;
135
140
 
136
141
  const voice = await client.voices.get(firstVoiceId);
137
142
  const settings = await client.voices.getSettings(firstVoiceId);
143
+
144
+ const randomVoice = await client.voices.random();
145
+ console.log(randomVoice.voiceId, randomVoice.name);
138
146
  ```
139
147
 
140
148
  Breeze voice creation is always two steps: produce a **preview**, let the
@@ -163,6 +171,8 @@ const design = await client.voices.createDesignPreview({
163
171
  generatedVoiceId = design.previews[0].generatedVoiceId;
164
172
  ```
165
173
 
174
+ `files` is also accepted with exactly one item.
175
+
166
176
  Stream the preview so the user can audition it, then save the one they
167
177
  pick:
168
178
 
@@ -190,6 +200,10 @@ await client.voices.delete(saved.voiceId);
190
200
  const models = await client.models.list();
191
201
  const balance = await client.account.balance();
192
202
  const usage = await client.account.usage({ days: 7 });
203
+ const keyUsage = await client.account.usage({
204
+ apiKeyId: "key_01hprod",
205
+ clientType: "sdk",
206
+ });
193
207
 
194
208
  const history = await client.history.list({ pageSize: 10 });
195
209
  const item = await client.history.get(history.history[0].historyItemId);
package/dist/client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { AudioResponse } from "./audio.js";
2
- import type { AudioRequestOptions, AsyncTextToSpeechJob, Balance, BreezeBlueClientOptions, GenericStatus, GenerationJob, HistoryItem, HistoryList, HistoryListParams, Model, RequestOptions, SaveVoiceRequest, StreamTextToSpeechOptions, TextToSpeechRequest, Usage, UsageParams, Voice, VoiceClonePreview, VoiceClonePreviewRequest, VoiceDesignRequest, VoiceDesignResponse, VoiceEditRequest, VoiceList, VoiceSearchParams, VoiceSettings } from "./types.js";
2
+ import type { AudioRequestOptions, AsyncTextToSpeechJob, Balance, BreezeBlueClientOptions, GenericStatus, GenerationJob, HistoryItem, HistoryList, HistoryListParams, Model, RequestOptions, SaveVoiceRequest, StreamTextToSpeechOptions, TextToSpeechRequest, TtsAiRewriteRequest, TtsAiRewriteResponse, Usage, UsageParams, Voice, VoiceClonePreview, VoiceClonePreviewRequest, VoiceDesignRequest, VoiceDesignResponse, VoiceEditRequest, VoiceList, VoiceSearchParams, VoiceSettings } from "./types.js";
3
3
  export declare class BreezeBlueClient {
4
4
  readonly apiKey: string;
5
5
  readonly baseUrl: string;
@@ -24,6 +24,7 @@ declare class TextToSpeechResource {
24
24
  convert(voiceId: string, request: TextToSpeechRequest, options?: AudioRequestOptions): Promise<AudioResponse>;
25
25
  createJob(voiceId: string, request: TextToSpeechRequest, options?: AudioRequestOptions): Promise<AsyncTextToSpeechJob>;
26
26
  stream(voiceId: string, request: TextToSpeechRequest, options?: StreamTextToSpeechOptions): Promise<AudioResponse>;
27
+ aiRewrite(request: TtsAiRewriteRequest, options?: RequestOptions): Promise<TtsAiRewriteResponse>;
27
28
  }
28
29
  declare class GenerationJobsResource {
29
30
  private readonly client;
@@ -44,6 +45,7 @@ declare class VoicesResource {
44
45
  constructor(client: BreezeBlueClient);
45
46
  search(params?: VoiceSearchParams, options?: RequestOptions): Promise<VoiceList>;
46
47
  get(voiceId: string, options?: RequestOptions): Promise<Voice>;
48
+ random(options?: RequestOptions): Promise<Voice>;
47
49
  edit(voiceId: string, request: VoiceEditRequest, options?: RequestOptions): Promise<GenericStatus>;
48
50
  delete(voiceId: string, options?: RequestOptions): Promise<GenericStatus>;
49
51
  getSettings(voiceId: string, options?: RequestOptions): Promise<Required<VoiceSettings>>;
package/dist/client.js CHANGED
@@ -96,6 +96,9 @@ class TextToSpeechResource {
96
96
  enableLogging: options.enableLogging,
97
97
  }, request, options);
98
98
  }
99
+ aiRewrite(request, options) {
100
+ return this.client.requestJson("POST", "/v1/text-to-speech/ai-rewrite", undefined, request, options);
101
+ }
99
102
  }
100
103
  class GenerationJobsResource {
101
104
  client;
@@ -129,6 +132,9 @@ class VoicesResource {
129
132
  get(voiceId, options) {
130
133
  return this.client.requestJson("GET", `/v1/voices/${encodeURIComponent(voiceId)}`, undefined, undefined, options);
131
134
  }
135
+ random(options) {
136
+ return this.client.requestJson("GET", "/v1/voices/random", undefined, undefined, options);
137
+ }
132
138
  edit(voiceId, request, options) {
133
139
  return this.client.requestJson("PATCH", `/v1/voices/${encodeURIComponent(voiceId)}`, undefined, voiceEditForm(request), options);
134
140
  }
@@ -279,7 +285,7 @@ function clonePreviewForm(request) {
279
285
  appendOptional(form, "labels", request.labels ? JSON.stringify(request.labels) : undefined);
280
286
  appendOptional(form, "text", request.text);
281
287
  appendOptional(form, "instructions", request.instructions);
282
- for (const file of normalizeFiles(request.file, request.files)) {
288
+ for (const file of normalizeFiles(request.file, request.files, { required: true })) {
283
289
  appendFile(form, "files", file);
284
290
  }
285
291
  return form;
@@ -289,7 +295,7 @@ function voiceEditForm(request) {
289
295
  form.set("name", request.name);
290
296
  appendOptional(form, "description", request.description);
291
297
  appendOptional(form, "labels", request.labels ? JSON.stringify(request.labels) : undefined);
292
- for (const file of normalizeFiles(request.file, request.files)) {
298
+ for (const file of normalizeFiles(request.file, request.files, { required: false })) {
293
299
  appendFile(form, "files", file);
294
300
  }
295
301
  return form;
@@ -299,10 +305,18 @@ function appendOptional(form, key, value) {
299
305
  return;
300
306
  form.set(key, String(value));
301
307
  }
302
- function normalizeFiles(file, files) {
303
- if (files && files.length > 0)
304
- return files;
305
- return file === undefined ? [] : [file];
308
+ function normalizeFiles(file, files, options) {
309
+ if (file !== undefined && files !== undefined) {
310
+ throw new BreezeBlueConfigurationError("Pass either file or files, not both.");
311
+ }
312
+ const selected = files !== undefined ? files : file === undefined ? [] : [file];
313
+ if (options.required && selected.length === 0) {
314
+ throw new BreezeBlueConfigurationError("Exactly one sample file is required.");
315
+ }
316
+ if (selected.length > 1) {
317
+ throw new BreezeBlueConfigurationError("Exactly one sample file is currently supported.");
318
+ }
319
+ return selected;
306
320
  }
307
321
  function appendFile(form, key, input) {
308
322
  const upload = isUploadFile(input) ? input : { data: input };
package/dist/errors.js CHANGED
@@ -68,6 +68,7 @@ const codeErrorMap = new Map([
68
68
  ["UPSTREAM_BILLING_ERROR", BreezeBlueUpstreamError],
69
69
  ["UPSTREAM_GENERATION_ERROR", BreezeBlueUpstreamError],
70
70
  ["UPSTREAM_TIMEOUT", BreezeBlueUpstreamError],
71
+ ["GENERATION_TIMEOUT", BreezeBlueUpstreamError],
71
72
  ["UPSTREAM_GENERATION_SERVICE_ERROR", BreezeBlueUpstreamError],
72
73
  ["UPSTREAM_ASSET_STORAGE_ERROR", BreezeBlueUpstreamError],
73
74
  ["GENERATION_INVALID_RESPONSE", BreezeBlueUpstreamError],
@@ -141,6 +142,8 @@ function fallbackCode(status) {
141
142
  return "VALIDATION_ERROR";
142
143
  if (status === 425)
143
144
  return "GENERATION_NOT_READY";
145
+ if (status === 429)
146
+ return "RATE_LIMITED";
144
147
  if (status === 502)
145
148
  return "UPSTREAM_GENERATION_ERROR";
146
149
  if (status === 503)
package/dist/types.d.ts CHANGED
@@ -46,6 +46,14 @@ export interface TextToSpeechRequest {
46
46
  applyTextNormalization?: string;
47
47
  applyLanguageTextNormalization?: boolean;
48
48
  }
49
+ export interface TtsAiRewriteRequest {
50
+ instruction: string;
51
+ languageCode?: string | null;
52
+ }
53
+ export interface TtsAiRewriteResponse {
54
+ instruction: string;
55
+ languageCode: string;
56
+ }
49
57
  export interface AsyncTextToSpeechJob {
50
58
  generationJobId: string;
51
59
  historyItemId: string;
@@ -192,6 +200,9 @@ export interface HistoryItem {
192
200
  requestId?: string | null;
193
201
  latencyMs?: number | null;
194
202
  httpStatus?: number | null;
203
+ billableUnits?: number | null;
204
+ cost?: number | null;
205
+ costMillicredits?: number | null;
195
206
  [key: string]: unknown;
196
207
  }
197
208
  export interface HistoryList {
@@ -244,15 +255,24 @@ export interface UsageItem {
244
255
  endpoint: string;
245
256
  method: string;
246
257
  status: number;
258
+ apiKeyId?: string | null;
259
+ apiKeyName?: string | null;
260
+ apiKeyPrefix?: string | null;
247
261
  model?: string | null;
248
262
  billableUnits?: number | null;
249
263
  cost?: number | null;
250
264
  costMillicredits?: number | null;
251
265
  latencyMs?: number | null;
266
+ durationMs?: number | null;
267
+ firstAudioChunkMs?: number | null;
268
+ requestDurationMs?: number | null;
252
269
  traceId?: string | null;
253
270
  requestId?: string | null;
254
271
  textCharacters?: number | null;
255
272
  actionCode?: string | null;
273
+ clientType?: string | null;
274
+ clientName?: string | null;
275
+ clientVersion?: string | null;
256
276
  createdAt?: string | null;
257
277
  [key: string]: unknown;
258
278
  }
@@ -270,6 +290,11 @@ export interface UsageParams {
270
290
  days?: number;
271
291
  search?: string;
272
292
  method?: string;
293
+ apiKeyId?: string;
294
+ statusClass?: "2xx" | "4xx" | "5xx" | "other" | string;
295
+ clientType?: "api" | "sdk" | "cli" | string;
296
+ from?: string;
297
+ to?: string;
273
298
  page?: number;
274
299
  pageSize?: number;
275
300
  }
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const SDK_VERSION = "0.3.0";
1
+ export declare const SDK_VERSION = "0.4.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.3.0";
1
+ export const SDK_VERSION = "0.4.0";
2
2
  export const SDK_NAME = "@breeze.blue/sdk";
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@breeze.blue/sdk",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "ESM-first TypeScript SDK for the Breeze Blue Developer API.",
5
5
  "license": "MIT",
6
6
  "author": "Breeze Blue <support@breeze.blue>",
7
- "homepage": "https://breeze.blue",
7
+ "homepage": "https://breezeblue.ai",
8
8
  "keywords": [
9
9
  "audio",
10
10
  "breeze",
@@ -45,8 +45,8 @@
45
45
  "typescript": "^5.9.3"
46
46
  },
47
47
  "scripts": {
48
- "build": "pnpm exec tsc -p tsconfig.json",
49
- "typecheck": "pnpm exec tsc -p tsconfig.json --noEmit",
48
+ "build": "node node_modules/typescript/bin/tsc -p tsconfig.json",
49
+ "typecheck": "node node_modules/typescript/bin/tsc -p tsconfig.json --noEmit",
50
50
  "test": "pnpm run build && node --test ./test/*.test.js"
51
51
  }
52
52
  }