sonilo 0.6.0 → 0.7.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/README.md CHANGED
@@ -175,6 +175,57 @@ Input videos may be at most 180 seconds long.
175
175
  Use `submit()` instead of `generate()` to get a `task_id` back immediately and
176
176
  poll it yourself with `client.tasks.wait<SoundResult>(taskId)`.
177
177
 
178
+ ## Dubbing
179
+
180
+ `client.dubbing.submit()` / `.generate()` dub a video into one or more target
181
+ languages in a single async call — one call, one task, one dubbed video per
182
+ language.
183
+
184
+ ```ts
185
+ import { SoniloClient } from "sonilo";
186
+ import type { DubbingResult } from "sonilo";
187
+
188
+ const client = new SoniloClient();
189
+
190
+ const task = await client.dubbing.submit({
191
+ videoUrl: "https://example.com/clip.mp4",
192
+ languages: ["es", "fr"],
193
+ });
194
+ const result = await client.tasks.wait<DubbingResult>(task.task_id);
195
+ for (const [language, url] of Object.entries(result.outputs ?? {})) {
196
+ console.log(language, url);
197
+ }
198
+ ```
199
+
200
+ `generate()` wraps submit + poll, same as the other async endpoints, and
201
+ accepts a `{ timeout }` option to override the default 10-minute wait. The
202
+ dubbing pipeline can take much longer than that, especially with several
203
+ languages in one call, so pass a longer timeout for anything but the shortest
204
+ clips. 7,200,000 ms matches the backend's own ceiling for a dubbing job and is
205
+ what the CLI defaults to. For long jobs you can also use `submit()` plus your
206
+ own `client.tasks.wait()`, as above:
207
+
208
+ ```ts
209
+ const result = await client.dubbing.generate(
210
+ { videoUrl: "https://example.com/clip.mp4", languages: ["es", "fr"] },
211
+ { timeout: 7_200_000 }, // 2 hours, the backend's own ceiling
212
+ );
213
+ ```
214
+
215
+ Params: exactly one of `video` / `videoUrl` (`videoUrl` must be **https** —
216
+ the dubbing pipeline fetches the source itself and rejects plain http). The
217
+ optional `languages` array defaults to `["zh_cn", "es", "fr"]`; supported
218
+ codes are `en, zh_cn, ja, ko, pt, es, de, fr, it, ru`.
219
+
220
+ Dubbing is async-only, and the source video may be at most 180 seconds long.
221
+ You are billed per language. Dubbing has **no free trial allowance** — unlike
222
+ every other endpoint, every call bills from the first one (see
223
+ [Free trial](#free-trial)).
224
+
225
+ The result is a `DubbingResult`, whose `outputs` is a map of language code to
226
+ dubbed `.mp4` URL — not the `audio`/`video`/`output_url` shape the other
227
+ endpoints use.
228
+
178
229
  ## Configuration
179
230
 
180
231
  ```ts
@@ -258,15 +309,25 @@ are presigned and expire; download promptly or re-fetch via `tasks.get`.
258
309
 
259
310
  ## Free trial
260
311
 
261
- Accounts created through self-serve signup start with free runs on every
262
- endpoint — no card required:
312
+ Accounts created through self-serve signup start with free runs on most
313
+ endpoints — no card required:
263
314
 
264
315
  | Free runs | Endpoints |
265
316
  | --- | --- |
266
317
  | 2 each | text-to-music, text-to-sfx, audio-ducking |
267
318
  | 1 each | video-to-music, video-to-sfx, video-to-video-music, video-to-video-sfx, video-to-sound, video-to-video-sound |
319
+ | 0 | dubbing |
268
320
 
269
321
  Once an endpoint's free runs are used up, calls to it bill at the normal rate.
322
+ **Dubbing has no free trial allowance at all** — it bills every call from the
323
+ first one. This is deliberate: dubbing charges `video_duration ×
324
+ number_of_languages`, so a single "free" run could easily cost more than the
325
+ free allowance on every other endpoint combined.
326
+
327
+ The table above is the current default. Read the live numbers from
328
+ `account.services()` rather than hard-coding them — see
329
+ [Account](#account) below, and [Errors](#errors) for what a spent trial
330
+ looks like at the call site.
270
331
 
271
332
  ## Account
272
333
 
@@ -275,10 +336,27 @@ const services = await sonilo.account.services();
275
336
  const usage = await sonilo.account.usage({ days: 7 });
276
337
  ```
277
338
 
339
+ `services.trial` reports the free-trial allowance per service, so an
340
+ integration can degrade gracefully *before* a call fails:
341
+
342
+ ```ts
343
+ const { trial } = await sonilo.account.services();
344
+ const quota = trial?.text_to_music;
345
+ if (quota && quota.remaining === 0) {
346
+ // Prompt for a payment method instead of firing a call that will 402.
347
+ console.log(`Free trial spent (${quota.used}/${quota.granted}).`);
348
+ }
349
+ ```
350
+
351
+ `trial` is present only for self-serve accounts, so always treat it as
352
+ optional; a service missing from the map has no trial allowance rather than
353
+ an unlimited one.
354
+
278
355
  ## Errors
279
356
 
280
357
  All errors extend `SoniloError`: `AuthenticationError` (401),
281
- `PaymentRequiredError` (402), `RateLimitError` (429, `.retryAfter`),
358
+ `PaymentRequiredError` (402), `TrialExhaustedError` (402, a subclass of
359
+ `PaymentRequiredError`), `RateLimitError` (429, `.retryAfter`),
282
360
  `BadRequestError` (400/413/422, `.detail`), `APIError` (anything else),
283
361
  `GenerationError` for failures mid-stream, `TaskFailedError` (`.code`,
284
362
  `.taskId`, `.refunded`) for a failed SFX task, `TaskTimeoutError`
@@ -292,3 +370,29 @@ Every `APIError` also carries `.status`, `.body` (the parsed response),
292
370
  `.code` (the API's error code, e.g. `"rate_limit_exceeded"`), and `.errors`
293
371
  (the validation detail array on a 422), in addition to any subclass-specific
294
372
  properties above.
373
+
374
+ ### The three 402s
375
+
376
+ A `402` is not one condition. Branch on the class (or equivalently on
377
+ `.code`), never on the message text:
378
+
379
+ ```ts
380
+ try {
381
+ await sonilo.textToMusic.generate({ prompt: "lofi", duration: 30 });
382
+ } catch (err) {
383
+ if (err instanceof TrialExhaustedError) {
384
+ // code: "trial_exhausted" — the free trial for this service is spent and
385
+ // the account has never been funded. Prompt for a payment method; a retry
386
+ // can never succeed.
387
+ } else if (err instanceof PaymentRequiredError) {
388
+ // code: "insufficient_balance" — a funded wallet ran dry. Add balance and
389
+ // retry the same request.
390
+ // code: "payment_required" — anything else, e.g. a suspended account.
391
+ }
392
+ }
393
+ ```
394
+
395
+ `TrialExhaustedError` extends `PaymentRequiredError`, so an existing
396
+ `catch (err) { if (err instanceof PaymentRequiredError) ... }` keeps
397
+ catching every 402 — order the checks most-specific-first if you want to
398
+ tell them apart.
package/dist/index.cjs CHANGED
@@ -32,6 +32,7 @@ __export(index_exports, {
32
32
  SoniloError: () => SoniloError,
33
33
  TaskFailedError: () => TaskFailedError,
34
34
  TaskTimeoutError: () => TaskTimeoutError,
35
+ TrialExhaustedError: () => TrialExhaustedError,
35
36
  VERSION: () => VERSION,
36
37
  download: () => download,
37
38
  isAudioChunkEvent: () => isAudioChunkEvent,
@@ -60,6 +61,8 @@ var AuthenticationError = class extends APIError {
60
61
  };
61
62
  var PaymentRequiredError = class extends APIError {
62
63
  };
64
+ var TrialExhaustedError = class extends PaymentRequiredError {
65
+ };
63
66
  var BadRequestError = class extends APIError {
64
67
  get detail() {
65
68
  const body = this.body;
@@ -129,8 +132,13 @@ async function errorFromResponse(res) {
129
132
  switch (res.status) {
130
133
  case 401:
131
134
  return new AuthenticationError(message, res.status, body);
132
- case 402:
135
+ case 402: {
136
+ const code = body?.code;
137
+ if (code === "trial_exhausted") {
138
+ return new TrialExhaustedError(message, res.status, body);
139
+ }
133
140
  return new PaymentRequiredError(message, res.status, body);
141
+ }
134
142
  case 429: {
135
143
  const ra = res.headers.get("retry-after");
136
144
  const retryAfter = ra !== null && ra !== "" && !Number.isNaN(Number(ra)) ? Number(ra) : void 0;
@@ -665,8 +673,48 @@ var VideoToVideoSound = class {
665
673
  }
666
674
  };
667
675
 
676
+ // src/resources/dubbing.ts
677
+ async function buildDubbingForm(params) {
678
+ if (params.video === void 0 === (params.videoUrl === void 0)) {
679
+ throw new SoniloError("Provide exactly one of video or videoUrl");
680
+ }
681
+ const form = new FormData();
682
+ if (params.video !== void 0) {
683
+ const { blob, filename } = await toUploadBlob(params.video);
684
+ form.set("video", blob, filename);
685
+ } else {
686
+ const url = params.videoUrl;
687
+ if (!url.toLowerCase().startsWith("https://")) {
688
+ throw new SoniloError(
689
+ "videoUrl must use https \u2014 the dubbing pipeline requires an https URL"
690
+ );
691
+ }
692
+ form.set("video_url", url);
693
+ }
694
+ if (params.languages !== void 0) {
695
+ form.set("languages", JSON.stringify(params.languages));
696
+ }
697
+ return form;
698
+ }
699
+ var Dubbing = class {
700
+ constructor(client) {
701
+ this.client = client;
702
+ }
703
+ async submit(params) {
704
+ const res = await this.client.request("/v1/dubbing", {
705
+ method: "POST",
706
+ body: await buildDubbingForm(params)
707
+ });
708
+ return await res.json();
709
+ }
710
+ async generate(params, opts) {
711
+ const task = await this.submit(params);
712
+ return this.client.tasks.wait(task.task_id, opts);
713
+ }
714
+ };
715
+
668
716
  // src/version.ts
669
- var VERSION = "0.6.0";
717
+ var VERSION = "0.7.0";
670
718
 
671
719
  // src/client.ts
672
720
  var DEFAULT_BASE_URL = "https://api.sonilo.com";
@@ -697,6 +745,7 @@ var SoniloClient = class {
697
745
  this.videoToVideoSfx = new VideoToVideoSfx(this);
698
746
  this.videoToSound = new VideoToSound(this);
699
747
  this.videoToVideoSound = new VideoToVideoSound(this);
748
+ this.dubbing = new Dubbing(this);
700
749
  }
701
750
  /**
702
751
  * Perform an authenticated request; throws a typed error on non-2xx.
@@ -769,6 +818,7 @@ function isErrorEvent(event) {
769
818
  SoniloError,
770
819
  TaskFailedError,
771
820
  TaskTimeoutError,
821
+ TrialExhaustedError,
772
822
  VERSION,
773
823
  download,
774
824
  isAudioChunkEvent,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/resources/account.ts","../src/resources/tasks.ts","../src/streaming.ts","../src/resources/textToMusic.ts","../src/upload.ts","../src/resources/videoToMusic.ts","../src/resources/textToSfx.ts","../src/resources/videoToSfx.ts","../src/resources/videoToVideoMusic.ts","../src/resources/videoToVideoSfx.ts","../src/resources/soundForm.ts","../src/resources/videoToSound.ts","../src/resources/videoToVideoSound.ts","../src/version.ts","../src/client.ts","../src/download.ts","../src/types.ts"],"sourcesContent":["export { DEFAULT_TIMEOUT_MS, SoniloClient, type SoniloClientOptions } from \"./client.js\";\nexport {\n APIError,\n AuthenticationError,\n BadRequestError,\n GenerationError,\n PaymentRequiredError,\n RateLimitError,\n RequestTimeoutError,\n SoniloError,\n TaskFailedError,\n TaskTimeoutError,\n} from \"./errors.js\";\nexport { download } from \"./download.js\";\nexport { VERSION } from \"./version.js\";\nexport type {\n AccountServices,\n AudioChunkEvent,\n BaseTaskResult,\n CompleteEvent,\n CostEvent,\n CostInfo,\n DailyUsage,\n ErrorEvent,\n MusicMediaEntry,\n MusicMuxEntry,\n MusicTaskResult,\n MusicTitle,\n Segment,\n SegmentLabel,\n SfxAudioFormat,\n SfxError,\n SfxMedia,\n SfxResult,\n SfxSegment,\n SfxTask,\n SoundResult,\n StreamEvent,\n TextToMusicParams,\n TextToSfxParams,\n TitleEvent,\n Track,\n TrialQuota,\n UnknownEvent,\n UsageResponse,\n UsageSummary,\n VideoInput,\n VideoResult,\n VideoToMusicParams,\n VideoToSfxParams,\n VideoToSoundParams,\n VideoToVideoMusicParams,\n VideoToVideoSfxParams,\n WaitOptions,\n} from \"./types.js\";\nexport { isAudioChunkEvent, isErrorEvent } from \"./types.js\";\n","export class SoniloError extends Error {\n constructor(message: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\nexport class APIError extends SoniloError {\n readonly status: number;\n readonly body: unknown;\n /** The API's typed error code (e.g. \"rate_limit_exceeded\"), distinct from the HTTP status. */\n readonly code?: string;\n /** Per-field validation details, present on a 422. */\n readonly errors?: unknown[];\n\n constructor(message: string, status: number, body?: unknown) {\n super(message);\n this.status = status;\n this.body = body;\n const parsed = body as { code?: unknown; errors?: unknown } | undefined;\n this.code = typeof parsed?.code === \"string\" ? parsed.code : undefined;\n this.errors = Array.isArray(parsed?.errors) ? parsed.errors : undefined;\n }\n}\n\nexport class AuthenticationError extends APIError {}\n\nexport class PaymentRequiredError extends APIError {}\n\nexport class BadRequestError extends APIError {\n get detail(): string | undefined {\n const body = this.body as { message?: unknown; detail?: unknown } | undefined;\n if (typeof body?.message === \"string\" && body.message) {\n return body.message;\n }\n return typeof body?.detail === \"string\" ? body.detail : undefined;\n }\n}\n\nexport class RateLimitError extends APIError {\n readonly retryAfter?: number;\n\n constructor(message: string, status: number, body?: unknown, retryAfter?: number) {\n super(message, status, body);\n this.retryAfter = retryAfter;\n }\n}\n\n/** Raised by generate() when an `error` event arrives mid-stream. */\nexport class GenerationError extends SoniloError {\n readonly code?: string;\n\n constructor(message: string, code?: string) {\n super(message);\n this.code = code;\n }\n}\n\n/** Raised by tasks.wait()/generate() when an SFX task reaches `failed`. */\nexport class TaskFailedError extends SoniloError {\n readonly code?: string;\n readonly taskId: string;\n readonly refunded?: boolean;\n\n constructor(\n message: string,\n opts: { code?: string; taskId: string; refunded?: boolean },\n ) {\n super(message);\n this.code = opts.code;\n this.taskId = opts.taskId;\n this.refunded = opts.refunded;\n }\n}\n\n/** Poll deadline passed. The task may still finish server-side — resume with\n * tasks.wait(taskId) or tasks.get(taskId). */\nexport class TaskTimeoutError extends SoniloError {\n readonly taskId: string;\n\n constructor(message: string, taskId: string) {\n super(message);\n this.taskId = taskId;\n }\n}\n\n/** Raised when a one-shot request or download is aborted by its own timeout\n * signal (as opposed to a caller-supplied AbortSignal, which propagates\n * untouched). */\nexport class RequestTimeoutError extends SoniloError {}\n\n/**\n * True if `err` is the rejection produced when an `AbortSignal.timeout()`\n * we created fires. Used to distinguish \"our\" timeout aborts (which should be\n * rethrown as `RequestTimeoutError`) from a caller-supplied signal's abort\n * (which must propagate untouched).\n */\nexport function isTimeoutSignalError(err: unknown): boolean {\n return err instanceof Error && (err.name === \"TimeoutError\" || err.name === \"AbortError\");\n}\n\nexport async function errorFromResponse(res: Response): Promise<APIError> {\n const text = await res.text().catch(() => \"\");\n let body: unknown = text;\n try {\n body = JSON.parse(text);\n } catch {\n // keep raw text\n }\n const parsed = body as { message?: unknown; detail?: unknown } | undefined;\n const rawMessage = typeof parsed?.message === \"string\" && parsed.message ? parsed.message : undefined;\n const rawDetail = parsed?.detail;\n const isDetailAbsent = rawDetail === undefined || rawDetail === null || rawDetail === \"\";\n let reason: string;\n if (rawMessage !== undefined) {\n reason = rawMessage;\n } else if (isDetailAbsent) {\n reason = res.statusText || \"request failed\";\n } else if (typeof rawDetail === \"string\") {\n reason = rawDetail;\n } else {\n try {\n reason = JSON.stringify(rawDetail);\n } catch {\n reason = res.statusText || \"request failed\";\n }\n }\n const message = `HTTP ${res.status}: ${reason}`;\n\n switch (res.status) {\n case 401:\n return new AuthenticationError(message, res.status, body);\n case 402:\n return new PaymentRequiredError(message, res.status, body);\n case 429: {\n const ra = res.headers.get(\"retry-after\");\n const retryAfter = ra !== null && ra !== \"\" && !Number.isNaN(Number(ra)) ? Number(ra) : undefined;\n return new RateLimitError(message, res.status, body, retryAfter);\n }\n case 400:\n case 413:\n case 422:\n return new BadRequestError(message, res.status, body);\n default:\n return new APIError(message, res.status, body);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport type { AccountServices, UsageResponse } from \"../types.js\";\n\nexport class Account {\n constructor(private readonly client: SoniloClient) {}\n\n async services(): Promise<AccountServices> {\n const res = await this.client.request(\"/v1/account/services\");\n return (await res.json()) as AccountServices;\n }\n\n async usage(params: { days?: number } = {}): Promise<UsageResponse> {\n const query = params.days !== undefined ? `?days=${params.days}` : \"\";\n const res = await this.client.request(`/v1/account/usage${query}`);\n return (await res.json()) as UsageResponse;\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError, TaskFailedError, TaskTimeoutError } from \"../errors.js\";\nimport type { BaseTaskResult, SfxResult, WaitOptions } from \"../types.js\";\n\nexport const DEFAULT_POLL_INTERVAL_MS = 2000;\nexport const DEFAULT_WAIT_TIMEOUT_MS = 600_000;\n\nconst sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));\n\n/** A negative delay is clamped to 0 by setTimeout, which would turn the poll\n * loop into a busy loop hammering the API until the deadline. */\nfunction validateWaitArgs(pollInterval: number, timeout: number): void {\n if (pollInterval < 0) {\n throw new SoniloError(`pollInterval must be >= 0, got ${pollInterval}`);\n }\n if (timeout < 0) {\n throw new SoniloError(`timeout must be >= 0, got ${timeout}`);\n }\n}\n\nexport class Tasks {\n constructor(private readonly client: SoniloClient) {}\n\n /**\n * Fetch current task state. Never throws on a failed status.\n *\n * Generic over the result shape so callers can request the endpoint-\n * specific type, e.g. `client.tasks.get<MusicTaskResult>(taskId)`.\n * Defaults to `SfxResult` for back-compat.\n */\n async get<T extends BaseTaskResult = SfxResult>(taskId: string): Promise<T> {\n const res = await this.client.request(`/v1/tasks/${encodeURIComponent(taskId)}`);\n return (await res.json()) as T;\n }\n\n /**\n * Poll until the task is terminal; throw on failure or deadline.\n *\n * Generic over the result shape, e.g.\n * `client.tasks.wait<MusicTaskResult>(taskId)`. Defaults to `SfxResult`\n * for back-compat.\n */\n async wait<T extends BaseTaskResult = SfxResult>(\n taskId: string,\n opts: WaitOptions = {},\n ): Promise<T> {\n const pollInterval = opts.pollInterval ?? DEFAULT_POLL_INTERVAL_MS;\n const timeout = opts.timeout ?? DEFAULT_WAIT_TIMEOUT_MS;\n validateWaitArgs(pollInterval, timeout);\n const deadline = performance.now() + timeout;\n for (;;) {\n const result = await this.get<T>(taskId);\n if (result.status === \"succeeded\") return result;\n if (result.status === \"failed\") {\n const message = result.error?.message || \"Generation failed\";\n throw new TaskFailedError(`Task ${taskId} failed: ${message}`, {\n code: result.error?.code,\n taskId,\n refunded: result.refunded,\n });\n }\n const remaining = deadline - performance.now();\n if (remaining <= 0) {\n throw new TaskTimeoutError(\n `Task ${taskId} still processing after ${timeout}ms; ` +\n \"it may finish later — resume with tasks.wait or tasks.get\",\n taskId,\n );\n }\n await sleep(Math.min(pollInterval, remaining));\n }\n }\n}\n","import { GenerationError } from \"./errors.js\";\nimport type { CostInfo, StreamEvent, Track } from \"./types.js\";\n\nexport function decodeBase64(b64: string): Uint8Array {\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n}\n\n/** Returns `null` for a valid-JSON-but-non-object line (e.g. a bare `null`\n * or a number/string), which carries no event `type` and is skipped like any\n * other junk line rather than crashing on a `.type` read off `null`. */\nfunction toEvent(line: string): StreamEvent | null {\n const parsed: unknown = JSON.parse(line);\n if (typeof parsed !== \"object\" || parsed === null) return null;\n const raw = parsed as { type: string; [key: string]: unknown };\n if (raw.type === \"audio_chunk\" && typeof raw.data === \"string\") {\n try {\n return { ...raw, type: \"audio_chunk\", data: decodeBase64(raw.data) };\n } catch {\n // Don't raise here: this must reach collectTrack's malformed-chunk\n // check, which turns undecodable data into a typed GenerationError.\n // Raising in place would let a raw DOMException escape\n // stream()/generate(), breaking the SDK's \"all errors extend\n // SoniloError\" contract.\n }\n }\n return raw as StreamEvent;\n}\n\nexport async function* parseNdjson(\n body: ReadableStream<Uint8Array>,\n): AsyncGenerator<StreamEvent, void, undefined> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n let nl: number;\n while ((nl = buffer.indexOf(\"\\n\")) !== -1) {\n const line = buffer.slice(0, nl).trim();\n buffer = buffer.slice(nl + 1);\n if (line) {\n const ev = toEvent(line);\n if (ev !== null) yield ev;\n }\n }\n }\n buffer += decoder.decode();\n const tail = buffer.trim();\n if (tail) {\n const ev = toEvent(tail);\n if (ev !== null) yield ev;\n }\n } finally {\n await reader.cancel().catch(() => {});\n }\n}\n\nexport async function collectTrack(events: AsyncIterable<StreamEvent>): Promise<Track> {\n const chunks: Uint8Array[] = [];\n let title: string | undefined;\n let cost: CostInfo | undefined;\n let sawComplete = false;\n\n for await (const ev of events) {\n if (ev.type === \"audio_chunk\") {\n // A malformed chunk (missing/non-decodable `data`) must not be\n // silently dropped: that would hand back a \"successful\" Track with\n // empty or truncated audio and no indication anything went wrong.\n if (!(ev.data instanceof Uint8Array)) {\n throw new GenerationError(\n \"received a malformed audio_chunk event (missing or non-decodable data)\",\n );\n }\n chunks.push(ev.data);\n } else if (ev.type === \"title\" && typeof ev.title === \"string\") {\n title = ev.title;\n } else if (ev.type === \"cost\") {\n const { type: _type, ...rest } = ev;\n cost = rest as CostInfo;\n } else if (ev.type === \"error\") {\n const message = typeof ev.message === \"string\" && ev.message !== \"\" ? ev.message : \"generation failed\";\n const code = typeof ev.code === \"string\" ? ev.code : undefined;\n throw new GenerationError(message, code);\n } else if (ev.type === \"complete\") {\n sawComplete = true;\n }\n // unknown event types: ignored\n }\n\n if (!sawComplete) {\n throw new GenerationError(\"stream ended before a 'complete' event (truncated response)\");\n }\n\n const total = chunks.reduce((n, c) => n + c.length, 0);\n const audio = new Uint8Array(total);\n let offset = 0;\n for (const c of chunks) {\n audio.set(c, offset);\n offset += c.length;\n }\n return { audio, title, cost };\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { collectTrack, parseNdjson } from \"../streaming.js\";\nimport type { SfxTask, StreamEvent, TextToMusicParams, Track } from \"../types.js\";\n\nexport class TextToMusic {\n constructor(private readonly client: SoniloClient) {}\n\n /** Stream raw generation events (audio chunks pre-decoded to bytes). */\n async *stream(params: TextToMusicParams): AsyncGenerator<StreamEvent, void, undefined> {\n const form = new FormData();\n form.set(\"prompt\", params.prompt);\n form.set(\"duration\", String(params.duration));\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n // Opt out of the client's absolute request timeout: this holds the\n // response body open and reads NDJSON chunks for as long as generation\n // takes, so an AbortSignal keyed to elapsed time would kill a healthy,\n // still-streaming, long-duration track. Pass `params.signal` yourself to\n // bound or cancel the stream instead — it is forwarded to `fetch` as-is.\n const res = await this.client.request(\n \"/v1/text-to-music\",\n { method: \"POST\", body: form, signal: params.signal },\n { timeout: null },\n );\n if (!res.body) throw new SoniloError(\"Response has no body\");\n yield* parseNdjson(res.body);\n }\n\n /** Generate and buffer the whole track; throws GenerationError on stream errors. */\n generate(params: TextToMusicParams): Promise<Track> {\n return collectTrack(this.stream(params));\n }\n\n /**\n * Submit an async text-to-music task; poll with\n * `client.tasks.wait<MusicTaskResult>(task.task_id)`. Required for\n * `outputFormat: \"wav\"`. `stream()`/`generate()` remain the streaming path.\n */\n async submit(params: TextToMusicParams): Promise<SfxTask> {\n const mode = params.mode ?? \"async\";\n if (mode !== \"async\") {\n throw new SoniloError('submit() requires mode: \"async\"');\n }\n const form = new FormData();\n form.set(\"prompt\", params.prompt);\n form.set(\"duration\", String(params.duration));\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n form.set(\"mode\", mode);\n if (params.outputFormat !== undefined) {\n form.set(\"output_format\", params.outputFormat);\n }\n const res = await this.client.request(\"/v1/text-to-music\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n}\n","import { SoniloError } from \"./errors.js\";\nimport type { VideoInput } from \"./types.js\";\n\nconst DEFAULT_FILENAME = \"video.mp4\";\n\n/**\n * Normalize every accepted video input into a FormData-ready Blob.\n * String inputs are file paths and work only in Node.js; browsers must\n * pass File/Blob/bytes/streams.\n */\nexport async function toUploadBlob(\n video: VideoInput,\n): Promise<{ blob: Blob; filename: string }> {\n if (typeof video === \"string\") {\n const isNode =\n typeof process !== \"undefined\" && Boolean((process as { versions?: { node?: string } }).versions?.node);\n if (!isNode) {\n throw new SoniloError(\n \"File paths are only supported in Node.js; pass a File or Blob in the browser\",\n );\n }\n const fsModule = \"node:fs/promises\";\n const { readFile } = (await import(\n /* webpackIgnore: true */ /* @vite-ignore */ fsModule\n )) as typeof import(\"node:fs/promises\");\n const data = await readFile(video);\n const filename = video.split(/[\\\\/]/).pop() || DEFAULT_FILENAME;\n return { blob: new Blob([data]), filename };\n }\n if (typeof File !== \"undefined\" && video instanceof File) {\n return { blob: video, filename: video.name || DEFAULT_FILENAME };\n }\n if (video instanceof Blob) {\n return { blob: video, filename: DEFAULT_FILENAME };\n }\n if (video instanceof Uint8Array) {\n return { blob: new Blob([video as unknown as BlobPart]), filename: DEFAULT_FILENAME };\n }\n if (video instanceof ArrayBuffer) {\n return { blob: new Blob([video]), filename: DEFAULT_FILENAME };\n }\n if (video instanceof ReadableStream) {\n return { blob: await new Response(video).blob(), filename: DEFAULT_FILENAME };\n }\n throw new SoniloError(\"Unsupported video input type\");\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { collectTrack, parseNdjson } from \"../streaming.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { SfxTask, StreamEvent, Track, VideoToMusicParams } from \"../types.js\";\n\nexport class VideoToMusic {\n constructor(private readonly client: SoniloClient) {}\n\n async *stream(params: VideoToMusicParams): AsyncGenerator<StreamEvent, void, undefined> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n // Opt out of the client's absolute request timeout: this holds the\n // response body open and reads NDJSON chunks for as long as generation\n // takes, so an AbortSignal keyed to elapsed time would kill a healthy,\n // still-streaming request (e.g. a slow video upload or long track). Pass\n // `params.signal` yourself to bound or cancel the stream instead — it is\n // forwarded to `fetch` as-is.\n const res = await this.client.request(\n \"/v1/video-to-music\",\n { method: \"POST\", body: form, signal: params.signal },\n { timeout: null },\n );\n if (!res.body) throw new SoniloError(\"Response has no body\");\n yield* parseNdjson(res.body);\n }\n\n generate(params: VideoToMusicParams): Promise<Track> {\n return collectTrack(this.stream(params));\n }\n\n /**\n * Submit an async video-to-music task; poll its result with\n * `client.tasks.wait<MusicTaskResult>(task.task_id)`. Required for\n * `isolateVocals` — the backend rejects vocal isolation on the plain\n * stream, and it only ever runs in async mode.\n */\n async submit(params: VideoToMusicParams): Promise<SfxTask> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n let mode = params.mode;\n const needsAsync =\n params.isolateVocals ||\n params.preserveSpeech ||\n params.ducking !== undefined ||\n params.outputFormat === \"wav\";\n // submit() always wants an async task ack, never a stream. Default to\n // async; only object if the caller explicitly asked for stream while\n // also requesting an async-only feature.\n if (mode === undefined) mode = \"async\";\n if (needsAsync && mode !== \"async\") {\n throw new SoniloError(\n 'isolateVocals/preserveSpeech/ducking/outputFormat \"wav\" require mode: \"async\"',\n );\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n form.set(\"mode\", mode);\n if (params.preserveSpeech !== undefined) {\n form.set(\"preserve_speech\", String(params.preserveSpeech));\n }\n if (params.isolateVocals !== undefined) {\n form.set(\"isolate_vocals\", String(params.isolateVocals));\n }\n if (params.outputFormat !== undefined) {\n form.set(\"output_format\", params.outputFormat);\n }\n if (params.ducking !== undefined) {\n form.set(\"ducking\", String(params.ducking));\n }\n const res = await this.client.request(\"/v1/video-to-music\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport type { SfxResult, SfxTask, TextToSfxParams, WaitOptions } from \"../types.js\";\n\nexport class TextToSfx {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: TextToSfxParams): Promise<SfxTask> {\n const form = new FormData();\n form.set(\"prompt\", params.prompt);\n form.set(\"duration\", String(params.duration));\n if (params.audioFormat !== undefined) form.set(\"audio_format\", params.audioFormat);\n const res = await this.client.request(\"/v1/text-to-sfx\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: TextToSfxParams, opts?: WaitOptions): Promise<SfxResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait(task.task_id, opts);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { SfxResult, SfxTask, VideoToSfxParams, WaitOptions } from \"../types.js\";\n\nexport class VideoToSfx {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToSfxParams): Promise<SfxTask> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n if (params.audioFormat !== undefined) form.set(\"audio_format\", params.audioFormat);\n const res = await this.client.request(\"/v1/video-to-sfx\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToSfxParams, opts?: WaitOptions): Promise<SfxResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait(task.task_id, opts);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { SfxTask, VideoResult, VideoToVideoMusicParams, WaitOptions } from \"../types.js\";\n\n/** Generate an original score for a video and get back a re-hosted video with\n * the music muxed in. Async only: `submit()` returns a task ack; poll with\n * `client.tasks.wait<VideoResult>(id)`, or use `generate()` to do both. */\nexport class VideoToVideoMusic {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToVideoMusicParams): Promise<SfxTask> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.preserveSpeech !== undefined) {\n form.set(\"preserve_speech\", String(params.preserveSpeech));\n }\n if (params.isolateVocals !== undefined) {\n form.set(\"isolate_vocals\", String(params.isolateVocals));\n }\n const res = await this.client.request(\"/v1/video-to-video-music\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToVideoMusicParams, opts?: WaitOptions): Promise<VideoResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait<VideoResult>(task.task_id, opts);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { SfxTask, VideoResult, VideoToVideoSfxParams, WaitOptions } from \"../types.js\";\n\n/** Generate sound effects for a video and get back a re-hosted video with the\n * SFX muxed in. Async only. */\nexport class VideoToVideoSfx {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToVideoSfxParams): Promise<SfxTask> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n const res = await this.client.request(\"/v1/video-to-video-sfx\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToVideoSfxParams, opts?: WaitOptions): Promise<VideoResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait<VideoResult>(task.task_id, opts);\n }\n}\n","import { SoniloError } from \"../errors.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { VideoToSoundParams } from \"../types.js\";\n\n/** Build the multipart body shared by /v1/video-to-sound and\n * /v1/video-to-video-sound — their form fields are identical, so the two\n * resources differ only in the path they POST to.\n *\n * Every optional field is omitted when unset rather than sent with a default:\n * `ducking` in particular is default-ON server-side, so an unset value must\n * not become an explicit \"false\" on the wire. */\nexport async function buildSoundForm(params: VideoToSoundParams): Promise<FormData> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.musicPrompt !== undefined) form.set(\"music_prompt\", params.musicPrompt);\n if (params.sfxPrompt !== undefined) form.set(\"sfx_prompt\", params.sfxPrompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n if (params.preserveSpeech !== undefined) {\n form.set(\"preserve_speech\", String(params.preserveSpeech));\n }\n if (params.ducking !== undefined) form.set(\"ducking\", String(params.ducking));\n return form;\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { buildSoundForm } from \"./soundForm.js\";\nimport type { SfxTask, SoundResult, VideoToSoundParams, WaitOptions } from \"../types.js\";\n\n/** Generate a combined music + sound-effects track for a video and get back\n * the mixed audio. Async only. */\nexport class VideoToSound {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToSoundParams): Promise<SfxTask> {\n const res = await this.client.request(\"/v1/video-to-sound\", {\n method: \"POST\",\n body: await buildSoundForm(params),\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToSoundParams, opts?: WaitOptions): Promise<SoundResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait<SoundResult>(task.task_id, opts);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { buildSoundForm } from \"./soundForm.js\";\nimport type { SfxTask, SoundResult, VideoToSoundParams, WaitOptions } from \"../types.js\";\n\n/** Generate a combined music + sound-effects track for a video and get back a\n * re-hosted video with that track muxed in. Async only. */\nexport class VideoToVideoSound {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToSoundParams): Promise<SfxTask> {\n const res = await this.client.request(\"/v1/video-to-video-sound\", {\n method: \"POST\",\n body: await buildSoundForm(params),\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToSoundParams, opts?: WaitOptions): Promise<SoundResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait<SoundResult>(task.task_id, opts);\n }\n}\n","/** The SDK's own version. Generated by scripts/sync-versions.mjs — do not edit. */\nexport const VERSION = \"0.6.0\";\n","import { RequestTimeoutError, SoniloError, errorFromResponse, isTimeoutSignalError } from \"./errors.js\";\nimport { Account } from \"./resources/account.js\";\nimport { Tasks } from \"./resources/tasks.js\";\nimport { TextToMusic } from \"./resources/textToMusic.js\";\nimport { VideoToMusic } from \"./resources/videoToMusic.js\";\nimport { TextToSfx } from \"./resources/textToSfx.js\";\nimport { VideoToSfx } from \"./resources/videoToSfx.js\";\nimport { VideoToVideoMusic } from \"./resources/videoToVideoMusic.js\";\nimport { VideoToVideoSfx } from \"./resources/videoToVideoSfx.js\";\nimport { VideoToSound } from \"./resources/videoToSound.js\";\nimport { VideoToVideoSound } from \"./resources/videoToVideoSound.js\";\nimport { VERSION } from \"./version.js\";\n\nexport interface SoniloClientOptions {\n /** Defaults to the SONILO_API_KEY environment variable (Node.js only). */\n apiKey?: string;\n /** Defaults to https://api.sonilo.com */\n baseUrl?: string;\n /** Injection point for tests and custom transports. */\n fetch?: typeof globalThis.fetch;\n /** Milliseconds before an in-flight request is aborted. Default 600000. */\n timeout?: number;\n /**\n * Identifies a wrapper built on this SDK (the CLI, the video kit) in the\n * `X-Sonilo-Client` header. Leave unset for direct SDK use — without an\n * override a wrapper's traffic is indistinguishable from the SDK's own.\n */\n clientName?: string;\n /** Version reported alongside `clientName`. Defaults to the SDK's version. */\n clientVersion?: string;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.sonilo.com\";\n\n/**\n * Reported in `X-Sonilo-Client` unless a wrapper overrides it. First-party\n * wrappers (the CLI, the video kit) pass their own name so their traffic stays\n * distinguishable from direct SDK use in server-side analytics.\n */\nexport const DEFAULT_CLIENT_NAME = \"sdk-js\";\n\n/** Milliseconds before an in-flight request is aborted, unless overridden. */\nexport const DEFAULT_TIMEOUT_MS = 600_000;\n\nexport class SoniloClient {\n readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly fetchFn: typeof globalThis.fetch;\n private readonly timeout: number;\n private readonly clientName: string;\n private readonly clientVersion: string;\n readonly account: Account;\n readonly tasks: Tasks;\n readonly textToMusic: TextToMusic;\n readonly videoToMusic: VideoToMusic;\n readonly textToSfx: TextToSfx;\n readonly videoToSfx: VideoToSfx;\n readonly videoToVideoMusic: VideoToVideoMusic;\n readonly videoToVideoSfx: VideoToVideoSfx;\n readonly videoToSound: VideoToSound;\n readonly videoToVideoSound: VideoToVideoSound;\n\n constructor(options: SoniloClientOptions = {}) {\n const envKey =\n typeof process !== \"undefined\" ? process.env?.SONILO_API_KEY : undefined;\n const apiKey = options.apiKey ?? envKey;\n if (!apiKey) {\n throw new SoniloError(\n \"Missing API key: pass { apiKey } or set the SONILO_API_KEY environment variable\",\n );\n }\n this.apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.fetchFn = (options.fetch ?? globalThis.fetch).bind(globalThis);\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;\n this.clientName = options.clientName ?? DEFAULT_CLIENT_NAME;\n this.clientVersion = options.clientVersion ?? VERSION;\n this.account = new Account(this);\n this.tasks = new Tasks(this);\n this.textToMusic = new TextToMusic(this);\n this.videoToMusic = new VideoToMusic(this);\n this.textToSfx = new TextToSfx(this);\n this.videoToSfx = new VideoToSfx(this);\n this.videoToVideoMusic = new VideoToVideoMusic(this);\n this.videoToVideoSfx = new VideoToVideoSfx(this);\n this.videoToSound = new VideoToSound(this);\n this.videoToVideoSound = new VideoToVideoSound(this);\n }\n\n /**\n * Perform an authenticated request; throws a typed error on non-2xx.\n *\n * `opts.timeout` overrides the client's default timeout for this call;\n * pass `null` to disable the abort-on-timeout behavior entirely (used by\n * the streaming music endpoints — see textToMusic.ts / videoToMusic.ts).\n * A caller-supplied `init.signal` always wins over any timeout signal.\n */\n async request(\n path: string,\n init: RequestInit = {},\n opts: { timeout?: number | null } = {},\n ): Promise<Response> {\n const headers = new Headers(init.headers);\n headers.set(\"Authorization\", `Bearer ${this.apiKey}`);\n headers.set(\"X-Sonilo-Client\", this.clientName);\n headers.set(\"X-Sonilo-Client-Version\", this.clientVersion);\n const timeout = opts.timeout === undefined ? this.timeout : opts.timeout;\n // We only \"own\" the signal (and may later rewrap its abort as a\n // RequestTimeoutError) when the caller didn't supply one and a timeout\n // is actually enabled.\n const ownsSignal = init.signal == null && timeout !== null;\n const signal = init.signal ?? (timeout === null ? undefined : AbortSignal.timeout(timeout));\n try {\n const res = await this.fetchFn(`${this.baseUrl}${path}`, { ...init, headers, signal });\n if (!res.ok) throw await errorFromResponse(res);\n return res;\n } catch (err) {\n if (ownsSignal && isTimeoutSignalError(err)) {\n throw new RequestTimeoutError(`Request to ${path} timed out after ${timeout}ms`);\n }\n throw err;\n }\n }\n}\n","import { DEFAULT_TIMEOUT_MS } from \"./client.js\";\nimport { RequestTimeoutError, SoniloError, isTimeoutSignalError } from \"./errors.js\";\nimport type { SfxMedia } from \"./types.js\";\n\n/** Fetch a result media file. The URL is presigned — no API key is sent.\n *\n * Accepts either a media object (`result.audio`, `result.music`, …) or a bare\n * URL string, which is what the combined video-to-sound endpoints return as\n * `output_url`. */\nexport async function download(\n media: SfxMedia | string | undefined,\n fetchFn: typeof globalThis.fetch = globalThis.fetch,\n timeout: number = DEFAULT_TIMEOUT_MS,\n): Promise<Uint8Array> {\n const url = typeof media === \"string\" ? media : media?.url;\n if (!url) {\n throw new SoniloError(\"No media to download\");\n }\n let res: Response;\n try {\n res = await fetchFn(url, { signal: AbortSignal.timeout(timeout) });\n } catch (err) {\n if (isTimeoutSignalError(err)) {\n throw new RequestTimeoutError(`Download of ${url} timed out after ${timeout}ms`);\n }\n throw err;\n }\n if (!res.ok) {\n throw new SoniloError(`Download failed: HTTP ${res.status}`);\n }\n return new Uint8Array(await res.arrayBuffer());\n}\n","export type SegmentLabel =\n | \"intro\"\n | \"verse\"\n | \"pre-chorus\"\n | \"chorus\"\n | \"bridge\"\n | \"break\"\n | \"silence\"\n | \"outro\"\n | \"none\";\n\nexport interface Segment {\n start: number;\n prompt: string;\n label?: SegmentLabel;\n}\n\n/** Monetary fields are strings, exactly as the backend serializes them. */\nexport interface CostInfo {\n billing_rate_per_sec: string;\n billing_before_discount: string;\n billing_after_discount: string;\n discount_factor: string;\n}\n\nexport interface AudioChunkEvent {\n type: \"audio_chunk\";\n /** Decoded from the wire's base64 by the SDK. */\n data: Uint8Array;\n}\n\nexport interface TitleEvent {\n type: \"title\";\n title: string;\n summary?: string;\n display_tags?: string[];\n [key: string]: unknown;\n}\n\nexport interface CompleteEvent {\n type: \"complete\";\n [key: string]: unknown;\n}\n\nexport interface ErrorEvent {\n type: \"error\";\n code?: string;\n message?: string;\n [key: string]: unknown;\n}\n\nexport interface CostEvent extends CostInfo {\n type: \"cost\";\n}\n\n/** Forward-compatibility: unrecognized event types are passed through. */\nexport interface UnknownEvent {\n type: string;\n [key: string]: unknown;\n}\n\nexport type StreamEvent =\n | AudioChunkEvent\n | TitleEvent\n | CompleteEvent\n | ErrorEvent\n | CostEvent\n | UnknownEvent;\n\nexport interface Track {\n audio: Uint8Array;\n title?: string;\n cost?: CostInfo;\n}\n\nexport interface TextToMusicParams {\n prompt: string;\n duration: number;\n segments?: Segment[];\n /** \"stream\" (default) or \"async\" (required by `submit()` and `output_format: \"wav\"`). */\n mode?: \"stream\" | \"async\";\n /** Container for the async result. `wav` requires `mode: \"async\"`. Defaults to m4a server-side. */\n outputFormat?: \"m4a\" | \"wav\";\n /** Bounds the stream: aborting this cancels the in-flight generation.\n * Passed straight through to `fetch` — it is never rewrapped as\n * RequestTimeoutError, since the client's own absolute timeout does not\n * apply to streaming music generation. */\n signal?: AbortSignal;\n}\n\n/** string = file path (Node.js only). */\nexport type VideoInput =\n | File\n | Blob\n | Uint8Array\n | ArrayBuffer\n | ReadableStream<Uint8Array>\n | string;\n\nexport interface VideoToMusicParams {\n video?: VideoInput;\n videoUrl?: string;\n prompt?: string;\n segments?: Segment[];\n /** Bounds the stream: aborting this cancels the in-flight generation.\n * Passed straight through to `fetch` — it is never rewrapped as\n * RequestTimeoutError, since the client's own absolute timeout does not\n * apply to streaming music generation. Only meaningful for `stream()`/\n * `generate()`; `submit()` ignores it. */\n signal?: AbortSignal;\n /** \"stream\" (the default, used by `stream()`/`generate()`) or \"async\"\n * (required for `submit()`, and for `isolateVocals`). Only consulted by\n * `submit()` — `stream()`/`generate()` always request a stream. */\n mode?: \"stream\" | \"async\";\n /** Split the generated track into a vocals-only stem alongside the mix.\n * Requires `mode: \"async\"`; if `mode` is left unset it defaults to\n * \"async\" automatically. Only usable via `submit()` — the backend\n * rejects it on the plain stream. */\n isolateVocals?: boolean;\n /** Keep the source speech/vocals in the async result. Current name for\n * `isolateVocals`; both are accepted and OR'd server-side. Requires\n * `mode: \"async\"` (auto-selected by `submit()`). */\n preserveSpeech?: boolean;\n /** Container for the async result. `wav` requires async. Defaults to m4a. */\n outputFormat?: \"m4a\" | \"wav\";\n /** Duck the generated music under the source voice at finalize time.\n * Default-ON server-side in async mode: leave unset to keep it on, pass\n * `false` to opt out. Free, best-effort; only valid on `submit()`. */\n ducking?: boolean;\n}\n\nexport interface TrialQuota {\n granted: number;\n used: number;\n remaining: number;\n}\n\nexport interface AccountServices {\n available_services: string[];\n rpm_limit: number;\n concurrency_limit: number;\n discount_factor: number | string;\n max_upload_size_mb: number | null;\n /** Free-trial allowance keyed by service. Returned only for self-serve\n * accounts; absent entirely for invoiced accounts. */\n trial?: Record<string, TrialQuota>;\n}\n\nexport interface UsageSummary {\n total_requests: number;\n total_duration_seconds: number;\n total_cost: number | string;\n period_start: string;\n period_end: string;\n [key: string]: unknown;\n}\n\nexport interface DailyUsage {\n date: string;\n requests: number;\n duration_seconds: number;\n cost: number | string;\n}\n\nexport interface UsageResponse {\n summary: UsageSummary;\n daily: DailyUsage[];\n}\n\nexport function isAudioChunkEvent(event: StreamEvent): event is AudioChunkEvent {\n return event.type === \"audio_chunk\" && (event as AudioChunkEvent).data instanceof Uint8Array;\n}\n\nexport function isErrorEvent(event: StreamEvent): event is ErrorEvent {\n return event.type === \"error\";\n}\n\n/** SFX segments (unlike music `Segment`) require `end`, must start at 0,\n * and be contiguous; validated server-side. */\nexport interface SfxSegment {\n start: number;\n end: number;\n prompt: string;\n}\n\nexport type SfxAudioFormat = \"wav\" | \"mp3\" | \"aac\" | \"flac\";\n\n/** Submission ack for the async SFX endpoints. */\nexport interface SfxTask {\n task_id: string;\n status: string;\n}\n\n/** A generated file re-hosted on R2 behind a presigned URL. */\nexport interface SfxMedia {\n url: string;\n content_type?: string;\n file_size?: number;\n}\n\nexport interface SfxError {\n code?: string;\n message?: string;\n}\n\n/**\n * Common shape of any polled task (`tasks.get`/`tasks.wait`), regardless of\n * which endpoint created it. `Tasks.get`/`Tasks.wait` are generic over this so\n * each endpoint's result type (e.g. `SfxResult`, `MusicTaskResult`) can add\n * its own `audio`/media fields while sharing the status/error/refund\n * bookkeeping the poller relies on.\n */\nexport interface BaseTaskResult {\n task_id: string;\n type?: string;\n status: \"processing\" | \"succeeded\" | \"failed\" | (string & {});\n /** Only present when the account's task-field whitelist enables cost. */\n cost?: number;\n error?: SfxError;\n refunded?: boolean;\n [key: string]: unknown;\n}\n\n/** State of an SFX task (`tasks.get`) or its final result (`wait`/`generate`). */\nexport interface SfxResult extends BaseTaskResult {\n audio?: SfxMedia;\n /** Kept for backward compatibility; no longer populated — video-to-sfx returns audio only. */\n video?: SfxMedia;\n}\n\nexport interface TextToSfxParams {\n prompt: string;\n duration: number;\n audioFormat?: SfxAudioFormat;\n}\n\nexport interface VideoToSfxParams {\n video?: VideoInput;\n videoUrl?: string;\n prompt?: string;\n segments?: SfxSegment[];\n audioFormat?: SfxAudioFormat;\n}\n\n/** One decoded audio stream of an async video-to-music result. Unlike SFX,\n * `audio` on a music task is always an array — even without `isolateVocals` —\n * since a music generation can carry more than one output stream. */\nexport interface MusicMediaEntry extends SfxMedia {\n stream_index: number;\n sample_rate?: number;\n channels?: number;\n}\n\n/** One muxed audio+video-aligned output, present only when `isolateVocals`\n * is set. */\nexport interface MusicMuxEntry extends SfxMedia {\n stream_index: number;\n}\n\nexport interface MusicTitle {\n title: string;\n summary?: string;\n display_tags?: string[];\n}\n\n/** State of an async video-to-music task (`tasks.get`) or its final result\n * (`tasks.wait<MusicTaskResult>()`). Only reachable via `videoToMusic.submit()`\n * with `mode: \"async\"`. */\nexport interface MusicTaskResult extends BaseTaskResult {\n audio?: MusicMediaEntry[];\n /** Vocals-only stem; present only when `isolateVocals` was requested. */\n vocals?: SfxMedia;\n /** Muxed output per stream; present only when `isolateVocals` was requested. */\n mux?: MusicMuxEntry[];\n /** Music ducked under the source voice; present only when `ducking` ran. */\n ducked?: MusicMediaEntry[];\n title?: MusicTitle;\n duration_seconds?: number;\n}\n\nexport interface WaitOptions {\n /** Milliseconds between polls. Default 2000. */\n pollInterval?: number;\n /** Overall deadline in milliseconds. Default 600000. */\n timeout?: number;\n}\n\n/** Result of an async video-to-video task (`videoToVideoMusic`/`videoToVideoSfx`):\n * a re-hosted video with generated music or SFX muxed in. */\nexport interface VideoResult extends BaseTaskResult {\n video?: SfxMedia;\n duration_seconds?: number;\n}\n\nexport interface VideoToVideoMusicParams {\n video?: VideoInput;\n videoUrl?: string;\n prompt?: string;\n /** Keep the source speech/vocals in the output. Both this and the legacy\n * `isolateVocals` are accepted and OR'd server-side. */\n preserveSpeech?: boolean;\n /** @deprecated Legacy alias for `preserveSpeech`. */\n isolateVocals?: boolean;\n}\n\nexport interface VideoToVideoSfxParams {\n video?: VideoInput;\n videoUrl?: string;\n prompt?: string;\n segments?: SfxSegment[];\n}\n\n/** Params for `videoToSound` and `videoToVideoSound`. Both endpoints take the\n * identical form, so they share one params type. */\nexport interface VideoToSoundParams {\n video?: VideoInput;\n videoUrl?: string;\n /** Style hint for the generated music bed. */\n musicPrompt?: string;\n /** Description of the sound effects layered over the music. */\n sfxPrompt?: string;\n /** Per-segment SFX descriptions; must start at 0 and be contiguous. */\n segments?: SfxSegment[];\n /** Keep the source speech in the result. */\n preserveSpeech?: boolean;\n /** Duck the generated music under the source speech. Default-ON\n * server-side: leave unset to keep it on, pass `false` to opt out. */\n ducking?: boolean;\n}\n\n/** Result of a `videoToSound` / `videoToVideoSound` task (`tasks.get`) or its\n * final state (`generate`).\n *\n * The combined music+SFX result is `output_url` — a bare presigned URL rather\n * than a media object, since these endpoints render one artifact whose kind is\n * announced by `output_type` (\"audio\" for video-to-sound, \"video\" for\n * video-to-video-sound). `music`, `music_processed` and `sfx` are the\n * individual stems; pass any of them, or `output_url` itself, to `download()`. */\nexport interface SoundResult extends BaseTaskResult {\n output_url?: string;\n output_type?: \"audio\" | \"video\";\n output_bytes?: number;\n music?: SfxMedia;\n /** Present only when `preserveSpeech`/`ducking` altered the music bed. */\n music_processed?: SfxMedia;\n sfx?: SfxMedia;\n duration_seconds?: number;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/resources/account.ts","../src/resources/tasks.ts","../src/streaming.ts","../src/resources/textToMusic.ts","../src/upload.ts","../src/resources/videoToMusic.ts","../src/resources/textToSfx.ts","../src/resources/videoToSfx.ts","../src/resources/videoToVideoMusic.ts","../src/resources/videoToVideoSfx.ts","../src/resources/soundForm.ts","../src/resources/videoToSound.ts","../src/resources/videoToVideoSound.ts","../src/resources/dubbing.ts","../src/version.ts","../src/client.ts","../src/download.ts","../src/types.ts"],"sourcesContent":["export { DEFAULT_TIMEOUT_MS, SoniloClient, type SoniloClientOptions } from \"./client.js\";\nexport {\n APIError,\n AuthenticationError,\n BadRequestError,\n GenerationError,\n PaymentRequiredError,\n RateLimitError,\n RequestTimeoutError,\n SoniloError,\n TaskFailedError,\n TaskTimeoutError,\n TrialExhaustedError,\n} from \"./errors.js\";\nexport { download } from \"./download.js\";\nexport { VERSION } from \"./version.js\";\nexport type {\n AccountServices,\n AudioChunkEvent,\n BaseTaskResult,\n CompleteEvent,\n CostEvent,\n CostInfo,\n DailyUsage,\n DubbingLanguage,\n DubbingParams,\n DubbingResult,\n ErrorEvent,\n MusicMediaEntry,\n MusicMuxEntry,\n MusicTaskResult,\n MusicTitle,\n Segment,\n SegmentLabel,\n SfxAudioFormat,\n SfxError,\n SfxMedia,\n SfxResult,\n SfxSegment,\n SfxTask,\n SoundResult,\n StreamEvent,\n TextToMusicParams,\n TextToSfxParams,\n TitleEvent,\n Track,\n TrialQuota,\n UnknownEvent,\n UsageResponse,\n UsageSummary,\n VideoInput,\n VideoResult,\n VideoToMusicParams,\n VideoToSfxParams,\n VideoToSoundParams,\n VideoToVideoMusicParams,\n VideoToVideoSfxParams,\n WaitOptions,\n} from \"./types.js\";\nexport { isAudioChunkEvent, isErrorEvent } from \"./types.js\";\n","export class SoniloError extends Error {\n constructor(message: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\nexport class APIError extends SoniloError {\n readonly status: number;\n readonly body: unknown;\n /** The API's typed error code (e.g. \"rate_limit_exceeded\"), distinct from the HTTP status. */\n readonly code?: string;\n /** Per-field validation details, present on a 422. */\n readonly errors?: unknown[];\n\n constructor(message: string, status: number, body?: unknown) {\n super(message);\n this.status = status;\n this.body = body;\n const parsed = body as { code?: unknown; errors?: unknown } | undefined;\n this.code = typeof parsed?.code === \"string\" ? parsed.code : undefined;\n this.errors = Array.isArray(parsed?.errors) ? parsed.errors : undefined;\n }\n}\n\nexport class AuthenticationError extends APIError {}\n\nexport class PaymentRequiredError extends APIError {}\n\n/** The account's free trial for this service is spent and it has never been\n * funded — the caller should add a payment method rather than retry. A\n * subclass of `PaymentRequiredError`, so code that already catches every 402\n * keeps working; catch this first to tell \"you haven't paid us yet\" apart\n * from a funded wallet that ran dry (`PaymentRequiredError` with\n * `code === \"insufficient_balance\"`). */\nexport class TrialExhaustedError extends PaymentRequiredError {}\n\nexport class BadRequestError extends APIError {\n get detail(): string | undefined {\n const body = this.body as { message?: unknown; detail?: unknown } | undefined;\n if (typeof body?.message === \"string\" && body.message) {\n return body.message;\n }\n return typeof body?.detail === \"string\" ? body.detail : undefined;\n }\n}\n\nexport class RateLimitError extends APIError {\n readonly retryAfter?: number;\n\n constructor(message: string, status: number, body?: unknown, retryAfter?: number) {\n super(message, status, body);\n this.retryAfter = retryAfter;\n }\n}\n\n/** Raised by generate() when an `error` event arrives mid-stream. */\nexport class GenerationError extends SoniloError {\n readonly code?: string;\n\n constructor(message: string, code?: string) {\n super(message);\n this.code = code;\n }\n}\n\n/** Raised by tasks.wait()/generate() when an SFX task reaches `failed`. */\nexport class TaskFailedError extends SoniloError {\n readonly code?: string;\n readonly taskId: string;\n readonly refunded?: boolean;\n\n constructor(\n message: string,\n opts: { code?: string; taskId: string; refunded?: boolean },\n ) {\n super(message);\n this.code = opts.code;\n this.taskId = opts.taskId;\n this.refunded = opts.refunded;\n }\n}\n\n/** Poll deadline passed. The task may still finish server-side — resume with\n * tasks.wait(taskId) or tasks.get(taskId). */\nexport class TaskTimeoutError extends SoniloError {\n readonly taskId: string;\n\n constructor(message: string, taskId: string) {\n super(message);\n this.taskId = taskId;\n }\n}\n\n/** Raised when a one-shot request or download is aborted by its own timeout\n * signal (as opposed to a caller-supplied AbortSignal, which propagates\n * untouched). */\nexport class RequestTimeoutError extends SoniloError {}\n\n/**\n * True if `err` is the rejection produced when an `AbortSignal.timeout()`\n * we created fires. Used to distinguish \"our\" timeout aborts (which should be\n * rethrown as `RequestTimeoutError`) from a caller-supplied signal's abort\n * (which must propagate untouched).\n */\nexport function isTimeoutSignalError(err: unknown): boolean {\n return err instanceof Error && (err.name === \"TimeoutError\" || err.name === \"AbortError\");\n}\n\nexport async function errorFromResponse(res: Response): Promise<APIError> {\n const text = await res.text().catch(() => \"\");\n let body: unknown = text;\n try {\n body = JSON.parse(text);\n } catch {\n // keep raw text\n }\n const parsed = body as { message?: unknown; detail?: unknown } | undefined;\n const rawMessage = typeof parsed?.message === \"string\" && parsed.message ? parsed.message : undefined;\n const rawDetail = parsed?.detail;\n const isDetailAbsent = rawDetail === undefined || rawDetail === null || rawDetail === \"\";\n let reason: string;\n if (rawMessage !== undefined) {\n reason = rawMessage;\n } else if (isDetailAbsent) {\n reason = res.statusText || \"request failed\";\n } else if (typeof rawDetail === \"string\") {\n reason = rawDetail;\n } else {\n try {\n reason = JSON.stringify(rawDetail);\n } catch {\n reason = res.statusText || \"request failed\";\n }\n }\n const message = `HTTP ${res.status}: ${reason}`;\n\n switch (res.status) {\n case 401:\n return new AuthenticationError(message, res.status, body);\n case 402: {\n // Branch on the API's `code`, never on the message text — the wording\n // is product copy and changes; the code is the contract.\n const code = (body as { code?: unknown } | undefined)?.code;\n if (code === \"trial_exhausted\") {\n return new TrialExhaustedError(message, res.status, body);\n }\n return new PaymentRequiredError(message, res.status, body);\n }\n case 429: {\n const ra = res.headers.get(\"retry-after\");\n const retryAfter = ra !== null && ra !== \"\" && !Number.isNaN(Number(ra)) ? Number(ra) : undefined;\n return new RateLimitError(message, res.status, body, retryAfter);\n }\n case 400:\n case 413:\n case 422:\n return new BadRequestError(message, res.status, body);\n default:\n return new APIError(message, res.status, body);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport type { AccountServices, UsageResponse } from \"../types.js\";\n\nexport class Account {\n constructor(private readonly client: SoniloClient) {}\n\n async services(): Promise<AccountServices> {\n const res = await this.client.request(\"/v1/account/services\");\n return (await res.json()) as AccountServices;\n }\n\n async usage(params: { days?: number } = {}): Promise<UsageResponse> {\n const query = params.days !== undefined ? `?days=${params.days}` : \"\";\n const res = await this.client.request(`/v1/account/usage${query}`);\n return (await res.json()) as UsageResponse;\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError, TaskFailedError, TaskTimeoutError } from \"../errors.js\";\nimport type { BaseTaskResult, SfxResult, WaitOptions } from \"../types.js\";\n\nexport const DEFAULT_POLL_INTERVAL_MS = 2000;\nexport const DEFAULT_WAIT_TIMEOUT_MS = 600_000;\n\nconst sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));\n\n/** A negative delay is clamped to 0 by setTimeout, which would turn the poll\n * loop into a busy loop hammering the API until the deadline. */\nfunction validateWaitArgs(pollInterval: number, timeout: number): void {\n if (pollInterval < 0) {\n throw new SoniloError(`pollInterval must be >= 0, got ${pollInterval}`);\n }\n if (timeout < 0) {\n throw new SoniloError(`timeout must be >= 0, got ${timeout}`);\n }\n}\n\nexport class Tasks {\n constructor(private readonly client: SoniloClient) {}\n\n /**\n * Fetch current task state. Never throws on a failed status.\n *\n * Generic over the result shape so callers can request the endpoint-\n * specific type, e.g. `client.tasks.get<MusicTaskResult>(taskId)`.\n * Defaults to `SfxResult` for back-compat.\n */\n async get<T extends BaseTaskResult = SfxResult>(taskId: string): Promise<T> {\n const res = await this.client.request(`/v1/tasks/${encodeURIComponent(taskId)}`);\n return (await res.json()) as T;\n }\n\n /**\n * Poll until the task is terminal; throw on failure or deadline.\n *\n * Generic over the result shape, e.g.\n * `client.tasks.wait<MusicTaskResult>(taskId)`. Defaults to `SfxResult`\n * for back-compat.\n */\n async wait<T extends BaseTaskResult = SfxResult>(\n taskId: string,\n opts: WaitOptions = {},\n ): Promise<T> {\n const pollInterval = opts.pollInterval ?? DEFAULT_POLL_INTERVAL_MS;\n const timeout = opts.timeout ?? DEFAULT_WAIT_TIMEOUT_MS;\n validateWaitArgs(pollInterval, timeout);\n const deadline = performance.now() + timeout;\n for (;;) {\n const result = await this.get<T>(taskId);\n if (result.status === \"succeeded\") return result;\n if (result.status === \"failed\") {\n const message = result.error?.message || \"Generation failed\";\n throw new TaskFailedError(`Task ${taskId} failed: ${message}`, {\n code: result.error?.code,\n taskId,\n refunded: result.refunded,\n });\n }\n const remaining = deadline - performance.now();\n if (remaining <= 0) {\n throw new TaskTimeoutError(\n `Task ${taskId} still processing after ${timeout}ms; ` +\n \"it may finish later — resume with tasks.wait or tasks.get\",\n taskId,\n );\n }\n await sleep(Math.min(pollInterval, remaining));\n }\n }\n}\n","import { GenerationError } from \"./errors.js\";\nimport type { CostInfo, StreamEvent, Track } from \"./types.js\";\n\nexport function decodeBase64(b64: string): Uint8Array {\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n}\n\n/** Returns `null` for a valid-JSON-but-non-object line (e.g. a bare `null`\n * or a number/string), which carries no event `type` and is skipped like any\n * other junk line rather than crashing on a `.type` read off `null`. */\nfunction toEvent(line: string): StreamEvent | null {\n const parsed: unknown = JSON.parse(line);\n if (typeof parsed !== \"object\" || parsed === null) return null;\n const raw = parsed as { type: string; [key: string]: unknown };\n if (raw.type === \"audio_chunk\" && typeof raw.data === \"string\") {\n try {\n return { ...raw, type: \"audio_chunk\", data: decodeBase64(raw.data) };\n } catch {\n // Don't raise here: this must reach collectTrack's malformed-chunk\n // check, which turns undecodable data into a typed GenerationError.\n // Raising in place would let a raw DOMException escape\n // stream()/generate(), breaking the SDK's \"all errors extend\n // SoniloError\" contract.\n }\n }\n return raw as StreamEvent;\n}\n\nexport async function* parseNdjson(\n body: ReadableStream<Uint8Array>,\n): AsyncGenerator<StreamEvent, void, undefined> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n let nl: number;\n while ((nl = buffer.indexOf(\"\\n\")) !== -1) {\n const line = buffer.slice(0, nl).trim();\n buffer = buffer.slice(nl + 1);\n if (line) {\n const ev = toEvent(line);\n if (ev !== null) yield ev;\n }\n }\n }\n buffer += decoder.decode();\n const tail = buffer.trim();\n if (tail) {\n const ev = toEvent(tail);\n if (ev !== null) yield ev;\n }\n } finally {\n await reader.cancel().catch(() => {});\n }\n}\n\nexport async function collectTrack(events: AsyncIterable<StreamEvent>): Promise<Track> {\n const chunks: Uint8Array[] = [];\n let title: string | undefined;\n let cost: CostInfo | undefined;\n let sawComplete = false;\n\n for await (const ev of events) {\n if (ev.type === \"audio_chunk\") {\n // A malformed chunk (missing/non-decodable `data`) must not be\n // silently dropped: that would hand back a \"successful\" Track with\n // empty or truncated audio and no indication anything went wrong.\n if (!(ev.data instanceof Uint8Array)) {\n throw new GenerationError(\n \"received a malformed audio_chunk event (missing or non-decodable data)\",\n );\n }\n chunks.push(ev.data);\n } else if (ev.type === \"title\" && typeof ev.title === \"string\") {\n title = ev.title;\n } else if (ev.type === \"cost\") {\n const { type: _type, ...rest } = ev;\n cost = rest as CostInfo;\n } else if (ev.type === \"error\") {\n const message = typeof ev.message === \"string\" && ev.message !== \"\" ? ev.message : \"generation failed\";\n const code = typeof ev.code === \"string\" ? ev.code : undefined;\n throw new GenerationError(message, code);\n } else if (ev.type === \"complete\") {\n sawComplete = true;\n }\n // unknown event types: ignored\n }\n\n if (!sawComplete) {\n throw new GenerationError(\"stream ended before a 'complete' event (truncated response)\");\n }\n\n const total = chunks.reduce((n, c) => n + c.length, 0);\n const audio = new Uint8Array(total);\n let offset = 0;\n for (const c of chunks) {\n audio.set(c, offset);\n offset += c.length;\n }\n return { audio, title, cost };\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { collectTrack, parseNdjson } from \"../streaming.js\";\nimport type { SfxTask, StreamEvent, TextToMusicParams, Track } from \"../types.js\";\n\nexport class TextToMusic {\n constructor(private readonly client: SoniloClient) {}\n\n /** Stream raw generation events (audio chunks pre-decoded to bytes). */\n async *stream(params: TextToMusicParams): AsyncGenerator<StreamEvent, void, undefined> {\n const form = new FormData();\n form.set(\"prompt\", params.prompt);\n form.set(\"duration\", String(params.duration));\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n // Opt out of the client's absolute request timeout: this holds the\n // response body open and reads NDJSON chunks for as long as generation\n // takes, so an AbortSignal keyed to elapsed time would kill a healthy,\n // still-streaming, long-duration track. Pass `params.signal` yourself to\n // bound or cancel the stream instead — it is forwarded to `fetch` as-is.\n const res = await this.client.request(\n \"/v1/text-to-music\",\n { method: \"POST\", body: form, signal: params.signal },\n { timeout: null },\n );\n if (!res.body) throw new SoniloError(\"Response has no body\");\n yield* parseNdjson(res.body);\n }\n\n /** Generate and buffer the whole track; throws GenerationError on stream errors. */\n generate(params: TextToMusicParams): Promise<Track> {\n return collectTrack(this.stream(params));\n }\n\n /**\n * Submit an async text-to-music task; poll with\n * `client.tasks.wait<MusicTaskResult>(task.task_id)`. Required for\n * `outputFormat: \"wav\"`. `stream()`/`generate()` remain the streaming path.\n */\n async submit(params: TextToMusicParams): Promise<SfxTask> {\n const mode = params.mode ?? \"async\";\n if (mode !== \"async\") {\n throw new SoniloError('submit() requires mode: \"async\"');\n }\n const form = new FormData();\n form.set(\"prompt\", params.prompt);\n form.set(\"duration\", String(params.duration));\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n form.set(\"mode\", mode);\n if (params.outputFormat !== undefined) {\n form.set(\"output_format\", params.outputFormat);\n }\n const res = await this.client.request(\"/v1/text-to-music\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n}\n","import { SoniloError } from \"./errors.js\";\nimport type { VideoInput } from \"./types.js\";\n\nconst DEFAULT_FILENAME = \"video.mp4\";\n\n/**\n * Normalize every accepted video input into a FormData-ready Blob.\n * String inputs are file paths and work only in Node.js; browsers must\n * pass File/Blob/bytes/streams.\n */\nexport async function toUploadBlob(\n video: VideoInput,\n): Promise<{ blob: Blob; filename: string }> {\n if (typeof video === \"string\") {\n const isNode =\n typeof process !== \"undefined\" && Boolean((process as { versions?: { node?: string } }).versions?.node);\n if (!isNode) {\n throw new SoniloError(\n \"File paths are only supported in Node.js; pass a File or Blob in the browser\",\n );\n }\n const fsModule = \"node:fs/promises\";\n const { readFile } = (await import(\n /* webpackIgnore: true */ /* @vite-ignore */ fsModule\n )) as typeof import(\"node:fs/promises\");\n const data = await readFile(video);\n const filename = video.split(/[\\\\/]/).pop() || DEFAULT_FILENAME;\n return { blob: new Blob([data]), filename };\n }\n if (typeof File !== \"undefined\" && video instanceof File) {\n return { blob: video, filename: video.name || DEFAULT_FILENAME };\n }\n if (video instanceof Blob) {\n return { blob: video, filename: DEFAULT_FILENAME };\n }\n if (video instanceof Uint8Array) {\n return { blob: new Blob([video as unknown as BlobPart]), filename: DEFAULT_FILENAME };\n }\n if (video instanceof ArrayBuffer) {\n return { blob: new Blob([video]), filename: DEFAULT_FILENAME };\n }\n if (video instanceof ReadableStream) {\n return { blob: await new Response(video).blob(), filename: DEFAULT_FILENAME };\n }\n throw new SoniloError(\"Unsupported video input type\");\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { collectTrack, parseNdjson } from \"../streaming.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { SfxTask, StreamEvent, Track, VideoToMusicParams } from \"../types.js\";\n\nexport class VideoToMusic {\n constructor(private readonly client: SoniloClient) {}\n\n async *stream(params: VideoToMusicParams): AsyncGenerator<StreamEvent, void, undefined> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n // Opt out of the client's absolute request timeout: this holds the\n // response body open and reads NDJSON chunks for as long as generation\n // takes, so an AbortSignal keyed to elapsed time would kill a healthy,\n // still-streaming request (e.g. a slow video upload or long track). Pass\n // `params.signal` yourself to bound or cancel the stream instead — it is\n // forwarded to `fetch` as-is.\n const res = await this.client.request(\n \"/v1/video-to-music\",\n { method: \"POST\", body: form, signal: params.signal },\n { timeout: null },\n );\n if (!res.body) throw new SoniloError(\"Response has no body\");\n yield* parseNdjson(res.body);\n }\n\n generate(params: VideoToMusicParams): Promise<Track> {\n return collectTrack(this.stream(params));\n }\n\n /**\n * Submit an async video-to-music task; poll its result with\n * `client.tasks.wait<MusicTaskResult>(task.task_id)`. Required for\n * `isolateVocals` — the backend rejects vocal isolation on the plain\n * stream, and it only ever runs in async mode.\n */\n async submit(params: VideoToMusicParams): Promise<SfxTask> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n let mode = params.mode;\n const needsAsync =\n params.isolateVocals ||\n params.preserveSpeech ||\n params.ducking !== undefined ||\n params.outputFormat === \"wav\";\n // submit() always wants an async task ack, never a stream. Default to\n // async; only object if the caller explicitly asked for stream while\n // also requesting an async-only feature.\n if (mode === undefined) mode = \"async\";\n if (needsAsync && mode !== \"async\") {\n throw new SoniloError(\n 'isolateVocals/preserveSpeech/ducking/outputFormat \"wav\" require mode: \"async\"',\n );\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n form.set(\"mode\", mode);\n if (params.preserveSpeech !== undefined) {\n form.set(\"preserve_speech\", String(params.preserveSpeech));\n }\n if (params.isolateVocals !== undefined) {\n form.set(\"isolate_vocals\", String(params.isolateVocals));\n }\n if (params.outputFormat !== undefined) {\n form.set(\"output_format\", params.outputFormat);\n }\n if (params.ducking !== undefined) {\n form.set(\"ducking\", String(params.ducking));\n }\n const res = await this.client.request(\"/v1/video-to-music\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport type { SfxResult, SfxTask, TextToSfxParams, WaitOptions } from \"../types.js\";\n\nexport class TextToSfx {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: TextToSfxParams): Promise<SfxTask> {\n const form = new FormData();\n form.set(\"prompt\", params.prompt);\n form.set(\"duration\", String(params.duration));\n if (params.audioFormat !== undefined) form.set(\"audio_format\", params.audioFormat);\n const res = await this.client.request(\"/v1/text-to-sfx\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: TextToSfxParams, opts?: WaitOptions): Promise<SfxResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait(task.task_id, opts);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { SfxResult, SfxTask, VideoToSfxParams, WaitOptions } from \"../types.js\";\n\nexport class VideoToSfx {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToSfxParams): Promise<SfxTask> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n if (params.audioFormat !== undefined) form.set(\"audio_format\", params.audioFormat);\n const res = await this.client.request(\"/v1/video-to-sfx\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToSfxParams, opts?: WaitOptions): Promise<SfxResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait(task.task_id, opts);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { SfxTask, VideoResult, VideoToVideoMusicParams, WaitOptions } from \"../types.js\";\n\n/** Generate an original score for a video and get back a re-hosted video with\n * the music muxed in. Async only: `submit()` returns a task ack; poll with\n * `client.tasks.wait<VideoResult>(id)`, or use `generate()` to do both. */\nexport class VideoToVideoMusic {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToVideoMusicParams): Promise<SfxTask> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.preserveSpeech !== undefined) {\n form.set(\"preserve_speech\", String(params.preserveSpeech));\n }\n if (params.isolateVocals !== undefined) {\n form.set(\"isolate_vocals\", String(params.isolateVocals));\n }\n const res = await this.client.request(\"/v1/video-to-video-music\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToVideoMusicParams, opts?: WaitOptions): Promise<VideoResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait<VideoResult>(task.task_id, opts);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { SfxTask, VideoResult, VideoToVideoSfxParams, WaitOptions } from \"../types.js\";\n\n/** Generate sound effects for a video and get back a re-hosted video with the\n * SFX muxed in. Async only. */\nexport class VideoToVideoSfx {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToVideoSfxParams): Promise<SfxTask> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n const res = await this.client.request(\"/v1/video-to-video-sfx\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToVideoSfxParams, opts?: WaitOptions): Promise<VideoResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait<VideoResult>(task.task_id, opts);\n }\n}\n","import { SoniloError } from \"../errors.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { VideoToSoundParams } from \"../types.js\";\n\n/** Build the multipart body shared by /v1/video-to-sound and\n * /v1/video-to-video-sound — their form fields are identical, so the two\n * resources differ only in the path they POST to.\n *\n * Every optional field is omitted when unset rather than sent with a default:\n * `ducking` in particular is default-ON server-side, so an unset value must\n * not become an explicit \"false\" on the wire. */\nexport async function buildSoundForm(params: VideoToSoundParams): Promise<FormData> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.musicPrompt !== undefined) form.set(\"music_prompt\", params.musicPrompt);\n if (params.sfxPrompt !== undefined) form.set(\"sfx_prompt\", params.sfxPrompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n if (params.preserveSpeech !== undefined) {\n form.set(\"preserve_speech\", String(params.preserveSpeech));\n }\n if (params.ducking !== undefined) form.set(\"ducking\", String(params.ducking));\n return form;\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { buildSoundForm } from \"./soundForm.js\";\nimport type { SfxTask, SoundResult, VideoToSoundParams, WaitOptions } from \"../types.js\";\n\n/** Generate a combined music + sound-effects track for a video and get back\n * the mixed audio. Async only. */\nexport class VideoToSound {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToSoundParams): Promise<SfxTask> {\n const res = await this.client.request(\"/v1/video-to-sound\", {\n method: \"POST\",\n body: await buildSoundForm(params),\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToSoundParams, opts?: WaitOptions): Promise<SoundResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait<SoundResult>(task.task_id, opts);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { buildSoundForm } from \"./soundForm.js\";\nimport type { SfxTask, SoundResult, VideoToSoundParams, WaitOptions } from \"../types.js\";\n\n/** Generate a combined music + sound-effects track for a video and get back a\n * re-hosted video with that track muxed in. Async only. */\nexport class VideoToVideoSound {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToSoundParams): Promise<SfxTask> {\n const res = await this.client.request(\"/v1/video-to-video-sound\", {\n method: \"POST\",\n body: await buildSoundForm(params),\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToSoundParams, opts?: WaitOptions): Promise<SoundResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait<SoundResult>(task.task_id, opts);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { DubbingParams, DubbingResult, SfxTask, WaitOptions } from \"../types.js\";\n\n/** Build the multipart body for /v1/dubbing.\n *\n * `languages` travels as one opaque form field holding a JSON array string —\n * that is the shape the backend parses. It is omitted entirely when unset so\n * the server default ([\"zh_cn\", \"es\", \"fr\"]) applies; sending an empty array\n * instead would be rejected as a malformed payload.\n *\n * The https check is local because it is a guaranteed server-side 422: the\n * dubbing pipeline fetches the source URL itself and requires https\n * specifically, unlike the fal-backed endpoints, which accept plain http.\n * Language codes are deliberately NOT checked here — the backend owns that\n * list, and a hardcoded copy would make this SDK reject codes added later. */\nexport async function buildDubbingForm(params: DubbingParams): Promise<FormData> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n const url = params.videoUrl as string;\n if (!url.toLowerCase().startsWith(\"https://\")) {\n throw new SoniloError(\n \"videoUrl must use https — the dubbing pipeline requires an https URL\",\n );\n }\n form.set(\"video_url\", url);\n }\n if (params.languages !== undefined) {\n form.set(\"languages\", JSON.stringify(params.languages));\n }\n return form;\n}\n\n/** Dub a video into one or more target languages. Async only; the result\n * carries a language → dubbed-video-URL map under `outputs`. */\nexport class Dubbing {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: DubbingParams): Promise<SfxTask> {\n const res = await this.client.request(\"/v1/dubbing\", {\n method: \"POST\",\n body: await buildDubbingForm(params),\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: DubbingParams, opts?: WaitOptions): Promise<DubbingResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait<DubbingResult>(task.task_id, opts);\n }\n}\n","/** The SDK's own version. Generated by scripts/sync-versions.mjs — do not edit. */\nexport const VERSION = \"0.7.0\";\n","import { RequestTimeoutError, SoniloError, errorFromResponse, isTimeoutSignalError } from \"./errors.js\";\nimport { Account } from \"./resources/account.js\";\nimport { Tasks } from \"./resources/tasks.js\";\nimport { TextToMusic } from \"./resources/textToMusic.js\";\nimport { VideoToMusic } from \"./resources/videoToMusic.js\";\nimport { TextToSfx } from \"./resources/textToSfx.js\";\nimport { VideoToSfx } from \"./resources/videoToSfx.js\";\nimport { VideoToVideoMusic } from \"./resources/videoToVideoMusic.js\";\nimport { VideoToVideoSfx } from \"./resources/videoToVideoSfx.js\";\nimport { VideoToSound } from \"./resources/videoToSound.js\";\nimport { VideoToVideoSound } from \"./resources/videoToVideoSound.js\";\nimport { Dubbing } from \"./resources/dubbing.js\";\nimport { VERSION } from \"./version.js\";\n\nexport interface SoniloClientOptions {\n /** Defaults to the SONILO_API_KEY environment variable (Node.js only). */\n apiKey?: string;\n /** Defaults to https://api.sonilo.com */\n baseUrl?: string;\n /** Injection point for tests and custom transports. */\n fetch?: typeof globalThis.fetch;\n /** Milliseconds before an in-flight request is aborted. Default 600000. */\n timeout?: number;\n /**\n * Identifies a wrapper built on this SDK (the CLI, the video kit) in the\n * `X-Sonilo-Client` header. Leave unset for direct SDK use — without an\n * override a wrapper's traffic is indistinguishable from the SDK's own.\n */\n clientName?: string;\n /** Version reported alongside `clientName`. Defaults to the SDK's version. */\n clientVersion?: string;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.sonilo.com\";\n\n/**\n * Reported in `X-Sonilo-Client` unless a wrapper overrides it. First-party\n * wrappers (the CLI, the video kit) pass their own name so their traffic stays\n * distinguishable from direct SDK use in server-side analytics.\n */\nexport const DEFAULT_CLIENT_NAME = \"sdk-js\";\n\n/** Milliseconds before an in-flight request is aborted, unless overridden. */\nexport const DEFAULT_TIMEOUT_MS = 600_000;\n\nexport class SoniloClient {\n readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly fetchFn: typeof globalThis.fetch;\n private readonly timeout: number;\n private readonly clientName: string;\n private readonly clientVersion: string;\n readonly account: Account;\n readonly tasks: Tasks;\n readonly textToMusic: TextToMusic;\n readonly videoToMusic: VideoToMusic;\n readonly textToSfx: TextToSfx;\n readonly videoToSfx: VideoToSfx;\n readonly videoToVideoMusic: VideoToVideoMusic;\n readonly videoToVideoSfx: VideoToVideoSfx;\n readonly videoToSound: VideoToSound;\n readonly videoToVideoSound: VideoToVideoSound;\n readonly dubbing: Dubbing;\n\n constructor(options: SoniloClientOptions = {}) {\n const envKey =\n typeof process !== \"undefined\" ? process.env?.SONILO_API_KEY : undefined;\n const apiKey = options.apiKey ?? envKey;\n if (!apiKey) {\n throw new SoniloError(\n \"Missing API key: pass { apiKey } or set the SONILO_API_KEY environment variable\",\n );\n }\n this.apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.fetchFn = (options.fetch ?? globalThis.fetch).bind(globalThis);\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;\n this.clientName = options.clientName ?? DEFAULT_CLIENT_NAME;\n this.clientVersion = options.clientVersion ?? VERSION;\n this.account = new Account(this);\n this.tasks = new Tasks(this);\n this.textToMusic = new TextToMusic(this);\n this.videoToMusic = new VideoToMusic(this);\n this.textToSfx = new TextToSfx(this);\n this.videoToSfx = new VideoToSfx(this);\n this.videoToVideoMusic = new VideoToVideoMusic(this);\n this.videoToVideoSfx = new VideoToVideoSfx(this);\n this.videoToSound = new VideoToSound(this);\n this.videoToVideoSound = new VideoToVideoSound(this);\n this.dubbing = new Dubbing(this);\n }\n\n /**\n * Perform an authenticated request; throws a typed error on non-2xx.\n *\n * `opts.timeout` overrides the client's default timeout for this call;\n * pass `null` to disable the abort-on-timeout behavior entirely (used by\n * the streaming music endpoints — see textToMusic.ts / videoToMusic.ts).\n * A caller-supplied `init.signal` always wins over any timeout signal.\n */\n async request(\n path: string,\n init: RequestInit = {},\n opts: { timeout?: number | null } = {},\n ): Promise<Response> {\n const headers = new Headers(init.headers);\n headers.set(\"Authorization\", `Bearer ${this.apiKey}`);\n headers.set(\"X-Sonilo-Client\", this.clientName);\n headers.set(\"X-Sonilo-Client-Version\", this.clientVersion);\n const timeout = opts.timeout === undefined ? this.timeout : opts.timeout;\n // We only \"own\" the signal (and may later rewrap its abort as a\n // RequestTimeoutError) when the caller didn't supply one and a timeout\n // is actually enabled.\n const ownsSignal = init.signal == null && timeout !== null;\n const signal = init.signal ?? (timeout === null ? undefined : AbortSignal.timeout(timeout));\n try {\n const res = await this.fetchFn(`${this.baseUrl}${path}`, { ...init, headers, signal });\n if (!res.ok) throw await errorFromResponse(res);\n return res;\n } catch (err) {\n if (ownsSignal && isTimeoutSignalError(err)) {\n throw new RequestTimeoutError(`Request to ${path} timed out after ${timeout}ms`);\n }\n throw err;\n }\n }\n}\n","import { DEFAULT_TIMEOUT_MS } from \"./client.js\";\nimport { RequestTimeoutError, SoniloError, isTimeoutSignalError } from \"./errors.js\";\nimport type { SfxMedia } from \"./types.js\";\n\n/** Fetch a result media file. The URL is presigned — no API key is sent.\n *\n * Accepts either a media object (`result.audio`, `result.music`, …) or a bare\n * URL string, which is what the combined video-to-sound endpoints return as\n * `output_url`. */\nexport async function download(\n media: SfxMedia | string | undefined,\n fetchFn: typeof globalThis.fetch = globalThis.fetch,\n timeout: number = DEFAULT_TIMEOUT_MS,\n): Promise<Uint8Array> {\n const url = typeof media === \"string\" ? media : media?.url;\n if (!url) {\n throw new SoniloError(\"No media to download\");\n }\n let res: Response;\n try {\n res = await fetchFn(url, { signal: AbortSignal.timeout(timeout) });\n } catch (err) {\n if (isTimeoutSignalError(err)) {\n throw new RequestTimeoutError(`Download of ${url} timed out after ${timeout}ms`);\n }\n throw err;\n }\n if (!res.ok) {\n throw new SoniloError(`Download failed: HTTP ${res.status}`);\n }\n return new Uint8Array(await res.arrayBuffer());\n}\n","export type SegmentLabel =\n | \"intro\"\n | \"verse\"\n | \"pre-chorus\"\n | \"chorus\"\n | \"bridge\"\n | \"break\"\n | \"silence\"\n | \"outro\"\n | \"none\";\n\nexport interface Segment {\n start: number;\n prompt: string;\n label?: SegmentLabel;\n}\n\n/** Monetary fields are strings, exactly as the backend serializes them. */\nexport interface CostInfo {\n billing_rate_per_sec: string;\n billing_before_discount: string;\n billing_after_discount: string;\n discount_factor: string;\n}\n\nexport interface AudioChunkEvent {\n type: \"audio_chunk\";\n /** Decoded from the wire's base64 by the SDK. */\n data: Uint8Array;\n}\n\nexport interface TitleEvent {\n type: \"title\";\n title: string;\n summary?: string;\n display_tags?: string[];\n [key: string]: unknown;\n}\n\nexport interface CompleteEvent {\n type: \"complete\";\n [key: string]: unknown;\n}\n\nexport interface ErrorEvent {\n type: \"error\";\n code?: string;\n message?: string;\n [key: string]: unknown;\n}\n\nexport interface CostEvent extends CostInfo {\n type: \"cost\";\n}\n\n/** Forward-compatibility: unrecognized event types are passed through. */\nexport interface UnknownEvent {\n type: string;\n [key: string]: unknown;\n}\n\nexport type StreamEvent =\n | AudioChunkEvent\n | TitleEvent\n | CompleteEvent\n | ErrorEvent\n | CostEvent\n | UnknownEvent;\n\nexport interface Track {\n audio: Uint8Array;\n title?: string;\n cost?: CostInfo;\n}\n\nexport interface TextToMusicParams {\n prompt: string;\n duration: number;\n segments?: Segment[];\n /** \"stream\" (default) or \"async\" (required by `submit()` and `output_format: \"wav\"`). */\n mode?: \"stream\" | \"async\";\n /** Container for the async result. `wav` requires `mode: \"async\"`. Defaults to m4a server-side. */\n outputFormat?: \"m4a\" | \"wav\";\n /** Bounds the stream: aborting this cancels the in-flight generation.\n * Passed straight through to `fetch` — it is never rewrapped as\n * RequestTimeoutError, since the client's own absolute timeout does not\n * apply to streaming music generation. */\n signal?: AbortSignal;\n}\n\n/** string = file path (Node.js only). */\nexport type VideoInput =\n | File\n | Blob\n | Uint8Array\n | ArrayBuffer\n | ReadableStream<Uint8Array>\n | string;\n\nexport interface VideoToMusicParams {\n video?: VideoInput;\n videoUrl?: string;\n prompt?: string;\n segments?: Segment[];\n /** Bounds the stream: aborting this cancels the in-flight generation.\n * Passed straight through to `fetch` — it is never rewrapped as\n * RequestTimeoutError, since the client's own absolute timeout does not\n * apply to streaming music generation. Only meaningful for `stream()`/\n * `generate()`; `submit()` ignores it. */\n signal?: AbortSignal;\n /** \"stream\" (the default, used by `stream()`/`generate()`) or \"async\"\n * (required for `submit()`, and for `isolateVocals`). Only consulted by\n * `submit()` — `stream()`/`generate()` always request a stream. */\n mode?: \"stream\" | \"async\";\n /** Split the generated track into a vocals-only stem alongside the mix.\n * Requires `mode: \"async\"`; if `mode` is left unset it defaults to\n * \"async\" automatically. Only usable via `submit()` — the backend\n * rejects it on the plain stream. */\n isolateVocals?: boolean;\n /** Keep the source speech/vocals in the async result. Current name for\n * `isolateVocals`; both are accepted and OR'd server-side. Requires\n * `mode: \"async\"` (auto-selected by `submit()`). */\n preserveSpeech?: boolean;\n /** Container for the async result. `wav` requires async. Defaults to m4a. */\n outputFormat?: \"m4a\" | \"wav\";\n /** Duck the generated music under the source voice at finalize time.\n * Default-ON server-side in async mode: leave unset to keep it on, pass\n * `false` to opt out. Free, best-effort; only valid on `submit()`. */\n ducking?: boolean;\n}\n\n/** One service's free-trial allowance. `remaining` is already floored at 0,\n * so it is safe to compare directly. */\nexport interface TrialQuota {\n granted: number;\n used: number;\n remaining: number;\n}\n\nexport interface AccountServices {\n available_services: string[];\n rpm_limit: number;\n concurrency_limit: number;\n discount_factor: number | string;\n max_upload_size_mb: number | null;\n /** Free-trial allowance keyed by service (`granted` / `used` /\n * `remaining`). Present only for self-serve accounts — always treat it as\n * possibly absent, and treat a service missing from the map as \"no trial\n * allowance\", not as an error. */\n trial?: Record<string, TrialQuota>;\n}\n\nexport interface UsageSummary {\n total_requests: number;\n total_duration_seconds: number;\n total_cost: number | string;\n period_start: string;\n period_end: string;\n [key: string]: unknown;\n}\n\nexport interface DailyUsage {\n date: string;\n requests: number;\n duration_seconds: number;\n cost: number | string;\n}\n\nexport interface UsageResponse {\n summary: UsageSummary;\n daily: DailyUsage[];\n}\n\nexport function isAudioChunkEvent(event: StreamEvent): event is AudioChunkEvent {\n return event.type === \"audio_chunk\" && (event as AudioChunkEvent).data instanceof Uint8Array;\n}\n\nexport function isErrorEvent(event: StreamEvent): event is ErrorEvent {\n return event.type === \"error\";\n}\n\n/** SFX segments (unlike music `Segment`) require `end`, must start at 0,\n * and be contiguous; validated server-side. */\nexport interface SfxSegment {\n start: number;\n end: number;\n prompt: string;\n}\n\nexport type SfxAudioFormat = \"wav\" | \"mp3\" | \"aac\" | \"flac\";\n\n/** Submission ack for the async SFX endpoints. */\nexport interface SfxTask {\n task_id: string;\n status: string;\n}\n\n/** A generated file re-hosted on R2 behind a presigned URL. */\nexport interface SfxMedia {\n url: string;\n content_type?: string;\n file_size?: number;\n}\n\nexport interface SfxError {\n code?: string;\n message?: string;\n}\n\n/**\n * Common shape of any polled task (`tasks.get`/`tasks.wait`), regardless of\n * which endpoint created it. `Tasks.get`/`Tasks.wait` are generic over this so\n * each endpoint's result type (e.g. `SfxResult`, `MusicTaskResult`) can add\n * its own `audio`/media fields while sharing the status/error/refund\n * bookkeeping the poller relies on.\n */\nexport interface BaseTaskResult {\n task_id: string;\n type?: string;\n status: \"processing\" | \"succeeded\" | \"failed\" | (string & {});\n /** Only present when the account's task-field whitelist enables cost. */\n cost?: number;\n error?: SfxError;\n refunded?: boolean;\n [key: string]: unknown;\n}\n\n/** State of an SFX task (`tasks.get`) or its final result (`wait`/`generate`). */\nexport interface SfxResult extends BaseTaskResult {\n audio?: SfxMedia;\n /** Kept for backward compatibility; no longer populated — video-to-sfx returns audio only. */\n video?: SfxMedia;\n}\n\nexport interface TextToSfxParams {\n prompt: string;\n duration: number;\n audioFormat?: SfxAudioFormat;\n}\n\nexport interface VideoToSfxParams {\n video?: VideoInput;\n videoUrl?: string;\n prompt?: string;\n segments?: SfxSegment[];\n audioFormat?: SfxAudioFormat;\n}\n\n/** One decoded audio stream of an async video-to-music result. Unlike SFX,\n * `audio` on a music task is always an array — even without `isolateVocals` —\n * since a music generation can carry more than one output stream. */\nexport interface MusicMediaEntry extends SfxMedia {\n stream_index: number;\n sample_rate?: number;\n channels?: number;\n}\n\n/** One muxed audio+video-aligned output, present only when `isolateVocals`\n * is set. */\nexport interface MusicMuxEntry extends SfxMedia {\n stream_index: number;\n}\n\nexport interface MusicTitle {\n title: string;\n summary?: string;\n display_tags?: string[];\n}\n\n/** State of an async video-to-music task (`tasks.get`) or its final result\n * (`tasks.wait<MusicTaskResult>()`). Only reachable via `videoToMusic.submit()`\n * with `mode: \"async\"`. */\nexport interface MusicTaskResult extends BaseTaskResult {\n audio?: MusicMediaEntry[];\n /** Vocals-only stem; present only when `isolateVocals` was requested. */\n vocals?: SfxMedia;\n /** Muxed output per stream; present only when `isolateVocals` was requested. */\n mux?: MusicMuxEntry[];\n /** Music ducked under the source voice; present only when `ducking` ran. */\n ducked?: MusicMediaEntry[];\n title?: MusicTitle;\n duration_seconds?: number;\n}\n\nexport interface WaitOptions {\n /** Milliseconds between polls. Default 2000. */\n pollInterval?: number;\n /** Overall deadline in milliseconds. Default 600000. */\n timeout?: number;\n}\n\n/** Result of an async video-to-video task (`videoToVideoMusic`/`videoToVideoSfx`):\n * a re-hosted video with generated music or SFX muxed in. */\nexport interface VideoResult extends BaseTaskResult {\n video?: SfxMedia;\n duration_seconds?: number;\n}\n\nexport interface VideoToVideoMusicParams {\n video?: VideoInput;\n videoUrl?: string;\n prompt?: string;\n /** Keep the source speech/vocals in the output. Both this and the legacy\n * `isolateVocals` are accepted and OR'd server-side. */\n preserveSpeech?: boolean;\n /** @deprecated Legacy alias for `preserveSpeech`. */\n isolateVocals?: boolean;\n}\n\nexport interface VideoToVideoSfxParams {\n video?: VideoInput;\n videoUrl?: string;\n prompt?: string;\n segments?: SfxSegment[];\n}\n\n/** Params for `videoToSound` and `videoToVideoSound`. Both endpoints take the\n * identical form, so they share one params type. */\nexport interface VideoToSoundParams {\n video?: VideoInput;\n videoUrl?: string;\n /** Style hint for the generated music bed. */\n musicPrompt?: string;\n /** Description of the sound effects layered over the music. */\n sfxPrompt?: string;\n /** Per-segment SFX descriptions; must start at 0 and be contiguous. */\n segments?: SfxSegment[];\n /** Keep the source speech in the result. */\n preserveSpeech?: boolean;\n /** Duck the generated music under the source speech. Default-ON\n * server-side: leave unset to keep it on, pass `false` to opt out. */\n ducking?: boolean;\n}\n\n/** Result of a `videoToSound` / `videoToVideoSound` task (`tasks.get`) or its\n * final state (`generate`).\n *\n * The combined music+SFX result is `output_url` — a bare presigned URL rather\n * than a media object, since these endpoints render one artifact whose kind is\n * announced by `output_type` (\"audio\" for video-to-sound, \"video\" for\n * video-to-video-sound). `music`, `music_processed` and `sfx` are the\n * individual stems; pass any of them, or `output_url` itself, to `download()`. */\nexport interface SoundResult extends BaseTaskResult {\n output_url?: string;\n output_type?: \"audio\" | \"video\";\n output_bytes?: number;\n music?: SfxMedia;\n /** Present only when `preserveSpeech`/`ducking` altered the music bed. */\n music_processed?: SfxMedia;\n sfx?: SfxMedia;\n duration_seconds?: number;\n}\n\n/**\n * A target language for /v1/dubbing. The union stays open (`string & {}`) so a\n * language added server-side still type-checks against an older SDK — the\n * backend, not this list, is the authority on what is supported.\n */\nexport type DubbingLanguage =\n | \"en\"\n | \"zh_cn\"\n | \"ja\"\n | \"ko\"\n | \"pt\"\n | \"es\"\n | \"de\"\n | \"fr\"\n | \"it\"\n | \"ru\"\n | (string & {});\n\nexport interface DubbingParams {\n /** Exactly one of `video` / `videoUrl`. */\n video?: VideoInput;\n /**\n * Exactly one of `video` / `videoUrl`. Must be an `https://` URL — the\n * dubbing pipeline fetches the source itself and rejects plain http.\n */\n videoUrl?: string;\n /** Omit to get the server default, `[\"zh_cn\", \"es\", \"fr\"]`. */\n languages?: DubbingLanguage[];\n}\n\nexport interface DubbingResult extends BaseTaskResult {\n /**\n * One dubbed video URL per requested language, keyed by language code.\n * Unlike every other endpoint's envelope this is a map, not an `audio`/\n * `video` slot — a dubbing task renders N artifacts, one per language.\n */\n outputs?: Record<string, string>;\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -94,6 +94,8 @@ interface VideoToMusicParams {
94
94
  * `false` to opt out. Free, best-effort; only valid on `submit()`. */
95
95
  ducking?: boolean;
96
96
  }
97
+ /** One service's free-trial allowance. `remaining` is already floored at 0,
98
+ * so it is safe to compare directly. */
97
99
  interface TrialQuota {
98
100
  granted: number;
99
101
  used: number;
@@ -105,8 +107,10 @@ interface AccountServices {
105
107
  concurrency_limit: number;
106
108
  discount_factor: number | string;
107
109
  max_upload_size_mb: number | null;
108
- /** Free-trial allowance keyed by service. Returned only for self-serve
109
- * accounts; absent entirely for invoiced accounts. */
110
+ /** Free-trial allowance keyed by service (`granted` / `used` /
111
+ * `remaining`). Present only for self-serve accounts — always treat it as
112
+ * possibly absent, and treat a service missing from the map as "no trial
113
+ * allowance", not as an error. */
110
114
  trial?: Record<string, TrialQuota>;
111
115
  }
112
116
  interface UsageSummary {
@@ -282,6 +286,31 @@ interface SoundResult extends BaseTaskResult {
282
286
  sfx?: SfxMedia;
283
287
  duration_seconds?: number;
284
288
  }
289
+ /**
290
+ * A target language for /v1/dubbing. The union stays open (`string & {}`) so a
291
+ * language added server-side still type-checks against an older SDK — the
292
+ * backend, not this list, is the authority on what is supported.
293
+ */
294
+ type DubbingLanguage = "en" | "zh_cn" | "ja" | "ko" | "pt" | "es" | "de" | "fr" | "it" | "ru" | (string & {});
295
+ interface DubbingParams {
296
+ /** Exactly one of `video` / `videoUrl`. */
297
+ video?: VideoInput;
298
+ /**
299
+ * Exactly one of `video` / `videoUrl`. Must be an `https://` URL — the
300
+ * dubbing pipeline fetches the source itself and rejects plain http.
301
+ */
302
+ videoUrl?: string;
303
+ /** Omit to get the server default, `["zh_cn", "es", "fr"]`. */
304
+ languages?: DubbingLanguage[];
305
+ }
306
+ interface DubbingResult extends BaseTaskResult {
307
+ /**
308
+ * One dubbed video URL per requested language, keyed by language code.
309
+ * Unlike every other endpoint's envelope this is a map, not an `audio`/
310
+ * `video` slot — a dubbing task renders N artifacts, one per language.
311
+ */
312
+ outputs?: Record<string, string>;
313
+ }
285
314
 
286
315
  declare class Account {
287
316
  private readonly client;
@@ -393,6 +422,15 @@ declare class VideoToVideoSound {
393
422
  generate(params: VideoToSoundParams, opts?: WaitOptions): Promise<SoundResult>;
394
423
  }
395
424
 
425
+ /** Dub a video into one or more target languages. Async only; the result
426
+ * carries a language → dubbed-video-URL map under `outputs`. */
427
+ declare class Dubbing {
428
+ private readonly client;
429
+ constructor(client: SoniloClient);
430
+ submit(params: DubbingParams): Promise<SfxTask>;
431
+ generate(params: DubbingParams, opts?: WaitOptions): Promise<DubbingResult>;
432
+ }
433
+
396
434
  interface SoniloClientOptions {
397
435
  /** Defaults to the SONILO_API_KEY environment variable (Node.js only). */
398
436
  apiKey?: string;
@@ -430,6 +468,7 @@ declare class SoniloClient {
430
468
  readonly videoToVideoSfx: VideoToVideoSfx;
431
469
  readonly videoToSound: VideoToSound;
432
470
  readonly videoToVideoSound: VideoToVideoSound;
471
+ readonly dubbing: Dubbing;
433
472
  constructor(options?: SoniloClientOptions);
434
473
  /**
435
474
  * Perform an authenticated request; throws a typed error on non-2xx.
@@ -460,6 +499,14 @@ declare class AuthenticationError extends APIError {
460
499
  }
461
500
  declare class PaymentRequiredError extends APIError {
462
501
  }
502
+ /** The account's free trial for this service is spent and it has never been
503
+ * funded — the caller should add a payment method rather than retry. A
504
+ * subclass of `PaymentRequiredError`, so code that already catches every 402
505
+ * keeps working; catch this first to tell "you haven't paid us yet" apart
506
+ * from a funded wallet that ran dry (`PaymentRequiredError` with
507
+ * `code === "insufficient_balance"`). */
508
+ declare class TrialExhaustedError extends PaymentRequiredError {
509
+ }
463
510
  declare class BadRequestError extends APIError {
464
511
  get detail(): string | undefined;
465
512
  }
@@ -503,6 +550,6 @@ declare class RequestTimeoutError extends SoniloError {
503
550
  declare function download(media: SfxMedia | string | undefined, fetchFn?: typeof globalThis.fetch, timeout?: number): Promise<Uint8Array>;
504
551
 
505
552
  /** The SDK's own version. Generated by scripts/sync-versions.mjs — do not edit. */
506
- declare const VERSION = "0.6.0";
553
+ declare const VERSION = "0.7.0";
507
554
 
508
- export { APIError, type AccountServices, type AudioChunkEvent, AuthenticationError, BadRequestError, type BaseTaskResult, type CompleteEvent, type CostEvent, type CostInfo, DEFAULT_TIMEOUT_MS, type DailyUsage, type ErrorEvent, GenerationError, type MusicMediaEntry, type MusicMuxEntry, type MusicTaskResult, type MusicTitle, PaymentRequiredError, RateLimitError, RequestTimeoutError, type Segment, type SegmentLabel, type SfxAudioFormat, type SfxError, type SfxMedia, type SfxResult, type SfxSegment, type SfxTask, SoniloClient, type SoniloClientOptions, SoniloError, type SoundResult, type StreamEvent, TaskFailedError, TaskTimeoutError, type TextToMusicParams, type TextToSfxParams, type TitleEvent, type Track, type TrialQuota, type UnknownEvent, type UsageResponse, type UsageSummary, VERSION, type VideoInput, type VideoResult, type VideoToMusicParams, type VideoToSfxParams, type VideoToSoundParams, type VideoToVideoMusicParams, type VideoToVideoSfxParams, type WaitOptions, download, isAudioChunkEvent, isErrorEvent };
555
+ export { APIError, type AccountServices, type AudioChunkEvent, AuthenticationError, BadRequestError, type BaseTaskResult, type CompleteEvent, type CostEvent, type CostInfo, DEFAULT_TIMEOUT_MS, type DailyUsage, type DubbingLanguage, type DubbingParams, type DubbingResult, type ErrorEvent, GenerationError, type MusicMediaEntry, type MusicMuxEntry, type MusicTaskResult, type MusicTitle, PaymentRequiredError, RateLimitError, RequestTimeoutError, type Segment, type SegmentLabel, type SfxAudioFormat, type SfxError, type SfxMedia, type SfxResult, type SfxSegment, type SfxTask, SoniloClient, type SoniloClientOptions, SoniloError, type SoundResult, type StreamEvent, TaskFailedError, TaskTimeoutError, type TextToMusicParams, type TextToSfxParams, type TitleEvent, type Track, TrialExhaustedError, type TrialQuota, type UnknownEvent, type UsageResponse, type UsageSummary, VERSION, type VideoInput, type VideoResult, type VideoToMusicParams, type VideoToSfxParams, type VideoToSoundParams, type VideoToVideoMusicParams, type VideoToVideoSfxParams, type WaitOptions, download, isAudioChunkEvent, isErrorEvent };
package/dist/index.d.ts CHANGED
@@ -94,6 +94,8 @@ interface VideoToMusicParams {
94
94
  * `false` to opt out. Free, best-effort; only valid on `submit()`. */
95
95
  ducking?: boolean;
96
96
  }
97
+ /** One service's free-trial allowance. `remaining` is already floored at 0,
98
+ * so it is safe to compare directly. */
97
99
  interface TrialQuota {
98
100
  granted: number;
99
101
  used: number;
@@ -105,8 +107,10 @@ interface AccountServices {
105
107
  concurrency_limit: number;
106
108
  discount_factor: number | string;
107
109
  max_upload_size_mb: number | null;
108
- /** Free-trial allowance keyed by service. Returned only for self-serve
109
- * accounts; absent entirely for invoiced accounts. */
110
+ /** Free-trial allowance keyed by service (`granted` / `used` /
111
+ * `remaining`). Present only for self-serve accounts — always treat it as
112
+ * possibly absent, and treat a service missing from the map as "no trial
113
+ * allowance", not as an error. */
110
114
  trial?: Record<string, TrialQuota>;
111
115
  }
112
116
  interface UsageSummary {
@@ -282,6 +286,31 @@ interface SoundResult extends BaseTaskResult {
282
286
  sfx?: SfxMedia;
283
287
  duration_seconds?: number;
284
288
  }
289
+ /**
290
+ * A target language for /v1/dubbing. The union stays open (`string & {}`) so a
291
+ * language added server-side still type-checks against an older SDK — the
292
+ * backend, not this list, is the authority on what is supported.
293
+ */
294
+ type DubbingLanguage = "en" | "zh_cn" | "ja" | "ko" | "pt" | "es" | "de" | "fr" | "it" | "ru" | (string & {});
295
+ interface DubbingParams {
296
+ /** Exactly one of `video` / `videoUrl`. */
297
+ video?: VideoInput;
298
+ /**
299
+ * Exactly one of `video` / `videoUrl`. Must be an `https://` URL — the
300
+ * dubbing pipeline fetches the source itself and rejects plain http.
301
+ */
302
+ videoUrl?: string;
303
+ /** Omit to get the server default, `["zh_cn", "es", "fr"]`. */
304
+ languages?: DubbingLanguage[];
305
+ }
306
+ interface DubbingResult extends BaseTaskResult {
307
+ /**
308
+ * One dubbed video URL per requested language, keyed by language code.
309
+ * Unlike every other endpoint's envelope this is a map, not an `audio`/
310
+ * `video` slot — a dubbing task renders N artifacts, one per language.
311
+ */
312
+ outputs?: Record<string, string>;
313
+ }
285
314
 
286
315
  declare class Account {
287
316
  private readonly client;
@@ -393,6 +422,15 @@ declare class VideoToVideoSound {
393
422
  generate(params: VideoToSoundParams, opts?: WaitOptions): Promise<SoundResult>;
394
423
  }
395
424
 
425
+ /** Dub a video into one or more target languages. Async only; the result
426
+ * carries a language → dubbed-video-URL map under `outputs`. */
427
+ declare class Dubbing {
428
+ private readonly client;
429
+ constructor(client: SoniloClient);
430
+ submit(params: DubbingParams): Promise<SfxTask>;
431
+ generate(params: DubbingParams, opts?: WaitOptions): Promise<DubbingResult>;
432
+ }
433
+
396
434
  interface SoniloClientOptions {
397
435
  /** Defaults to the SONILO_API_KEY environment variable (Node.js only). */
398
436
  apiKey?: string;
@@ -430,6 +468,7 @@ declare class SoniloClient {
430
468
  readonly videoToVideoSfx: VideoToVideoSfx;
431
469
  readonly videoToSound: VideoToSound;
432
470
  readonly videoToVideoSound: VideoToVideoSound;
471
+ readonly dubbing: Dubbing;
433
472
  constructor(options?: SoniloClientOptions);
434
473
  /**
435
474
  * Perform an authenticated request; throws a typed error on non-2xx.
@@ -460,6 +499,14 @@ declare class AuthenticationError extends APIError {
460
499
  }
461
500
  declare class PaymentRequiredError extends APIError {
462
501
  }
502
+ /** The account's free trial for this service is spent and it has never been
503
+ * funded — the caller should add a payment method rather than retry. A
504
+ * subclass of `PaymentRequiredError`, so code that already catches every 402
505
+ * keeps working; catch this first to tell "you haven't paid us yet" apart
506
+ * from a funded wallet that ran dry (`PaymentRequiredError` with
507
+ * `code === "insufficient_balance"`). */
508
+ declare class TrialExhaustedError extends PaymentRequiredError {
509
+ }
463
510
  declare class BadRequestError extends APIError {
464
511
  get detail(): string | undefined;
465
512
  }
@@ -503,6 +550,6 @@ declare class RequestTimeoutError extends SoniloError {
503
550
  declare function download(media: SfxMedia | string | undefined, fetchFn?: typeof globalThis.fetch, timeout?: number): Promise<Uint8Array>;
504
551
 
505
552
  /** The SDK's own version. Generated by scripts/sync-versions.mjs — do not edit. */
506
- declare const VERSION = "0.6.0";
553
+ declare const VERSION = "0.7.0";
507
554
 
508
- export { APIError, type AccountServices, type AudioChunkEvent, AuthenticationError, BadRequestError, type BaseTaskResult, type CompleteEvent, type CostEvent, type CostInfo, DEFAULT_TIMEOUT_MS, type DailyUsage, type ErrorEvent, GenerationError, type MusicMediaEntry, type MusicMuxEntry, type MusicTaskResult, type MusicTitle, PaymentRequiredError, RateLimitError, RequestTimeoutError, type Segment, type SegmentLabel, type SfxAudioFormat, type SfxError, type SfxMedia, type SfxResult, type SfxSegment, type SfxTask, SoniloClient, type SoniloClientOptions, SoniloError, type SoundResult, type StreamEvent, TaskFailedError, TaskTimeoutError, type TextToMusicParams, type TextToSfxParams, type TitleEvent, type Track, type TrialQuota, type UnknownEvent, type UsageResponse, type UsageSummary, VERSION, type VideoInput, type VideoResult, type VideoToMusicParams, type VideoToSfxParams, type VideoToSoundParams, type VideoToVideoMusicParams, type VideoToVideoSfxParams, type WaitOptions, download, isAudioChunkEvent, isErrorEvent };
555
+ export { APIError, type AccountServices, type AudioChunkEvent, AuthenticationError, BadRequestError, type BaseTaskResult, type CompleteEvent, type CostEvent, type CostInfo, DEFAULT_TIMEOUT_MS, type DailyUsage, type DubbingLanguage, type DubbingParams, type DubbingResult, type ErrorEvent, GenerationError, type MusicMediaEntry, type MusicMuxEntry, type MusicTaskResult, type MusicTitle, PaymentRequiredError, RateLimitError, RequestTimeoutError, type Segment, type SegmentLabel, type SfxAudioFormat, type SfxError, type SfxMedia, type SfxResult, type SfxSegment, type SfxTask, SoniloClient, type SoniloClientOptions, SoniloError, type SoundResult, type StreamEvent, TaskFailedError, TaskTimeoutError, type TextToMusicParams, type TextToSfxParams, type TitleEvent, type Track, TrialExhaustedError, type TrialQuota, type UnknownEvent, type UsageResponse, type UsageSummary, VERSION, type VideoInput, type VideoResult, type VideoToMusicParams, type VideoToSfxParams, type VideoToSoundParams, type VideoToVideoMusicParams, type VideoToVideoSfxParams, type WaitOptions, download, isAudioChunkEvent, isErrorEvent };
package/dist/index.js CHANGED
@@ -19,6 +19,8 @@ var AuthenticationError = class extends APIError {
19
19
  };
20
20
  var PaymentRequiredError = class extends APIError {
21
21
  };
22
+ var TrialExhaustedError = class extends PaymentRequiredError {
23
+ };
22
24
  var BadRequestError = class extends APIError {
23
25
  get detail() {
24
26
  const body = this.body;
@@ -88,8 +90,13 @@ async function errorFromResponse(res) {
88
90
  switch (res.status) {
89
91
  case 401:
90
92
  return new AuthenticationError(message, res.status, body);
91
- case 402:
93
+ case 402: {
94
+ const code = body?.code;
95
+ if (code === "trial_exhausted") {
96
+ return new TrialExhaustedError(message, res.status, body);
97
+ }
92
98
  return new PaymentRequiredError(message, res.status, body);
99
+ }
93
100
  case 429: {
94
101
  const ra = res.headers.get("retry-after");
95
102
  const retryAfter = ra !== null && ra !== "" && !Number.isNaN(Number(ra)) ? Number(ra) : void 0;
@@ -624,8 +631,48 @@ var VideoToVideoSound = class {
624
631
  }
625
632
  };
626
633
 
634
+ // src/resources/dubbing.ts
635
+ async function buildDubbingForm(params) {
636
+ if (params.video === void 0 === (params.videoUrl === void 0)) {
637
+ throw new SoniloError("Provide exactly one of video or videoUrl");
638
+ }
639
+ const form = new FormData();
640
+ if (params.video !== void 0) {
641
+ const { blob, filename } = await toUploadBlob(params.video);
642
+ form.set("video", blob, filename);
643
+ } else {
644
+ const url = params.videoUrl;
645
+ if (!url.toLowerCase().startsWith("https://")) {
646
+ throw new SoniloError(
647
+ "videoUrl must use https \u2014 the dubbing pipeline requires an https URL"
648
+ );
649
+ }
650
+ form.set("video_url", url);
651
+ }
652
+ if (params.languages !== void 0) {
653
+ form.set("languages", JSON.stringify(params.languages));
654
+ }
655
+ return form;
656
+ }
657
+ var Dubbing = class {
658
+ constructor(client) {
659
+ this.client = client;
660
+ }
661
+ async submit(params) {
662
+ const res = await this.client.request("/v1/dubbing", {
663
+ method: "POST",
664
+ body: await buildDubbingForm(params)
665
+ });
666
+ return await res.json();
667
+ }
668
+ async generate(params, opts) {
669
+ const task = await this.submit(params);
670
+ return this.client.tasks.wait(task.task_id, opts);
671
+ }
672
+ };
673
+
627
674
  // src/version.ts
628
- var VERSION = "0.6.0";
675
+ var VERSION = "0.7.0";
629
676
 
630
677
  // src/client.ts
631
678
  var DEFAULT_BASE_URL = "https://api.sonilo.com";
@@ -656,6 +703,7 @@ var SoniloClient = class {
656
703
  this.videoToVideoSfx = new VideoToVideoSfx(this);
657
704
  this.videoToSound = new VideoToSound(this);
658
705
  this.videoToVideoSound = new VideoToVideoSound(this);
706
+ this.dubbing = new Dubbing(this);
659
707
  }
660
708
  /**
661
709
  * Perform an authenticated request; throws a typed error on non-2xx.
@@ -727,6 +775,7 @@ export {
727
775
  SoniloError,
728
776
  TaskFailedError,
729
777
  TaskTimeoutError,
778
+ TrialExhaustedError,
730
779
  VERSION,
731
780
  download,
732
781
  isAudioChunkEvent,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/resources/account.ts","../src/resources/tasks.ts","../src/streaming.ts","../src/resources/textToMusic.ts","../src/upload.ts","../src/resources/videoToMusic.ts","../src/resources/textToSfx.ts","../src/resources/videoToSfx.ts","../src/resources/videoToVideoMusic.ts","../src/resources/videoToVideoSfx.ts","../src/resources/soundForm.ts","../src/resources/videoToSound.ts","../src/resources/videoToVideoSound.ts","../src/version.ts","../src/client.ts","../src/download.ts","../src/types.ts"],"sourcesContent":["export class SoniloError extends Error {\n constructor(message: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\nexport class APIError extends SoniloError {\n readonly status: number;\n readonly body: unknown;\n /** The API's typed error code (e.g. \"rate_limit_exceeded\"), distinct from the HTTP status. */\n readonly code?: string;\n /** Per-field validation details, present on a 422. */\n readonly errors?: unknown[];\n\n constructor(message: string, status: number, body?: unknown) {\n super(message);\n this.status = status;\n this.body = body;\n const parsed = body as { code?: unknown; errors?: unknown } | undefined;\n this.code = typeof parsed?.code === \"string\" ? parsed.code : undefined;\n this.errors = Array.isArray(parsed?.errors) ? parsed.errors : undefined;\n }\n}\n\nexport class AuthenticationError extends APIError {}\n\nexport class PaymentRequiredError extends APIError {}\n\nexport class BadRequestError extends APIError {\n get detail(): string | undefined {\n const body = this.body as { message?: unknown; detail?: unknown } | undefined;\n if (typeof body?.message === \"string\" && body.message) {\n return body.message;\n }\n return typeof body?.detail === \"string\" ? body.detail : undefined;\n }\n}\n\nexport class RateLimitError extends APIError {\n readonly retryAfter?: number;\n\n constructor(message: string, status: number, body?: unknown, retryAfter?: number) {\n super(message, status, body);\n this.retryAfter = retryAfter;\n }\n}\n\n/** Raised by generate() when an `error` event arrives mid-stream. */\nexport class GenerationError extends SoniloError {\n readonly code?: string;\n\n constructor(message: string, code?: string) {\n super(message);\n this.code = code;\n }\n}\n\n/** Raised by tasks.wait()/generate() when an SFX task reaches `failed`. */\nexport class TaskFailedError extends SoniloError {\n readonly code?: string;\n readonly taskId: string;\n readonly refunded?: boolean;\n\n constructor(\n message: string,\n opts: { code?: string; taskId: string; refunded?: boolean },\n ) {\n super(message);\n this.code = opts.code;\n this.taskId = opts.taskId;\n this.refunded = opts.refunded;\n }\n}\n\n/** Poll deadline passed. The task may still finish server-side — resume with\n * tasks.wait(taskId) or tasks.get(taskId). */\nexport class TaskTimeoutError extends SoniloError {\n readonly taskId: string;\n\n constructor(message: string, taskId: string) {\n super(message);\n this.taskId = taskId;\n }\n}\n\n/** Raised when a one-shot request or download is aborted by its own timeout\n * signal (as opposed to a caller-supplied AbortSignal, which propagates\n * untouched). */\nexport class RequestTimeoutError extends SoniloError {}\n\n/**\n * True if `err` is the rejection produced when an `AbortSignal.timeout()`\n * we created fires. Used to distinguish \"our\" timeout aborts (which should be\n * rethrown as `RequestTimeoutError`) from a caller-supplied signal's abort\n * (which must propagate untouched).\n */\nexport function isTimeoutSignalError(err: unknown): boolean {\n return err instanceof Error && (err.name === \"TimeoutError\" || err.name === \"AbortError\");\n}\n\nexport async function errorFromResponse(res: Response): Promise<APIError> {\n const text = await res.text().catch(() => \"\");\n let body: unknown = text;\n try {\n body = JSON.parse(text);\n } catch {\n // keep raw text\n }\n const parsed = body as { message?: unknown; detail?: unknown } | undefined;\n const rawMessage = typeof parsed?.message === \"string\" && parsed.message ? parsed.message : undefined;\n const rawDetail = parsed?.detail;\n const isDetailAbsent = rawDetail === undefined || rawDetail === null || rawDetail === \"\";\n let reason: string;\n if (rawMessage !== undefined) {\n reason = rawMessage;\n } else if (isDetailAbsent) {\n reason = res.statusText || \"request failed\";\n } else if (typeof rawDetail === \"string\") {\n reason = rawDetail;\n } else {\n try {\n reason = JSON.stringify(rawDetail);\n } catch {\n reason = res.statusText || \"request failed\";\n }\n }\n const message = `HTTP ${res.status}: ${reason}`;\n\n switch (res.status) {\n case 401:\n return new AuthenticationError(message, res.status, body);\n case 402:\n return new PaymentRequiredError(message, res.status, body);\n case 429: {\n const ra = res.headers.get(\"retry-after\");\n const retryAfter = ra !== null && ra !== \"\" && !Number.isNaN(Number(ra)) ? Number(ra) : undefined;\n return new RateLimitError(message, res.status, body, retryAfter);\n }\n case 400:\n case 413:\n case 422:\n return new BadRequestError(message, res.status, body);\n default:\n return new APIError(message, res.status, body);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport type { AccountServices, UsageResponse } from \"../types.js\";\n\nexport class Account {\n constructor(private readonly client: SoniloClient) {}\n\n async services(): Promise<AccountServices> {\n const res = await this.client.request(\"/v1/account/services\");\n return (await res.json()) as AccountServices;\n }\n\n async usage(params: { days?: number } = {}): Promise<UsageResponse> {\n const query = params.days !== undefined ? `?days=${params.days}` : \"\";\n const res = await this.client.request(`/v1/account/usage${query}`);\n return (await res.json()) as UsageResponse;\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError, TaskFailedError, TaskTimeoutError } from \"../errors.js\";\nimport type { BaseTaskResult, SfxResult, WaitOptions } from \"../types.js\";\n\nexport const DEFAULT_POLL_INTERVAL_MS = 2000;\nexport const DEFAULT_WAIT_TIMEOUT_MS = 600_000;\n\nconst sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));\n\n/** A negative delay is clamped to 0 by setTimeout, which would turn the poll\n * loop into a busy loop hammering the API until the deadline. */\nfunction validateWaitArgs(pollInterval: number, timeout: number): void {\n if (pollInterval < 0) {\n throw new SoniloError(`pollInterval must be >= 0, got ${pollInterval}`);\n }\n if (timeout < 0) {\n throw new SoniloError(`timeout must be >= 0, got ${timeout}`);\n }\n}\n\nexport class Tasks {\n constructor(private readonly client: SoniloClient) {}\n\n /**\n * Fetch current task state. Never throws on a failed status.\n *\n * Generic over the result shape so callers can request the endpoint-\n * specific type, e.g. `client.tasks.get<MusicTaskResult>(taskId)`.\n * Defaults to `SfxResult` for back-compat.\n */\n async get<T extends BaseTaskResult = SfxResult>(taskId: string): Promise<T> {\n const res = await this.client.request(`/v1/tasks/${encodeURIComponent(taskId)}`);\n return (await res.json()) as T;\n }\n\n /**\n * Poll until the task is terminal; throw on failure or deadline.\n *\n * Generic over the result shape, e.g.\n * `client.tasks.wait<MusicTaskResult>(taskId)`. Defaults to `SfxResult`\n * for back-compat.\n */\n async wait<T extends BaseTaskResult = SfxResult>(\n taskId: string,\n opts: WaitOptions = {},\n ): Promise<T> {\n const pollInterval = opts.pollInterval ?? DEFAULT_POLL_INTERVAL_MS;\n const timeout = opts.timeout ?? DEFAULT_WAIT_TIMEOUT_MS;\n validateWaitArgs(pollInterval, timeout);\n const deadline = performance.now() + timeout;\n for (;;) {\n const result = await this.get<T>(taskId);\n if (result.status === \"succeeded\") return result;\n if (result.status === \"failed\") {\n const message = result.error?.message || \"Generation failed\";\n throw new TaskFailedError(`Task ${taskId} failed: ${message}`, {\n code: result.error?.code,\n taskId,\n refunded: result.refunded,\n });\n }\n const remaining = deadline - performance.now();\n if (remaining <= 0) {\n throw new TaskTimeoutError(\n `Task ${taskId} still processing after ${timeout}ms; ` +\n \"it may finish later — resume with tasks.wait or tasks.get\",\n taskId,\n );\n }\n await sleep(Math.min(pollInterval, remaining));\n }\n }\n}\n","import { GenerationError } from \"./errors.js\";\nimport type { CostInfo, StreamEvent, Track } from \"./types.js\";\n\nexport function decodeBase64(b64: string): Uint8Array {\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n}\n\n/** Returns `null` for a valid-JSON-but-non-object line (e.g. a bare `null`\n * or a number/string), which carries no event `type` and is skipped like any\n * other junk line rather than crashing on a `.type` read off `null`. */\nfunction toEvent(line: string): StreamEvent | null {\n const parsed: unknown = JSON.parse(line);\n if (typeof parsed !== \"object\" || parsed === null) return null;\n const raw = parsed as { type: string; [key: string]: unknown };\n if (raw.type === \"audio_chunk\" && typeof raw.data === \"string\") {\n try {\n return { ...raw, type: \"audio_chunk\", data: decodeBase64(raw.data) };\n } catch {\n // Don't raise here: this must reach collectTrack's malformed-chunk\n // check, which turns undecodable data into a typed GenerationError.\n // Raising in place would let a raw DOMException escape\n // stream()/generate(), breaking the SDK's \"all errors extend\n // SoniloError\" contract.\n }\n }\n return raw as StreamEvent;\n}\n\nexport async function* parseNdjson(\n body: ReadableStream<Uint8Array>,\n): AsyncGenerator<StreamEvent, void, undefined> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n let nl: number;\n while ((nl = buffer.indexOf(\"\\n\")) !== -1) {\n const line = buffer.slice(0, nl).trim();\n buffer = buffer.slice(nl + 1);\n if (line) {\n const ev = toEvent(line);\n if (ev !== null) yield ev;\n }\n }\n }\n buffer += decoder.decode();\n const tail = buffer.trim();\n if (tail) {\n const ev = toEvent(tail);\n if (ev !== null) yield ev;\n }\n } finally {\n await reader.cancel().catch(() => {});\n }\n}\n\nexport async function collectTrack(events: AsyncIterable<StreamEvent>): Promise<Track> {\n const chunks: Uint8Array[] = [];\n let title: string | undefined;\n let cost: CostInfo | undefined;\n let sawComplete = false;\n\n for await (const ev of events) {\n if (ev.type === \"audio_chunk\") {\n // A malformed chunk (missing/non-decodable `data`) must not be\n // silently dropped: that would hand back a \"successful\" Track with\n // empty or truncated audio and no indication anything went wrong.\n if (!(ev.data instanceof Uint8Array)) {\n throw new GenerationError(\n \"received a malformed audio_chunk event (missing or non-decodable data)\",\n );\n }\n chunks.push(ev.data);\n } else if (ev.type === \"title\" && typeof ev.title === \"string\") {\n title = ev.title;\n } else if (ev.type === \"cost\") {\n const { type: _type, ...rest } = ev;\n cost = rest as CostInfo;\n } else if (ev.type === \"error\") {\n const message = typeof ev.message === \"string\" && ev.message !== \"\" ? ev.message : \"generation failed\";\n const code = typeof ev.code === \"string\" ? ev.code : undefined;\n throw new GenerationError(message, code);\n } else if (ev.type === \"complete\") {\n sawComplete = true;\n }\n // unknown event types: ignored\n }\n\n if (!sawComplete) {\n throw new GenerationError(\"stream ended before a 'complete' event (truncated response)\");\n }\n\n const total = chunks.reduce((n, c) => n + c.length, 0);\n const audio = new Uint8Array(total);\n let offset = 0;\n for (const c of chunks) {\n audio.set(c, offset);\n offset += c.length;\n }\n return { audio, title, cost };\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { collectTrack, parseNdjson } from \"../streaming.js\";\nimport type { SfxTask, StreamEvent, TextToMusicParams, Track } from \"../types.js\";\n\nexport class TextToMusic {\n constructor(private readonly client: SoniloClient) {}\n\n /** Stream raw generation events (audio chunks pre-decoded to bytes). */\n async *stream(params: TextToMusicParams): AsyncGenerator<StreamEvent, void, undefined> {\n const form = new FormData();\n form.set(\"prompt\", params.prompt);\n form.set(\"duration\", String(params.duration));\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n // Opt out of the client's absolute request timeout: this holds the\n // response body open and reads NDJSON chunks for as long as generation\n // takes, so an AbortSignal keyed to elapsed time would kill a healthy,\n // still-streaming, long-duration track. Pass `params.signal` yourself to\n // bound or cancel the stream instead — it is forwarded to `fetch` as-is.\n const res = await this.client.request(\n \"/v1/text-to-music\",\n { method: \"POST\", body: form, signal: params.signal },\n { timeout: null },\n );\n if (!res.body) throw new SoniloError(\"Response has no body\");\n yield* parseNdjson(res.body);\n }\n\n /** Generate and buffer the whole track; throws GenerationError on stream errors. */\n generate(params: TextToMusicParams): Promise<Track> {\n return collectTrack(this.stream(params));\n }\n\n /**\n * Submit an async text-to-music task; poll with\n * `client.tasks.wait<MusicTaskResult>(task.task_id)`. Required for\n * `outputFormat: \"wav\"`. `stream()`/`generate()` remain the streaming path.\n */\n async submit(params: TextToMusicParams): Promise<SfxTask> {\n const mode = params.mode ?? \"async\";\n if (mode !== \"async\") {\n throw new SoniloError('submit() requires mode: \"async\"');\n }\n const form = new FormData();\n form.set(\"prompt\", params.prompt);\n form.set(\"duration\", String(params.duration));\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n form.set(\"mode\", mode);\n if (params.outputFormat !== undefined) {\n form.set(\"output_format\", params.outputFormat);\n }\n const res = await this.client.request(\"/v1/text-to-music\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n}\n","import { SoniloError } from \"./errors.js\";\nimport type { VideoInput } from \"./types.js\";\n\nconst DEFAULT_FILENAME = \"video.mp4\";\n\n/**\n * Normalize every accepted video input into a FormData-ready Blob.\n * String inputs are file paths and work only in Node.js; browsers must\n * pass File/Blob/bytes/streams.\n */\nexport async function toUploadBlob(\n video: VideoInput,\n): Promise<{ blob: Blob; filename: string }> {\n if (typeof video === \"string\") {\n const isNode =\n typeof process !== \"undefined\" && Boolean((process as { versions?: { node?: string } }).versions?.node);\n if (!isNode) {\n throw new SoniloError(\n \"File paths are only supported in Node.js; pass a File or Blob in the browser\",\n );\n }\n const fsModule = \"node:fs/promises\";\n const { readFile } = (await import(\n /* webpackIgnore: true */ /* @vite-ignore */ fsModule\n )) as typeof import(\"node:fs/promises\");\n const data = await readFile(video);\n const filename = video.split(/[\\\\/]/).pop() || DEFAULT_FILENAME;\n return { blob: new Blob([data]), filename };\n }\n if (typeof File !== \"undefined\" && video instanceof File) {\n return { blob: video, filename: video.name || DEFAULT_FILENAME };\n }\n if (video instanceof Blob) {\n return { blob: video, filename: DEFAULT_FILENAME };\n }\n if (video instanceof Uint8Array) {\n return { blob: new Blob([video as unknown as BlobPart]), filename: DEFAULT_FILENAME };\n }\n if (video instanceof ArrayBuffer) {\n return { blob: new Blob([video]), filename: DEFAULT_FILENAME };\n }\n if (video instanceof ReadableStream) {\n return { blob: await new Response(video).blob(), filename: DEFAULT_FILENAME };\n }\n throw new SoniloError(\"Unsupported video input type\");\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { collectTrack, parseNdjson } from \"../streaming.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { SfxTask, StreamEvent, Track, VideoToMusicParams } from \"../types.js\";\n\nexport class VideoToMusic {\n constructor(private readonly client: SoniloClient) {}\n\n async *stream(params: VideoToMusicParams): AsyncGenerator<StreamEvent, void, undefined> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n // Opt out of the client's absolute request timeout: this holds the\n // response body open and reads NDJSON chunks for as long as generation\n // takes, so an AbortSignal keyed to elapsed time would kill a healthy,\n // still-streaming request (e.g. a slow video upload or long track). Pass\n // `params.signal` yourself to bound or cancel the stream instead — it is\n // forwarded to `fetch` as-is.\n const res = await this.client.request(\n \"/v1/video-to-music\",\n { method: \"POST\", body: form, signal: params.signal },\n { timeout: null },\n );\n if (!res.body) throw new SoniloError(\"Response has no body\");\n yield* parseNdjson(res.body);\n }\n\n generate(params: VideoToMusicParams): Promise<Track> {\n return collectTrack(this.stream(params));\n }\n\n /**\n * Submit an async video-to-music task; poll its result with\n * `client.tasks.wait<MusicTaskResult>(task.task_id)`. Required for\n * `isolateVocals` — the backend rejects vocal isolation on the plain\n * stream, and it only ever runs in async mode.\n */\n async submit(params: VideoToMusicParams): Promise<SfxTask> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n let mode = params.mode;\n const needsAsync =\n params.isolateVocals ||\n params.preserveSpeech ||\n params.ducking !== undefined ||\n params.outputFormat === \"wav\";\n // submit() always wants an async task ack, never a stream. Default to\n // async; only object if the caller explicitly asked for stream while\n // also requesting an async-only feature.\n if (mode === undefined) mode = \"async\";\n if (needsAsync && mode !== \"async\") {\n throw new SoniloError(\n 'isolateVocals/preserveSpeech/ducking/outputFormat \"wav\" require mode: \"async\"',\n );\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n form.set(\"mode\", mode);\n if (params.preserveSpeech !== undefined) {\n form.set(\"preserve_speech\", String(params.preserveSpeech));\n }\n if (params.isolateVocals !== undefined) {\n form.set(\"isolate_vocals\", String(params.isolateVocals));\n }\n if (params.outputFormat !== undefined) {\n form.set(\"output_format\", params.outputFormat);\n }\n if (params.ducking !== undefined) {\n form.set(\"ducking\", String(params.ducking));\n }\n const res = await this.client.request(\"/v1/video-to-music\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport type { SfxResult, SfxTask, TextToSfxParams, WaitOptions } from \"../types.js\";\n\nexport class TextToSfx {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: TextToSfxParams): Promise<SfxTask> {\n const form = new FormData();\n form.set(\"prompt\", params.prompt);\n form.set(\"duration\", String(params.duration));\n if (params.audioFormat !== undefined) form.set(\"audio_format\", params.audioFormat);\n const res = await this.client.request(\"/v1/text-to-sfx\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: TextToSfxParams, opts?: WaitOptions): Promise<SfxResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait(task.task_id, opts);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { SfxResult, SfxTask, VideoToSfxParams, WaitOptions } from \"../types.js\";\n\nexport class VideoToSfx {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToSfxParams): Promise<SfxTask> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n if (params.audioFormat !== undefined) form.set(\"audio_format\", params.audioFormat);\n const res = await this.client.request(\"/v1/video-to-sfx\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToSfxParams, opts?: WaitOptions): Promise<SfxResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait(task.task_id, opts);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { SfxTask, VideoResult, VideoToVideoMusicParams, WaitOptions } from \"../types.js\";\n\n/** Generate an original score for a video and get back a re-hosted video with\n * the music muxed in. Async only: `submit()` returns a task ack; poll with\n * `client.tasks.wait<VideoResult>(id)`, or use `generate()` to do both. */\nexport class VideoToVideoMusic {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToVideoMusicParams): Promise<SfxTask> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.preserveSpeech !== undefined) {\n form.set(\"preserve_speech\", String(params.preserveSpeech));\n }\n if (params.isolateVocals !== undefined) {\n form.set(\"isolate_vocals\", String(params.isolateVocals));\n }\n const res = await this.client.request(\"/v1/video-to-video-music\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToVideoMusicParams, opts?: WaitOptions): Promise<VideoResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait<VideoResult>(task.task_id, opts);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { SfxTask, VideoResult, VideoToVideoSfxParams, WaitOptions } from \"../types.js\";\n\n/** Generate sound effects for a video and get back a re-hosted video with the\n * SFX muxed in. Async only. */\nexport class VideoToVideoSfx {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToVideoSfxParams): Promise<SfxTask> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n const res = await this.client.request(\"/v1/video-to-video-sfx\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToVideoSfxParams, opts?: WaitOptions): Promise<VideoResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait<VideoResult>(task.task_id, opts);\n }\n}\n","import { SoniloError } from \"../errors.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { VideoToSoundParams } from \"../types.js\";\n\n/** Build the multipart body shared by /v1/video-to-sound and\n * /v1/video-to-video-sound — their form fields are identical, so the two\n * resources differ only in the path they POST to.\n *\n * Every optional field is omitted when unset rather than sent with a default:\n * `ducking` in particular is default-ON server-side, so an unset value must\n * not become an explicit \"false\" on the wire. */\nexport async function buildSoundForm(params: VideoToSoundParams): Promise<FormData> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.musicPrompt !== undefined) form.set(\"music_prompt\", params.musicPrompt);\n if (params.sfxPrompt !== undefined) form.set(\"sfx_prompt\", params.sfxPrompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n if (params.preserveSpeech !== undefined) {\n form.set(\"preserve_speech\", String(params.preserveSpeech));\n }\n if (params.ducking !== undefined) form.set(\"ducking\", String(params.ducking));\n return form;\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { buildSoundForm } from \"./soundForm.js\";\nimport type { SfxTask, SoundResult, VideoToSoundParams, WaitOptions } from \"../types.js\";\n\n/** Generate a combined music + sound-effects track for a video and get back\n * the mixed audio. Async only. */\nexport class VideoToSound {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToSoundParams): Promise<SfxTask> {\n const res = await this.client.request(\"/v1/video-to-sound\", {\n method: \"POST\",\n body: await buildSoundForm(params),\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToSoundParams, opts?: WaitOptions): Promise<SoundResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait<SoundResult>(task.task_id, opts);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { buildSoundForm } from \"./soundForm.js\";\nimport type { SfxTask, SoundResult, VideoToSoundParams, WaitOptions } from \"../types.js\";\n\n/** Generate a combined music + sound-effects track for a video and get back a\n * re-hosted video with that track muxed in. Async only. */\nexport class VideoToVideoSound {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToSoundParams): Promise<SfxTask> {\n const res = await this.client.request(\"/v1/video-to-video-sound\", {\n method: \"POST\",\n body: await buildSoundForm(params),\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToSoundParams, opts?: WaitOptions): Promise<SoundResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait<SoundResult>(task.task_id, opts);\n }\n}\n","/** The SDK's own version. Generated by scripts/sync-versions.mjs — do not edit. */\nexport const VERSION = \"0.6.0\";\n","import { RequestTimeoutError, SoniloError, errorFromResponse, isTimeoutSignalError } from \"./errors.js\";\nimport { Account } from \"./resources/account.js\";\nimport { Tasks } from \"./resources/tasks.js\";\nimport { TextToMusic } from \"./resources/textToMusic.js\";\nimport { VideoToMusic } from \"./resources/videoToMusic.js\";\nimport { TextToSfx } from \"./resources/textToSfx.js\";\nimport { VideoToSfx } from \"./resources/videoToSfx.js\";\nimport { VideoToVideoMusic } from \"./resources/videoToVideoMusic.js\";\nimport { VideoToVideoSfx } from \"./resources/videoToVideoSfx.js\";\nimport { VideoToSound } from \"./resources/videoToSound.js\";\nimport { VideoToVideoSound } from \"./resources/videoToVideoSound.js\";\nimport { VERSION } from \"./version.js\";\n\nexport interface SoniloClientOptions {\n /** Defaults to the SONILO_API_KEY environment variable (Node.js only). */\n apiKey?: string;\n /** Defaults to https://api.sonilo.com */\n baseUrl?: string;\n /** Injection point for tests and custom transports. */\n fetch?: typeof globalThis.fetch;\n /** Milliseconds before an in-flight request is aborted. Default 600000. */\n timeout?: number;\n /**\n * Identifies a wrapper built on this SDK (the CLI, the video kit) in the\n * `X-Sonilo-Client` header. Leave unset for direct SDK use — without an\n * override a wrapper's traffic is indistinguishable from the SDK's own.\n */\n clientName?: string;\n /** Version reported alongside `clientName`. Defaults to the SDK's version. */\n clientVersion?: string;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.sonilo.com\";\n\n/**\n * Reported in `X-Sonilo-Client` unless a wrapper overrides it. First-party\n * wrappers (the CLI, the video kit) pass their own name so their traffic stays\n * distinguishable from direct SDK use in server-side analytics.\n */\nexport const DEFAULT_CLIENT_NAME = \"sdk-js\";\n\n/** Milliseconds before an in-flight request is aborted, unless overridden. */\nexport const DEFAULT_TIMEOUT_MS = 600_000;\n\nexport class SoniloClient {\n readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly fetchFn: typeof globalThis.fetch;\n private readonly timeout: number;\n private readonly clientName: string;\n private readonly clientVersion: string;\n readonly account: Account;\n readonly tasks: Tasks;\n readonly textToMusic: TextToMusic;\n readonly videoToMusic: VideoToMusic;\n readonly textToSfx: TextToSfx;\n readonly videoToSfx: VideoToSfx;\n readonly videoToVideoMusic: VideoToVideoMusic;\n readonly videoToVideoSfx: VideoToVideoSfx;\n readonly videoToSound: VideoToSound;\n readonly videoToVideoSound: VideoToVideoSound;\n\n constructor(options: SoniloClientOptions = {}) {\n const envKey =\n typeof process !== \"undefined\" ? process.env?.SONILO_API_KEY : undefined;\n const apiKey = options.apiKey ?? envKey;\n if (!apiKey) {\n throw new SoniloError(\n \"Missing API key: pass { apiKey } or set the SONILO_API_KEY environment variable\",\n );\n }\n this.apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.fetchFn = (options.fetch ?? globalThis.fetch).bind(globalThis);\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;\n this.clientName = options.clientName ?? DEFAULT_CLIENT_NAME;\n this.clientVersion = options.clientVersion ?? VERSION;\n this.account = new Account(this);\n this.tasks = new Tasks(this);\n this.textToMusic = new TextToMusic(this);\n this.videoToMusic = new VideoToMusic(this);\n this.textToSfx = new TextToSfx(this);\n this.videoToSfx = new VideoToSfx(this);\n this.videoToVideoMusic = new VideoToVideoMusic(this);\n this.videoToVideoSfx = new VideoToVideoSfx(this);\n this.videoToSound = new VideoToSound(this);\n this.videoToVideoSound = new VideoToVideoSound(this);\n }\n\n /**\n * Perform an authenticated request; throws a typed error on non-2xx.\n *\n * `opts.timeout` overrides the client's default timeout for this call;\n * pass `null` to disable the abort-on-timeout behavior entirely (used by\n * the streaming music endpoints — see textToMusic.ts / videoToMusic.ts).\n * A caller-supplied `init.signal` always wins over any timeout signal.\n */\n async request(\n path: string,\n init: RequestInit = {},\n opts: { timeout?: number | null } = {},\n ): Promise<Response> {\n const headers = new Headers(init.headers);\n headers.set(\"Authorization\", `Bearer ${this.apiKey}`);\n headers.set(\"X-Sonilo-Client\", this.clientName);\n headers.set(\"X-Sonilo-Client-Version\", this.clientVersion);\n const timeout = opts.timeout === undefined ? this.timeout : opts.timeout;\n // We only \"own\" the signal (and may later rewrap its abort as a\n // RequestTimeoutError) when the caller didn't supply one and a timeout\n // is actually enabled.\n const ownsSignal = init.signal == null && timeout !== null;\n const signal = init.signal ?? (timeout === null ? undefined : AbortSignal.timeout(timeout));\n try {\n const res = await this.fetchFn(`${this.baseUrl}${path}`, { ...init, headers, signal });\n if (!res.ok) throw await errorFromResponse(res);\n return res;\n } catch (err) {\n if (ownsSignal && isTimeoutSignalError(err)) {\n throw new RequestTimeoutError(`Request to ${path} timed out after ${timeout}ms`);\n }\n throw err;\n }\n }\n}\n","import { DEFAULT_TIMEOUT_MS } from \"./client.js\";\nimport { RequestTimeoutError, SoniloError, isTimeoutSignalError } from \"./errors.js\";\nimport type { SfxMedia } from \"./types.js\";\n\n/** Fetch a result media file. The URL is presigned — no API key is sent.\n *\n * Accepts either a media object (`result.audio`, `result.music`, …) or a bare\n * URL string, which is what the combined video-to-sound endpoints return as\n * `output_url`. */\nexport async function download(\n media: SfxMedia | string | undefined,\n fetchFn: typeof globalThis.fetch = globalThis.fetch,\n timeout: number = DEFAULT_TIMEOUT_MS,\n): Promise<Uint8Array> {\n const url = typeof media === \"string\" ? media : media?.url;\n if (!url) {\n throw new SoniloError(\"No media to download\");\n }\n let res: Response;\n try {\n res = await fetchFn(url, { signal: AbortSignal.timeout(timeout) });\n } catch (err) {\n if (isTimeoutSignalError(err)) {\n throw new RequestTimeoutError(`Download of ${url} timed out after ${timeout}ms`);\n }\n throw err;\n }\n if (!res.ok) {\n throw new SoniloError(`Download failed: HTTP ${res.status}`);\n }\n return new Uint8Array(await res.arrayBuffer());\n}\n","export type SegmentLabel =\n | \"intro\"\n | \"verse\"\n | \"pre-chorus\"\n | \"chorus\"\n | \"bridge\"\n | \"break\"\n | \"silence\"\n | \"outro\"\n | \"none\";\n\nexport interface Segment {\n start: number;\n prompt: string;\n label?: SegmentLabel;\n}\n\n/** Monetary fields are strings, exactly as the backend serializes them. */\nexport interface CostInfo {\n billing_rate_per_sec: string;\n billing_before_discount: string;\n billing_after_discount: string;\n discount_factor: string;\n}\n\nexport interface AudioChunkEvent {\n type: \"audio_chunk\";\n /** Decoded from the wire's base64 by the SDK. */\n data: Uint8Array;\n}\n\nexport interface TitleEvent {\n type: \"title\";\n title: string;\n summary?: string;\n display_tags?: string[];\n [key: string]: unknown;\n}\n\nexport interface CompleteEvent {\n type: \"complete\";\n [key: string]: unknown;\n}\n\nexport interface ErrorEvent {\n type: \"error\";\n code?: string;\n message?: string;\n [key: string]: unknown;\n}\n\nexport interface CostEvent extends CostInfo {\n type: \"cost\";\n}\n\n/** Forward-compatibility: unrecognized event types are passed through. */\nexport interface UnknownEvent {\n type: string;\n [key: string]: unknown;\n}\n\nexport type StreamEvent =\n | AudioChunkEvent\n | TitleEvent\n | CompleteEvent\n | ErrorEvent\n | CostEvent\n | UnknownEvent;\n\nexport interface Track {\n audio: Uint8Array;\n title?: string;\n cost?: CostInfo;\n}\n\nexport interface TextToMusicParams {\n prompt: string;\n duration: number;\n segments?: Segment[];\n /** \"stream\" (default) or \"async\" (required by `submit()` and `output_format: \"wav\"`). */\n mode?: \"stream\" | \"async\";\n /** Container for the async result. `wav` requires `mode: \"async\"`. Defaults to m4a server-side. */\n outputFormat?: \"m4a\" | \"wav\";\n /** Bounds the stream: aborting this cancels the in-flight generation.\n * Passed straight through to `fetch` — it is never rewrapped as\n * RequestTimeoutError, since the client's own absolute timeout does not\n * apply to streaming music generation. */\n signal?: AbortSignal;\n}\n\n/** string = file path (Node.js only). */\nexport type VideoInput =\n | File\n | Blob\n | Uint8Array\n | ArrayBuffer\n | ReadableStream<Uint8Array>\n | string;\n\nexport interface VideoToMusicParams {\n video?: VideoInput;\n videoUrl?: string;\n prompt?: string;\n segments?: Segment[];\n /** Bounds the stream: aborting this cancels the in-flight generation.\n * Passed straight through to `fetch` — it is never rewrapped as\n * RequestTimeoutError, since the client's own absolute timeout does not\n * apply to streaming music generation. Only meaningful for `stream()`/\n * `generate()`; `submit()` ignores it. */\n signal?: AbortSignal;\n /** \"stream\" (the default, used by `stream()`/`generate()`) or \"async\"\n * (required for `submit()`, and for `isolateVocals`). Only consulted by\n * `submit()` — `stream()`/`generate()` always request a stream. */\n mode?: \"stream\" | \"async\";\n /** Split the generated track into a vocals-only stem alongside the mix.\n * Requires `mode: \"async\"`; if `mode` is left unset it defaults to\n * \"async\" automatically. Only usable via `submit()` — the backend\n * rejects it on the plain stream. */\n isolateVocals?: boolean;\n /** Keep the source speech/vocals in the async result. Current name for\n * `isolateVocals`; both are accepted and OR'd server-side. Requires\n * `mode: \"async\"` (auto-selected by `submit()`). */\n preserveSpeech?: boolean;\n /** Container for the async result. `wav` requires async. Defaults to m4a. */\n outputFormat?: \"m4a\" | \"wav\";\n /** Duck the generated music under the source voice at finalize time.\n * Default-ON server-side in async mode: leave unset to keep it on, pass\n * `false` to opt out. Free, best-effort; only valid on `submit()`. */\n ducking?: boolean;\n}\n\nexport interface TrialQuota {\n granted: number;\n used: number;\n remaining: number;\n}\n\nexport interface AccountServices {\n available_services: string[];\n rpm_limit: number;\n concurrency_limit: number;\n discount_factor: number | string;\n max_upload_size_mb: number | null;\n /** Free-trial allowance keyed by service. Returned only for self-serve\n * accounts; absent entirely for invoiced accounts. */\n trial?: Record<string, TrialQuota>;\n}\n\nexport interface UsageSummary {\n total_requests: number;\n total_duration_seconds: number;\n total_cost: number | string;\n period_start: string;\n period_end: string;\n [key: string]: unknown;\n}\n\nexport interface DailyUsage {\n date: string;\n requests: number;\n duration_seconds: number;\n cost: number | string;\n}\n\nexport interface UsageResponse {\n summary: UsageSummary;\n daily: DailyUsage[];\n}\n\nexport function isAudioChunkEvent(event: StreamEvent): event is AudioChunkEvent {\n return event.type === \"audio_chunk\" && (event as AudioChunkEvent).data instanceof Uint8Array;\n}\n\nexport function isErrorEvent(event: StreamEvent): event is ErrorEvent {\n return event.type === \"error\";\n}\n\n/** SFX segments (unlike music `Segment`) require `end`, must start at 0,\n * and be contiguous; validated server-side. */\nexport interface SfxSegment {\n start: number;\n end: number;\n prompt: string;\n}\n\nexport type SfxAudioFormat = \"wav\" | \"mp3\" | \"aac\" | \"flac\";\n\n/** Submission ack for the async SFX endpoints. */\nexport interface SfxTask {\n task_id: string;\n status: string;\n}\n\n/** A generated file re-hosted on R2 behind a presigned URL. */\nexport interface SfxMedia {\n url: string;\n content_type?: string;\n file_size?: number;\n}\n\nexport interface SfxError {\n code?: string;\n message?: string;\n}\n\n/**\n * Common shape of any polled task (`tasks.get`/`tasks.wait`), regardless of\n * which endpoint created it. `Tasks.get`/`Tasks.wait` are generic over this so\n * each endpoint's result type (e.g. `SfxResult`, `MusicTaskResult`) can add\n * its own `audio`/media fields while sharing the status/error/refund\n * bookkeeping the poller relies on.\n */\nexport interface BaseTaskResult {\n task_id: string;\n type?: string;\n status: \"processing\" | \"succeeded\" | \"failed\" | (string & {});\n /** Only present when the account's task-field whitelist enables cost. */\n cost?: number;\n error?: SfxError;\n refunded?: boolean;\n [key: string]: unknown;\n}\n\n/** State of an SFX task (`tasks.get`) or its final result (`wait`/`generate`). */\nexport interface SfxResult extends BaseTaskResult {\n audio?: SfxMedia;\n /** Kept for backward compatibility; no longer populated — video-to-sfx returns audio only. */\n video?: SfxMedia;\n}\n\nexport interface TextToSfxParams {\n prompt: string;\n duration: number;\n audioFormat?: SfxAudioFormat;\n}\n\nexport interface VideoToSfxParams {\n video?: VideoInput;\n videoUrl?: string;\n prompt?: string;\n segments?: SfxSegment[];\n audioFormat?: SfxAudioFormat;\n}\n\n/** One decoded audio stream of an async video-to-music result. Unlike SFX,\n * `audio` on a music task is always an array — even without `isolateVocals` —\n * since a music generation can carry more than one output stream. */\nexport interface MusicMediaEntry extends SfxMedia {\n stream_index: number;\n sample_rate?: number;\n channels?: number;\n}\n\n/** One muxed audio+video-aligned output, present only when `isolateVocals`\n * is set. */\nexport interface MusicMuxEntry extends SfxMedia {\n stream_index: number;\n}\n\nexport interface MusicTitle {\n title: string;\n summary?: string;\n display_tags?: string[];\n}\n\n/** State of an async video-to-music task (`tasks.get`) or its final result\n * (`tasks.wait<MusicTaskResult>()`). Only reachable via `videoToMusic.submit()`\n * with `mode: \"async\"`. */\nexport interface MusicTaskResult extends BaseTaskResult {\n audio?: MusicMediaEntry[];\n /** Vocals-only stem; present only when `isolateVocals` was requested. */\n vocals?: SfxMedia;\n /** Muxed output per stream; present only when `isolateVocals` was requested. */\n mux?: MusicMuxEntry[];\n /** Music ducked under the source voice; present only when `ducking` ran. */\n ducked?: MusicMediaEntry[];\n title?: MusicTitle;\n duration_seconds?: number;\n}\n\nexport interface WaitOptions {\n /** Milliseconds between polls. Default 2000. */\n pollInterval?: number;\n /** Overall deadline in milliseconds. Default 600000. */\n timeout?: number;\n}\n\n/** Result of an async video-to-video task (`videoToVideoMusic`/`videoToVideoSfx`):\n * a re-hosted video with generated music or SFX muxed in. */\nexport interface VideoResult extends BaseTaskResult {\n video?: SfxMedia;\n duration_seconds?: number;\n}\n\nexport interface VideoToVideoMusicParams {\n video?: VideoInput;\n videoUrl?: string;\n prompt?: string;\n /** Keep the source speech/vocals in the output. Both this and the legacy\n * `isolateVocals` are accepted and OR'd server-side. */\n preserveSpeech?: boolean;\n /** @deprecated Legacy alias for `preserveSpeech`. */\n isolateVocals?: boolean;\n}\n\nexport interface VideoToVideoSfxParams {\n video?: VideoInput;\n videoUrl?: string;\n prompt?: string;\n segments?: SfxSegment[];\n}\n\n/** Params for `videoToSound` and `videoToVideoSound`. Both endpoints take the\n * identical form, so they share one params type. */\nexport interface VideoToSoundParams {\n video?: VideoInput;\n videoUrl?: string;\n /** Style hint for the generated music bed. */\n musicPrompt?: string;\n /** Description of the sound effects layered over the music. */\n sfxPrompt?: string;\n /** Per-segment SFX descriptions; must start at 0 and be contiguous. */\n segments?: SfxSegment[];\n /** Keep the source speech in the result. */\n preserveSpeech?: boolean;\n /** Duck the generated music under the source speech. Default-ON\n * server-side: leave unset to keep it on, pass `false` to opt out. */\n ducking?: boolean;\n}\n\n/** Result of a `videoToSound` / `videoToVideoSound` task (`tasks.get`) or its\n * final state (`generate`).\n *\n * The combined music+SFX result is `output_url` — a bare presigned URL rather\n * than a media object, since these endpoints render one artifact whose kind is\n * announced by `output_type` (\"audio\" for video-to-sound, \"video\" for\n * video-to-video-sound). `music`, `music_processed` and `sfx` are the\n * individual stems; pass any of them, or `output_url` itself, to `download()`. */\nexport interface SoundResult extends BaseTaskResult {\n output_url?: string;\n output_type?: \"audio\" | \"video\";\n output_bytes?: number;\n music?: SfxMedia;\n /** Present only when `preserveSpeech`/`ducking` altered the music bed. */\n music_processed?: SfxMedia;\n sfx?: SfxMedia;\n duration_seconds?: number;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/resources/account.ts","../src/resources/tasks.ts","../src/streaming.ts","../src/resources/textToMusic.ts","../src/upload.ts","../src/resources/videoToMusic.ts","../src/resources/textToSfx.ts","../src/resources/videoToSfx.ts","../src/resources/videoToVideoMusic.ts","../src/resources/videoToVideoSfx.ts","../src/resources/soundForm.ts","../src/resources/videoToSound.ts","../src/resources/videoToVideoSound.ts","../src/resources/dubbing.ts","../src/version.ts","../src/client.ts","../src/download.ts","../src/types.ts"],"sourcesContent":["export class SoniloError extends Error {\n constructor(message: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\nexport class APIError extends SoniloError {\n readonly status: number;\n readonly body: unknown;\n /** The API's typed error code (e.g. \"rate_limit_exceeded\"), distinct from the HTTP status. */\n readonly code?: string;\n /** Per-field validation details, present on a 422. */\n readonly errors?: unknown[];\n\n constructor(message: string, status: number, body?: unknown) {\n super(message);\n this.status = status;\n this.body = body;\n const parsed = body as { code?: unknown; errors?: unknown } | undefined;\n this.code = typeof parsed?.code === \"string\" ? parsed.code : undefined;\n this.errors = Array.isArray(parsed?.errors) ? parsed.errors : undefined;\n }\n}\n\nexport class AuthenticationError extends APIError {}\n\nexport class PaymentRequiredError extends APIError {}\n\n/** The account's free trial for this service is spent and it has never been\n * funded — the caller should add a payment method rather than retry. A\n * subclass of `PaymentRequiredError`, so code that already catches every 402\n * keeps working; catch this first to tell \"you haven't paid us yet\" apart\n * from a funded wallet that ran dry (`PaymentRequiredError` with\n * `code === \"insufficient_balance\"`). */\nexport class TrialExhaustedError extends PaymentRequiredError {}\n\nexport class BadRequestError extends APIError {\n get detail(): string | undefined {\n const body = this.body as { message?: unknown; detail?: unknown } | undefined;\n if (typeof body?.message === \"string\" && body.message) {\n return body.message;\n }\n return typeof body?.detail === \"string\" ? body.detail : undefined;\n }\n}\n\nexport class RateLimitError extends APIError {\n readonly retryAfter?: number;\n\n constructor(message: string, status: number, body?: unknown, retryAfter?: number) {\n super(message, status, body);\n this.retryAfter = retryAfter;\n }\n}\n\n/** Raised by generate() when an `error` event arrives mid-stream. */\nexport class GenerationError extends SoniloError {\n readonly code?: string;\n\n constructor(message: string, code?: string) {\n super(message);\n this.code = code;\n }\n}\n\n/** Raised by tasks.wait()/generate() when an SFX task reaches `failed`. */\nexport class TaskFailedError extends SoniloError {\n readonly code?: string;\n readonly taskId: string;\n readonly refunded?: boolean;\n\n constructor(\n message: string,\n opts: { code?: string; taskId: string; refunded?: boolean },\n ) {\n super(message);\n this.code = opts.code;\n this.taskId = opts.taskId;\n this.refunded = opts.refunded;\n }\n}\n\n/** Poll deadline passed. The task may still finish server-side — resume with\n * tasks.wait(taskId) or tasks.get(taskId). */\nexport class TaskTimeoutError extends SoniloError {\n readonly taskId: string;\n\n constructor(message: string, taskId: string) {\n super(message);\n this.taskId = taskId;\n }\n}\n\n/** Raised when a one-shot request or download is aborted by its own timeout\n * signal (as opposed to a caller-supplied AbortSignal, which propagates\n * untouched). */\nexport class RequestTimeoutError extends SoniloError {}\n\n/**\n * True if `err` is the rejection produced when an `AbortSignal.timeout()`\n * we created fires. Used to distinguish \"our\" timeout aborts (which should be\n * rethrown as `RequestTimeoutError`) from a caller-supplied signal's abort\n * (which must propagate untouched).\n */\nexport function isTimeoutSignalError(err: unknown): boolean {\n return err instanceof Error && (err.name === \"TimeoutError\" || err.name === \"AbortError\");\n}\n\nexport async function errorFromResponse(res: Response): Promise<APIError> {\n const text = await res.text().catch(() => \"\");\n let body: unknown = text;\n try {\n body = JSON.parse(text);\n } catch {\n // keep raw text\n }\n const parsed = body as { message?: unknown; detail?: unknown } | undefined;\n const rawMessage = typeof parsed?.message === \"string\" && parsed.message ? parsed.message : undefined;\n const rawDetail = parsed?.detail;\n const isDetailAbsent = rawDetail === undefined || rawDetail === null || rawDetail === \"\";\n let reason: string;\n if (rawMessage !== undefined) {\n reason = rawMessage;\n } else if (isDetailAbsent) {\n reason = res.statusText || \"request failed\";\n } else if (typeof rawDetail === \"string\") {\n reason = rawDetail;\n } else {\n try {\n reason = JSON.stringify(rawDetail);\n } catch {\n reason = res.statusText || \"request failed\";\n }\n }\n const message = `HTTP ${res.status}: ${reason}`;\n\n switch (res.status) {\n case 401:\n return new AuthenticationError(message, res.status, body);\n case 402: {\n // Branch on the API's `code`, never on the message text — the wording\n // is product copy and changes; the code is the contract.\n const code = (body as { code?: unknown } | undefined)?.code;\n if (code === \"trial_exhausted\") {\n return new TrialExhaustedError(message, res.status, body);\n }\n return new PaymentRequiredError(message, res.status, body);\n }\n case 429: {\n const ra = res.headers.get(\"retry-after\");\n const retryAfter = ra !== null && ra !== \"\" && !Number.isNaN(Number(ra)) ? Number(ra) : undefined;\n return new RateLimitError(message, res.status, body, retryAfter);\n }\n case 400:\n case 413:\n case 422:\n return new BadRequestError(message, res.status, body);\n default:\n return new APIError(message, res.status, body);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport type { AccountServices, UsageResponse } from \"../types.js\";\n\nexport class Account {\n constructor(private readonly client: SoniloClient) {}\n\n async services(): Promise<AccountServices> {\n const res = await this.client.request(\"/v1/account/services\");\n return (await res.json()) as AccountServices;\n }\n\n async usage(params: { days?: number } = {}): Promise<UsageResponse> {\n const query = params.days !== undefined ? `?days=${params.days}` : \"\";\n const res = await this.client.request(`/v1/account/usage${query}`);\n return (await res.json()) as UsageResponse;\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError, TaskFailedError, TaskTimeoutError } from \"../errors.js\";\nimport type { BaseTaskResult, SfxResult, WaitOptions } from \"../types.js\";\n\nexport const DEFAULT_POLL_INTERVAL_MS = 2000;\nexport const DEFAULT_WAIT_TIMEOUT_MS = 600_000;\n\nconst sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));\n\n/** A negative delay is clamped to 0 by setTimeout, which would turn the poll\n * loop into a busy loop hammering the API until the deadline. */\nfunction validateWaitArgs(pollInterval: number, timeout: number): void {\n if (pollInterval < 0) {\n throw new SoniloError(`pollInterval must be >= 0, got ${pollInterval}`);\n }\n if (timeout < 0) {\n throw new SoniloError(`timeout must be >= 0, got ${timeout}`);\n }\n}\n\nexport class Tasks {\n constructor(private readonly client: SoniloClient) {}\n\n /**\n * Fetch current task state. Never throws on a failed status.\n *\n * Generic over the result shape so callers can request the endpoint-\n * specific type, e.g. `client.tasks.get<MusicTaskResult>(taskId)`.\n * Defaults to `SfxResult` for back-compat.\n */\n async get<T extends BaseTaskResult = SfxResult>(taskId: string): Promise<T> {\n const res = await this.client.request(`/v1/tasks/${encodeURIComponent(taskId)}`);\n return (await res.json()) as T;\n }\n\n /**\n * Poll until the task is terminal; throw on failure or deadline.\n *\n * Generic over the result shape, e.g.\n * `client.tasks.wait<MusicTaskResult>(taskId)`. Defaults to `SfxResult`\n * for back-compat.\n */\n async wait<T extends BaseTaskResult = SfxResult>(\n taskId: string,\n opts: WaitOptions = {},\n ): Promise<T> {\n const pollInterval = opts.pollInterval ?? DEFAULT_POLL_INTERVAL_MS;\n const timeout = opts.timeout ?? DEFAULT_WAIT_TIMEOUT_MS;\n validateWaitArgs(pollInterval, timeout);\n const deadline = performance.now() + timeout;\n for (;;) {\n const result = await this.get<T>(taskId);\n if (result.status === \"succeeded\") return result;\n if (result.status === \"failed\") {\n const message = result.error?.message || \"Generation failed\";\n throw new TaskFailedError(`Task ${taskId} failed: ${message}`, {\n code: result.error?.code,\n taskId,\n refunded: result.refunded,\n });\n }\n const remaining = deadline - performance.now();\n if (remaining <= 0) {\n throw new TaskTimeoutError(\n `Task ${taskId} still processing after ${timeout}ms; ` +\n \"it may finish later — resume with tasks.wait or tasks.get\",\n taskId,\n );\n }\n await sleep(Math.min(pollInterval, remaining));\n }\n }\n}\n","import { GenerationError } from \"./errors.js\";\nimport type { CostInfo, StreamEvent, Track } from \"./types.js\";\n\nexport function decodeBase64(b64: string): Uint8Array {\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n}\n\n/** Returns `null` for a valid-JSON-but-non-object line (e.g. a bare `null`\n * or a number/string), which carries no event `type` and is skipped like any\n * other junk line rather than crashing on a `.type` read off `null`. */\nfunction toEvent(line: string): StreamEvent | null {\n const parsed: unknown = JSON.parse(line);\n if (typeof parsed !== \"object\" || parsed === null) return null;\n const raw = parsed as { type: string; [key: string]: unknown };\n if (raw.type === \"audio_chunk\" && typeof raw.data === \"string\") {\n try {\n return { ...raw, type: \"audio_chunk\", data: decodeBase64(raw.data) };\n } catch {\n // Don't raise here: this must reach collectTrack's malformed-chunk\n // check, which turns undecodable data into a typed GenerationError.\n // Raising in place would let a raw DOMException escape\n // stream()/generate(), breaking the SDK's \"all errors extend\n // SoniloError\" contract.\n }\n }\n return raw as StreamEvent;\n}\n\nexport async function* parseNdjson(\n body: ReadableStream<Uint8Array>,\n): AsyncGenerator<StreamEvent, void, undefined> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n let nl: number;\n while ((nl = buffer.indexOf(\"\\n\")) !== -1) {\n const line = buffer.slice(0, nl).trim();\n buffer = buffer.slice(nl + 1);\n if (line) {\n const ev = toEvent(line);\n if (ev !== null) yield ev;\n }\n }\n }\n buffer += decoder.decode();\n const tail = buffer.trim();\n if (tail) {\n const ev = toEvent(tail);\n if (ev !== null) yield ev;\n }\n } finally {\n await reader.cancel().catch(() => {});\n }\n}\n\nexport async function collectTrack(events: AsyncIterable<StreamEvent>): Promise<Track> {\n const chunks: Uint8Array[] = [];\n let title: string | undefined;\n let cost: CostInfo | undefined;\n let sawComplete = false;\n\n for await (const ev of events) {\n if (ev.type === \"audio_chunk\") {\n // A malformed chunk (missing/non-decodable `data`) must not be\n // silently dropped: that would hand back a \"successful\" Track with\n // empty or truncated audio and no indication anything went wrong.\n if (!(ev.data instanceof Uint8Array)) {\n throw new GenerationError(\n \"received a malformed audio_chunk event (missing or non-decodable data)\",\n );\n }\n chunks.push(ev.data);\n } else if (ev.type === \"title\" && typeof ev.title === \"string\") {\n title = ev.title;\n } else if (ev.type === \"cost\") {\n const { type: _type, ...rest } = ev;\n cost = rest as CostInfo;\n } else if (ev.type === \"error\") {\n const message = typeof ev.message === \"string\" && ev.message !== \"\" ? ev.message : \"generation failed\";\n const code = typeof ev.code === \"string\" ? ev.code : undefined;\n throw new GenerationError(message, code);\n } else if (ev.type === \"complete\") {\n sawComplete = true;\n }\n // unknown event types: ignored\n }\n\n if (!sawComplete) {\n throw new GenerationError(\"stream ended before a 'complete' event (truncated response)\");\n }\n\n const total = chunks.reduce((n, c) => n + c.length, 0);\n const audio = new Uint8Array(total);\n let offset = 0;\n for (const c of chunks) {\n audio.set(c, offset);\n offset += c.length;\n }\n return { audio, title, cost };\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { collectTrack, parseNdjson } from \"../streaming.js\";\nimport type { SfxTask, StreamEvent, TextToMusicParams, Track } from \"../types.js\";\n\nexport class TextToMusic {\n constructor(private readonly client: SoniloClient) {}\n\n /** Stream raw generation events (audio chunks pre-decoded to bytes). */\n async *stream(params: TextToMusicParams): AsyncGenerator<StreamEvent, void, undefined> {\n const form = new FormData();\n form.set(\"prompt\", params.prompt);\n form.set(\"duration\", String(params.duration));\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n // Opt out of the client's absolute request timeout: this holds the\n // response body open and reads NDJSON chunks for as long as generation\n // takes, so an AbortSignal keyed to elapsed time would kill a healthy,\n // still-streaming, long-duration track. Pass `params.signal` yourself to\n // bound or cancel the stream instead — it is forwarded to `fetch` as-is.\n const res = await this.client.request(\n \"/v1/text-to-music\",\n { method: \"POST\", body: form, signal: params.signal },\n { timeout: null },\n );\n if (!res.body) throw new SoniloError(\"Response has no body\");\n yield* parseNdjson(res.body);\n }\n\n /** Generate and buffer the whole track; throws GenerationError on stream errors. */\n generate(params: TextToMusicParams): Promise<Track> {\n return collectTrack(this.stream(params));\n }\n\n /**\n * Submit an async text-to-music task; poll with\n * `client.tasks.wait<MusicTaskResult>(task.task_id)`. Required for\n * `outputFormat: \"wav\"`. `stream()`/`generate()` remain the streaming path.\n */\n async submit(params: TextToMusicParams): Promise<SfxTask> {\n const mode = params.mode ?? \"async\";\n if (mode !== \"async\") {\n throw new SoniloError('submit() requires mode: \"async\"');\n }\n const form = new FormData();\n form.set(\"prompt\", params.prompt);\n form.set(\"duration\", String(params.duration));\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n form.set(\"mode\", mode);\n if (params.outputFormat !== undefined) {\n form.set(\"output_format\", params.outputFormat);\n }\n const res = await this.client.request(\"/v1/text-to-music\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n}\n","import { SoniloError } from \"./errors.js\";\nimport type { VideoInput } from \"./types.js\";\n\nconst DEFAULT_FILENAME = \"video.mp4\";\n\n/**\n * Normalize every accepted video input into a FormData-ready Blob.\n * String inputs are file paths and work only in Node.js; browsers must\n * pass File/Blob/bytes/streams.\n */\nexport async function toUploadBlob(\n video: VideoInput,\n): Promise<{ blob: Blob; filename: string }> {\n if (typeof video === \"string\") {\n const isNode =\n typeof process !== \"undefined\" && Boolean((process as { versions?: { node?: string } }).versions?.node);\n if (!isNode) {\n throw new SoniloError(\n \"File paths are only supported in Node.js; pass a File or Blob in the browser\",\n );\n }\n const fsModule = \"node:fs/promises\";\n const { readFile } = (await import(\n /* webpackIgnore: true */ /* @vite-ignore */ fsModule\n )) as typeof import(\"node:fs/promises\");\n const data = await readFile(video);\n const filename = video.split(/[\\\\/]/).pop() || DEFAULT_FILENAME;\n return { blob: new Blob([data]), filename };\n }\n if (typeof File !== \"undefined\" && video instanceof File) {\n return { blob: video, filename: video.name || DEFAULT_FILENAME };\n }\n if (video instanceof Blob) {\n return { blob: video, filename: DEFAULT_FILENAME };\n }\n if (video instanceof Uint8Array) {\n return { blob: new Blob([video as unknown as BlobPart]), filename: DEFAULT_FILENAME };\n }\n if (video instanceof ArrayBuffer) {\n return { blob: new Blob([video]), filename: DEFAULT_FILENAME };\n }\n if (video instanceof ReadableStream) {\n return { blob: await new Response(video).blob(), filename: DEFAULT_FILENAME };\n }\n throw new SoniloError(\"Unsupported video input type\");\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { collectTrack, parseNdjson } from \"../streaming.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { SfxTask, StreamEvent, Track, VideoToMusicParams } from \"../types.js\";\n\nexport class VideoToMusic {\n constructor(private readonly client: SoniloClient) {}\n\n async *stream(params: VideoToMusicParams): AsyncGenerator<StreamEvent, void, undefined> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n // Opt out of the client's absolute request timeout: this holds the\n // response body open and reads NDJSON chunks for as long as generation\n // takes, so an AbortSignal keyed to elapsed time would kill a healthy,\n // still-streaming request (e.g. a slow video upload or long track). Pass\n // `params.signal` yourself to bound or cancel the stream instead — it is\n // forwarded to `fetch` as-is.\n const res = await this.client.request(\n \"/v1/video-to-music\",\n { method: \"POST\", body: form, signal: params.signal },\n { timeout: null },\n );\n if (!res.body) throw new SoniloError(\"Response has no body\");\n yield* parseNdjson(res.body);\n }\n\n generate(params: VideoToMusicParams): Promise<Track> {\n return collectTrack(this.stream(params));\n }\n\n /**\n * Submit an async video-to-music task; poll its result with\n * `client.tasks.wait<MusicTaskResult>(task.task_id)`. Required for\n * `isolateVocals` — the backend rejects vocal isolation on the plain\n * stream, and it only ever runs in async mode.\n */\n async submit(params: VideoToMusicParams): Promise<SfxTask> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n let mode = params.mode;\n const needsAsync =\n params.isolateVocals ||\n params.preserveSpeech ||\n params.ducking !== undefined ||\n params.outputFormat === \"wav\";\n // submit() always wants an async task ack, never a stream. Default to\n // async; only object if the caller explicitly asked for stream while\n // also requesting an async-only feature.\n if (mode === undefined) mode = \"async\";\n if (needsAsync && mode !== \"async\") {\n throw new SoniloError(\n 'isolateVocals/preserveSpeech/ducking/outputFormat \"wav\" require mode: \"async\"',\n );\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n form.set(\"mode\", mode);\n if (params.preserveSpeech !== undefined) {\n form.set(\"preserve_speech\", String(params.preserveSpeech));\n }\n if (params.isolateVocals !== undefined) {\n form.set(\"isolate_vocals\", String(params.isolateVocals));\n }\n if (params.outputFormat !== undefined) {\n form.set(\"output_format\", params.outputFormat);\n }\n if (params.ducking !== undefined) {\n form.set(\"ducking\", String(params.ducking));\n }\n const res = await this.client.request(\"/v1/video-to-music\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport type { SfxResult, SfxTask, TextToSfxParams, WaitOptions } from \"../types.js\";\n\nexport class TextToSfx {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: TextToSfxParams): Promise<SfxTask> {\n const form = new FormData();\n form.set(\"prompt\", params.prompt);\n form.set(\"duration\", String(params.duration));\n if (params.audioFormat !== undefined) form.set(\"audio_format\", params.audioFormat);\n const res = await this.client.request(\"/v1/text-to-sfx\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: TextToSfxParams, opts?: WaitOptions): Promise<SfxResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait(task.task_id, opts);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { SfxResult, SfxTask, VideoToSfxParams, WaitOptions } from \"../types.js\";\n\nexport class VideoToSfx {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToSfxParams): Promise<SfxTask> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n if (params.audioFormat !== undefined) form.set(\"audio_format\", params.audioFormat);\n const res = await this.client.request(\"/v1/video-to-sfx\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToSfxParams, opts?: WaitOptions): Promise<SfxResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait(task.task_id, opts);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { SfxTask, VideoResult, VideoToVideoMusicParams, WaitOptions } from \"../types.js\";\n\n/** Generate an original score for a video and get back a re-hosted video with\n * the music muxed in. Async only: `submit()` returns a task ack; poll with\n * `client.tasks.wait<VideoResult>(id)`, or use `generate()` to do both. */\nexport class VideoToVideoMusic {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToVideoMusicParams): Promise<SfxTask> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.preserveSpeech !== undefined) {\n form.set(\"preserve_speech\", String(params.preserveSpeech));\n }\n if (params.isolateVocals !== undefined) {\n form.set(\"isolate_vocals\", String(params.isolateVocals));\n }\n const res = await this.client.request(\"/v1/video-to-video-music\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToVideoMusicParams, opts?: WaitOptions): Promise<VideoResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait<VideoResult>(task.task_id, opts);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { SfxTask, VideoResult, VideoToVideoSfxParams, WaitOptions } from \"../types.js\";\n\n/** Generate sound effects for a video and get back a re-hosted video with the\n * SFX muxed in. Async only. */\nexport class VideoToVideoSfx {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToVideoSfxParams): Promise<SfxTask> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.prompt !== undefined) form.set(\"prompt\", params.prompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n const res = await this.client.request(\"/v1/video-to-video-sfx\", {\n method: \"POST\",\n body: form,\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToVideoSfxParams, opts?: WaitOptions): Promise<VideoResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait<VideoResult>(task.task_id, opts);\n }\n}\n","import { SoniloError } from \"../errors.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { VideoToSoundParams } from \"../types.js\";\n\n/** Build the multipart body shared by /v1/video-to-sound and\n * /v1/video-to-video-sound — their form fields are identical, so the two\n * resources differ only in the path they POST to.\n *\n * Every optional field is omitted when unset rather than sent with a default:\n * `ducking` in particular is default-ON server-side, so an unset value must\n * not become an explicit \"false\" on the wire. */\nexport async function buildSoundForm(params: VideoToSoundParams): Promise<FormData> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n form.set(\"video_url\", params.videoUrl as string);\n }\n if (params.musicPrompt !== undefined) form.set(\"music_prompt\", params.musicPrompt);\n if (params.sfxPrompt !== undefined) form.set(\"sfx_prompt\", params.sfxPrompt);\n if (params.segments !== undefined) {\n form.set(\"segments\", JSON.stringify(params.segments));\n }\n if (params.preserveSpeech !== undefined) {\n form.set(\"preserve_speech\", String(params.preserveSpeech));\n }\n if (params.ducking !== undefined) form.set(\"ducking\", String(params.ducking));\n return form;\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { buildSoundForm } from \"./soundForm.js\";\nimport type { SfxTask, SoundResult, VideoToSoundParams, WaitOptions } from \"../types.js\";\n\n/** Generate a combined music + sound-effects track for a video and get back\n * the mixed audio. Async only. */\nexport class VideoToSound {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToSoundParams): Promise<SfxTask> {\n const res = await this.client.request(\"/v1/video-to-sound\", {\n method: \"POST\",\n body: await buildSoundForm(params),\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToSoundParams, opts?: WaitOptions): Promise<SoundResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait<SoundResult>(task.task_id, opts);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { buildSoundForm } from \"./soundForm.js\";\nimport type { SfxTask, SoundResult, VideoToSoundParams, WaitOptions } from \"../types.js\";\n\n/** Generate a combined music + sound-effects track for a video and get back a\n * re-hosted video with that track muxed in. Async only. */\nexport class VideoToVideoSound {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: VideoToSoundParams): Promise<SfxTask> {\n const res = await this.client.request(\"/v1/video-to-video-sound\", {\n method: \"POST\",\n body: await buildSoundForm(params),\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: VideoToSoundParams, opts?: WaitOptions): Promise<SoundResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait<SoundResult>(task.task_id, opts);\n }\n}\n","import type { SoniloClient } from \"../client.js\";\nimport { SoniloError } from \"../errors.js\";\nimport { toUploadBlob } from \"../upload.js\";\nimport type { DubbingParams, DubbingResult, SfxTask, WaitOptions } from \"../types.js\";\n\n/** Build the multipart body for /v1/dubbing.\n *\n * `languages` travels as one opaque form field holding a JSON array string —\n * that is the shape the backend parses. It is omitted entirely when unset so\n * the server default ([\"zh_cn\", \"es\", \"fr\"]) applies; sending an empty array\n * instead would be rejected as a malformed payload.\n *\n * The https check is local because it is a guaranteed server-side 422: the\n * dubbing pipeline fetches the source URL itself and requires https\n * specifically, unlike the fal-backed endpoints, which accept plain http.\n * Language codes are deliberately NOT checked here — the backend owns that\n * list, and a hardcoded copy would make this SDK reject codes added later. */\nexport async function buildDubbingForm(params: DubbingParams): Promise<FormData> {\n if ((params.video === undefined) === (params.videoUrl === undefined)) {\n throw new SoniloError(\"Provide exactly one of video or videoUrl\");\n }\n const form = new FormData();\n if (params.video !== undefined) {\n const { blob, filename } = await toUploadBlob(params.video);\n form.set(\"video\", blob, filename);\n } else {\n const url = params.videoUrl as string;\n if (!url.toLowerCase().startsWith(\"https://\")) {\n throw new SoniloError(\n \"videoUrl must use https — the dubbing pipeline requires an https URL\",\n );\n }\n form.set(\"video_url\", url);\n }\n if (params.languages !== undefined) {\n form.set(\"languages\", JSON.stringify(params.languages));\n }\n return form;\n}\n\n/** Dub a video into one or more target languages. Async only; the result\n * carries a language → dubbed-video-URL map under `outputs`. */\nexport class Dubbing {\n constructor(private readonly client: SoniloClient) {}\n\n async submit(params: DubbingParams): Promise<SfxTask> {\n const res = await this.client.request(\"/v1/dubbing\", {\n method: \"POST\",\n body: await buildDubbingForm(params),\n });\n return (await res.json()) as SfxTask;\n }\n\n async generate(params: DubbingParams, opts?: WaitOptions): Promise<DubbingResult> {\n const task = await this.submit(params);\n return this.client.tasks.wait<DubbingResult>(task.task_id, opts);\n }\n}\n","/** The SDK's own version. Generated by scripts/sync-versions.mjs — do not edit. */\nexport const VERSION = \"0.7.0\";\n","import { RequestTimeoutError, SoniloError, errorFromResponse, isTimeoutSignalError } from \"./errors.js\";\nimport { Account } from \"./resources/account.js\";\nimport { Tasks } from \"./resources/tasks.js\";\nimport { TextToMusic } from \"./resources/textToMusic.js\";\nimport { VideoToMusic } from \"./resources/videoToMusic.js\";\nimport { TextToSfx } from \"./resources/textToSfx.js\";\nimport { VideoToSfx } from \"./resources/videoToSfx.js\";\nimport { VideoToVideoMusic } from \"./resources/videoToVideoMusic.js\";\nimport { VideoToVideoSfx } from \"./resources/videoToVideoSfx.js\";\nimport { VideoToSound } from \"./resources/videoToSound.js\";\nimport { VideoToVideoSound } from \"./resources/videoToVideoSound.js\";\nimport { Dubbing } from \"./resources/dubbing.js\";\nimport { VERSION } from \"./version.js\";\n\nexport interface SoniloClientOptions {\n /** Defaults to the SONILO_API_KEY environment variable (Node.js only). */\n apiKey?: string;\n /** Defaults to https://api.sonilo.com */\n baseUrl?: string;\n /** Injection point for tests and custom transports. */\n fetch?: typeof globalThis.fetch;\n /** Milliseconds before an in-flight request is aborted. Default 600000. */\n timeout?: number;\n /**\n * Identifies a wrapper built on this SDK (the CLI, the video kit) in the\n * `X-Sonilo-Client` header. Leave unset for direct SDK use — without an\n * override a wrapper's traffic is indistinguishable from the SDK's own.\n */\n clientName?: string;\n /** Version reported alongside `clientName`. Defaults to the SDK's version. */\n clientVersion?: string;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.sonilo.com\";\n\n/**\n * Reported in `X-Sonilo-Client` unless a wrapper overrides it. First-party\n * wrappers (the CLI, the video kit) pass their own name so their traffic stays\n * distinguishable from direct SDK use in server-side analytics.\n */\nexport const DEFAULT_CLIENT_NAME = \"sdk-js\";\n\n/** Milliseconds before an in-flight request is aborted, unless overridden. */\nexport const DEFAULT_TIMEOUT_MS = 600_000;\n\nexport class SoniloClient {\n readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly fetchFn: typeof globalThis.fetch;\n private readonly timeout: number;\n private readonly clientName: string;\n private readonly clientVersion: string;\n readonly account: Account;\n readonly tasks: Tasks;\n readonly textToMusic: TextToMusic;\n readonly videoToMusic: VideoToMusic;\n readonly textToSfx: TextToSfx;\n readonly videoToSfx: VideoToSfx;\n readonly videoToVideoMusic: VideoToVideoMusic;\n readonly videoToVideoSfx: VideoToVideoSfx;\n readonly videoToSound: VideoToSound;\n readonly videoToVideoSound: VideoToVideoSound;\n readonly dubbing: Dubbing;\n\n constructor(options: SoniloClientOptions = {}) {\n const envKey =\n typeof process !== \"undefined\" ? process.env?.SONILO_API_KEY : undefined;\n const apiKey = options.apiKey ?? envKey;\n if (!apiKey) {\n throw new SoniloError(\n \"Missing API key: pass { apiKey } or set the SONILO_API_KEY environment variable\",\n );\n }\n this.apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.fetchFn = (options.fetch ?? globalThis.fetch).bind(globalThis);\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;\n this.clientName = options.clientName ?? DEFAULT_CLIENT_NAME;\n this.clientVersion = options.clientVersion ?? VERSION;\n this.account = new Account(this);\n this.tasks = new Tasks(this);\n this.textToMusic = new TextToMusic(this);\n this.videoToMusic = new VideoToMusic(this);\n this.textToSfx = new TextToSfx(this);\n this.videoToSfx = new VideoToSfx(this);\n this.videoToVideoMusic = new VideoToVideoMusic(this);\n this.videoToVideoSfx = new VideoToVideoSfx(this);\n this.videoToSound = new VideoToSound(this);\n this.videoToVideoSound = new VideoToVideoSound(this);\n this.dubbing = new Dubbing(this);\n }\n\n /**\n * Perform an authenticated request; throws a typed error on non-2xx.\n *\n * `opts.timeout` overrides the client's default timeout for this call;\n * pass `null` to disable the abort-on-timeout behavior entirely (used by\n * the streaming music endpoints — see textToMusic.ts / videoToMusic.ts).\n * A caller-supplied `init.signal` always wins over any timeout signal.\n */\n async request(\n path: string,\n init: RequestInit = {},\n opts: { timeout?: number | null } = {},\n ): Promise<Response> {\n const headers = new Headers(init.headers);\n headers.set(\"Authorization\", `Bearer ${this.apiKey}`);\n headers.set(\"X-Sonilo-Client\", this.clientName);\n headers.set(\"X-Sonilo-Client-Version\", this.clientVersion);\n const timeout = opts.timeout === undefined ? this.timeout : opts.timeout;\n // We only \"own\" the signal (and may later rewrap its abort as a\n // RequestTimeoutError) when the caller didn't supply one and a timeout\n // is actually enabled.\n const ownsSignal = init.signal == null && timeout !== null;\n const signal = init.signal ?? (timeout === null ? undefined : AbortSignal.timeout(timeout));\n try {\n const res = await this.fetchFn(`${this.baseUrl}${path}`, { ...init, headers, signal });\n if (!res.ok) throw await errorFromResponse(res);\n return res;\n } catch (err) {\n if (ownsSignal && isTimeoutSignalError(err)) {\n throw new RequestTimeoutError(`Request to ${path} timed out after ${timeout}ms`);\n }\n throw err;\n }\n }\n}\n","import { DEFAULT_TIMEOUT_MS } from \"./client.js\";\nimport { RequestTimeoutError, SoniloError, isTimeoutSignalError } from \"./errors.js\";\nimport type { SfxMedia } from \"./types.js\";\n\n/** Fetch a result media file. The URL is presigned — no API key is sent.\n *\n * Accepts either a media object (`result.audio`, `result.music`, …) or a bare\n * URL string, which is what the combined video-to-sound endpoints return as\n * `output_url`. */\nexport async function download(\n media: SfxMedia | string | undefined,\n fetchFn: typeof globalThis.fetch = globalThis.fetch,\n timeout: number = DEFAULT_TIMEOUT_MS,\n): Promise<Uint8Array> {\n const url = typeof media === \"string\" ? media : media?.url;\n if (!url) {\n throw new SoniloError(\"No media to download\");\n }\n let res: Response;\n try {\n res = await fetchFn(url, { signal: AbortSignal.timeout(timeout) });\n } catch (err) {\n if (isTimeoutSignalError(err)) {\n throw new RequestTimeoutError(`Download of ${url} timed out after ${timeout}ms`);\n }\n throw err;\n }\n if (!res.ok) {\n throw new SoniloError(`Download failed: HTTP ${res.status}`);\n }\n return new Uint8Array(await res.arrayBuffer());\n}\n","export type SegmentLabel =\n | \"intro\"\n | \"verse\"\n | \"pre-chorus\"\n | \"chorus\"\n | \"bridge\"\n | \"break\"\n | \"silence\"\n | \"outro\"\n | \"none\";\n\nexport interface Segment {\n start: number;\n prompt: string;\n label?: SegmentLabel;\n}\n\n/** Monetary fields are strings, exactly as the backend serializes them. */\nexport interface CostInfo {\n billing_rate_per_sec: string;\n billing_before_discount: string;\n billing_after_discount: string;\n discount_factor: string;\n}\n\nexport interface AudioChunkEvent {\n type: \"audio_chunk\";\n /** Decoded from the wire's base64 by the SDK. */\n data: Uint8Array;\n}\n\nexport interface TitleEvent {\n type: \"title\";\n title: string;\n summary?: string;\n display_tags?: string[];\n [key: string]: unknown;\n}\n\nexport interface CompleteEvent {\n type: \"complete\";\n [key: string]: unknown;\n}\n\nexport interface ErrorEvent {\n type: \"error\";\n code?: string;\n message?: string;\n [key: string]: unknown;\n}\n\nexport interface CostEvent extends CostInfo {\n type: \"cost\";\n}\n\n/** Forward-compatibility: unrecognized event types are passed through. */\nexport interface UnknownEvent {\n type: string;\n [key: string]: unknown;\n}\n\nexport type StreamEvent =\n | AudioChunkEvent\n | TitleEvent\n | CompleteEvent\n | ErrorEvent\n | CostEvent\n | UnknownEvent;\n\nexport interface Track {\n audio: Uint8Array;\n title?: string;\n cost?: CostInfo;\n}\n\nexport interface TextToMusicParams {\n prompt: string;\n duration: number;\n segments?: Segment[];\n /** \"stream\" (default) or \"async\" (required by `submit()` and `output_format: \"wav\"`). */\n mode?: \"stream\" | \"async\";\n /** Container for the async result. `wav` requires `mode: \"async\"`. Defaults to m4a server-side. */\n outputFormat?: \"m4a\" | \"wav\";\n /** Bounds the stream: aborting this cancels the in-flight generation.\n * Passed straight through to `fetch` — it is never rewrapped as\n * RequestTimeoutError, since the client's own absolute timeout does not\n * apply to streaming music generation. */\n signal?: AbortSignal;\n}\n\n/** string = file path (Node.js only). */\nexport type VideoInput =\n | File\n | Blob\n | Uint8Array\n | ArrayBuffer\n | ReadableStream<Uint8Array>\n | string;\n\nexport interface VideoToMusicParams {\n video?: VideoInput;\n videoUrl?: string;\n prompt?: string;\n segments?: Segment[];\n /** Bounds the stream: aborting this cancels the in-flight generation.\n * Passed straight through to `fetch` — it is never rewrapped as\n * RequestTimeoutError, since the client's own absolute timeout does not\n * apply to streaming music generation. Only meaningful for `stream()`/\n * `generate()`; `submit()` ignores it. */\n signal?: AbortSignal;\n /** \"stream\" (the default, used by `stream()`/`generate()`) or \"async\"\n * (required for `submit()`, and for `isolateVocals`). Only consulted by\n * `submit()` — `stream()`/`generate()` always request a stream. */\n mode?: \"stream\" | \"async\";\n /** Split the generated track into a vocals-only stem alongside the mix.\n * Requires `mode: \"async\"`; if `mode` is left unset it defaults to\n * \"async\" automatically. Only usable via `submit()` — the backend\n * rejects it on the plain stream. */\n isolateVocals?: boolean;\n /** Keep the source speech/vocals in the async result. Current name for\n * `isolateVocals`; both are accepted and OR'd server-side. Requires\n * `mode: \"async\"` (auto-selected by `submit()`). */\n preserveSpeech?: boolean;\n /** Container for the async result. `wav` requires async. Defaults to m4a. */\n outputFormat?: \"m4a\" | \"wav\";\n /** Duck the generated music under the source voice at finalize time.\n * Default-ON server-side in async mode: leave unset to keep it on, pass\n * `false` to opt out. Free, best-effort; only valid on `submit()`. */\n ducking?: boolean;\n}\n\n/** One service's free-trial allowance. `remaining` is already floored at 0,\n * so it is safe to compare directly. */\nexport interface TrialQuota {\n granted: number;\n used: number;\n remaining: number;\n}\n\nexport interface AccountServices {\n available_services: string[];\n rpm_limit: number;\n concurrency_limit: number;\n discount_factor: number | string;\n max_upload_size_mb: number | null;\n /** Free-trial allowance keyed by service (`granted` / `used` /\n * `remaining`). Present only for self-serve accounts — always treat it as\n * possibly absent, and treat a service missing from the map as \"no trial\n * allowance\", not as an error. */\n trial?: Record<string, TrialQuota>;\n}\n\nexport interface UsageSummary {\n total_requests: number;\n total_duration_seconds: number;\n total_cost: number | string;\n period_start: string;\n period_end: string;\n [key: string]: unknown;\n}\n\nexport interface DailyUsage {\n date: string;\n requests: number;\n duration_seconds: number;\n cost: number | string;\n}\n\nexport interface UsageResponse {\n summary: UsageSummary;\n daily: DailyUsage[];\n}\n\nexport function isAudioChunkEvent(event: StreamEvent): event is AudioChunkEvent {\n return event.type === \"audio_chunk\" && (event as AudioChunkEvent).data instanceof Uint8Array;\n}\n\nexport function isErrorEvent(event: StreamEvent): event is ErrorEvent {\n return event.type === \"error\";\n}\n\n/** SFX segments (unlike music `Segment`) require `end`, must start at 0,\n * and be contiguous; validated server-side. */\nexport interface SfxSegment {\n start: number;\n end: number;\n prompt: string;\n}\n\nexport type SfxAudioFormat = \"wav\" | \"mp3\" | \"aac\" | \"flac\";\n\n/** Submission ack for the async SFX endpoints. */\nexport interface SfxTask {\n task_id: string;\n status: string;\n}\n\n/** A generated file re-hosted on R2 behind a presigned URL. */\nexport interface SfxMedia {\n url: string;\n content_type?: string;\n file_size?: number;\n}\n\nexport interface SfxError {\n code?: string;\n message?: string;\n}\n\n/**\n * Common shape of any polled task (`tasks.get`/`tasks.wait`), regardless of\n * which endpoint created it. `Tasks.get`/`Tasks.wait` are generic over this so\n * each endpoint's result type (e.g. `SfxResult`, `MusicTaskResult`) can add\n * its own `audio`/media fields while sharing the status/error/refund\n * bookkeeping the poller relies on.\n */\nexport interface BaseTaskResult {\n task_id: string;\n type?: string;\n status: \"processing\" | \"succeeded\" | \"failed\" | (string & {});\n /** Only present when the account's task-field whitelist enables cost. */\n cost?: number;\n error?: SfxError;\n refunded?: boolean;\n [key: string]: unknown;\n}\n\n/** State of an SFX task (`tasks.get`) or its final result (`wait`/`generate`). */\nexport interface SfxResult extends BaseTaskResult {\n audio?: SfxMedia;\n /** Kept for backward compatibility; no longer populated — video-to-sfx returns audio only. */\n video?: SfxMedia;\n}\n\nexport interface TextToSfxParams {\n prompt: string;\n duration: number;\n audioFormat?: SfxAudioFormat;\n}\n\nexport interface VideoToSfxParams {\n video?: VideoInput;\n videoUrl?: string;\n prompt?: string;\n segments?: SfxSegment[];\n audioFormat?: SfxAudioFormat;\n}\n\n/** One decoded audio stream of an async video-to-music result. Unlike SFX,\n * `audio` on a music task is always an array — even without `isolateVocals` —\n * since a music generation can carry more than one output stream. */\nexport interface MusicMediaEntry extends SfxMedia {\n stream_index: number;\n sample_rate?: number;\n channels?: number;\n}\n\n/** One muxed audio+video-aligned output, present only when `isolateVocals`\n * is set. */\nexport interface MusicMuxEntry extends SfxMedia {\n stream_index: number;\n}\n\nexport interface MusicTitle {\n title: string;\n summary?: string;\n display_tags?: string[];\n}\n\n/** State of an async video-to-music task (`tasks.get`) or its final result\n * (`tasks.wait<MusicTaskResult>()`). Only reachable via `videoToMusic.submit()`\n * with `mode: \"async\"`. */\nexport interface MusicTaskResult extends BaseTaskResult {\n audio?: MusicMediaEntry[];\n /** Vocals-only stem; present only when `isolateVocals` was requested. */\n vocals?: SfxMedia;\n /** Muxed output per stream; present only when `isolateVocals` was requested. */\n mux?: MusicMuxEntry[];\n /** Music ducked under the source voice; present only when `ducking` ran. */\n ducked?: MusicMediaEntry[];\n title?: MusicTitle;\n duration_seconds?: number;\n}\n\nexport interface WaitOptions {\n /** Milliseconds between polls. Default 2000. */\n pollInterval?: number;\n /** Overall deadline in milliseconds. Default 600000. */\n timeout?: number;\n}\n\n/** Result of an async video-to-video task (`videoToVideoMusic`/`videoToVideoSfx`):\n * a re-hosted video with generated music or SFX muxed in. */\nexport interface VideoResult extends BaseTaskResult {\n video?: SfxMedia;\n duration_seconds?: number;\n}\n\nexport interface VideoToVideoMusicParams {\n video?: VideoInput;\n videoUrl?: string;\n prompt?: string;\n /** Keep the source speech/vocals in the output. Both this and the legacy\n * `isolateVocals` are accepted and OR'd server-side. */\n preserveSpeech?: boolean;\n /** @deprecated Legacy alias for `preserveSpeech`. */\n isolateVocals?: boolean;\n}\n\nexport interface VideoToVideoSfxParams {\n video?: VideoInput;\n videoUrl?: string;\n prompt?: string;\n segments?: SfxSegment[];\n}\n\n/** Params for `videoToSound` and `videoToVideoSound`. Both endpoints take the\n * identical form, so they share one params type. */\nexport interface VideoToSoundParams {\n video?: VideoInput;\n videoUrl?: string;\n /** Style hint for the generated music bed. */\n musicPrompt?: string;\n /** Description of the sound effects layered over the music. */\n sfxPrompt?: string;\n /** Per-segment SFX descriptions; must start at 0 and be contiguous. */\n segments?: SfxSegment[];\n /** Keep the source speech in the result. */\n preserveSpeech?: boolean;\n /** Duck the generated music under the source speech. Default-ON\n * server-side: leave unset to keep it on, pass `false` to opt out. */\n ducking?: boolean;\n}\n\n/** Result of a `videoToSound` / `videoToVideoSound` task (`tasks.get`) or its\n * final state (`generate`).\n *\n * The combined music+SFX result is `output_url` — a bare presigned URL rather\n * than a media object, since these endpoints render one artifact whose kind is\n * announced by `output_type` (\"audio\" for video-to-sound, \"video\" for\n * video-to-video-sound). `music`, `music_processed` and `sfx` are the\n * individual stems; pass any of them, or `output_url` itself, to `download()`. */\nexport interface SoundResult extends BaseTaskResult {\n output_url?: string;\n output_type?: \"audio\" | \"video\";\n output_bytes?: number;\n music?: SfxMedia;\n /** Present only when `preserveSpeech`/`ducking` altered the music bed. */\n music_processed?: SfxMedia;\n sfx?: SfxMedia;\n duration_seconds?: number;\n}\n\n/**\n * A target language for /v1/dubbing. The union stays open (`string & {}`) so a\n * language added server-side still type-checks against an older SDK — the\n * backend, not this list, is the authority on what is supported.\n */\nexport type DubbingLanguage =\n | \"en\"\n | \"zh_cn\"\n | \"ja\"\n | \"ko\"\n | \"pt\"\n | \"es\"\n | \"de\"\n | \"fr\"\n | \"it\"\n | \"ru\"\n | (string & {});\n\nexport interface DubbingParams {\n /** Exactly one of `video` / `videoUrl`. */\n video?: VideoInput;\n /**\n * Exactly one of `video` / `videoUrl`. Must be an `https://` URL — the\n * dubbing pipeline fetches the source itself and rejects plain http.\n */\n videoUrl?: string;\n /** Omit to get the server default, `[\"zh_cn\", \"es\", \"fr\"]`. */\n languages?: DubbingLanguage[];\n}\n\nexport interface DubbingResult extends BaseTaskResult {\n /**\n * One dubbed video URL per requested language, keyed by language code.\n * Unlike every other endpoint's envelope this is a map, not an `audio`/\n * `video` slot — a dubbing task renders N artifacts, one per language.\n */\n outputs?: Record<string, string>;\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonilo",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Official TypeScript/JavaScript client for the Sonilo API",
5
5
  "license": "MIT",
6
6
  "repository": {