sonilo 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -10,6 +10,9 @@ var APIError = class extends SoniloError {
10
10
  super(message);
11
11
  this.status = status;
12
12
  this.body = body;
13
+ const parsed = body;
14
+ this.code = typeof parsed?.code === "string" ? parsed.code : void 0;
15
+ this.errors = Array.isArray(parsed?.errors) ? parsed.errors : void 0;
13
16
  }
14
17
  };
15
18
  var AuthenticationError = class extends APIError {
@@ -19,6 +22,9 @@ var PaymentRequiredError = class extends APIError {
19
22
  var BadRequestError = class extends APIError {
20
23
  get detail() {
21
24
  const body = this.body;
25
+ if (typeof body?.message === "string" && body.message) {
26
+ return body.message;
27
+ }
22
28
  return typeof body?.detail === "string" ? body.detail : void 0;
23
29
  }
24
30
  };
@@ -34,6 +40,25 @@ var GenerationError = class extends SoniloError {
34
40
  this.code = code;
35
41
  }
36
42
  };
43
+ var TaskFailedError = class extends SoniloError {
44
+ constructor(message, opts) {
45
+ super(message);
46
+ this.code = opts.code;
47
+ this.taskId = opts.taskId;
48
+ this.refunded = opts.refunded;
49
+ }
50
+ };
51
+ var TaskTimeoutError = class extends SoniloError {
52
+ constructor(message, taskId) {
53
+ super(message);
54
+ this.taskId = taskId;
55
+ }
56
+ };
57
+ var RequestTimeoutError = class extends SoniloError {
58
+ };
59
+ function isTimeoutSignalError(err) {
60
+ return err instanceof Error && (err.name === "TimeoutError" || err.name === "AbortError");
61
+ }
37
62
  async function errorFromResponse(res) {
38
63
  const text = await res.text().catch(() => "");
39
64
  let body = text;
@@ -41,8 +66,25 @@ async function errorFromResponse(res) {
41
66
  body = JSON.parse(text);
42
67
  } catch {
43
68
  }
44
- const detail = typeof body?.detail === "string" ? body.detail : res.statusText || "request failed";
45
- const message = `HTTP ${res.status}: ${detail}`;
69
+ const parsed = body;
70
+ const rawMessage = typeof parsed?.message === "string" && parsed.message ? parsed.message : void 0;
71
+ const rawDetail = parsed?.detail;
72
+ const isDetailAbsent = rawDetail === void 0 || rawDetail === null || rawDetail === "";
73
+ let reason;
74
+ if (rawMessage !== void 0) {
75
+ reason = rawMessage;
76
+ } else if (isDetailAbsent) {
77
+ reason = res.statusText || "request failed";
78
+ } else if (typeof rawDetail === "string") {
79
+ reason = rawDetail;
80
+ } else {
81
+ try {
82
+ reason = JSON.stringify(rawDetail);
83
+ } catch {
84
+ reason = res.statusText || "request failed";
85
+ }
86
+ }
87
+ const message = `HTTP ${res.status}: ${reason}`;
46
88
  switch (res.status) {
47
89
  case 401:
48
90
  return new AuthenticationError(message, res.status, body);
@@ -78,6 +120,56 @@ var Account = class {
78
120
  }
79
121
  };
80
122
 
123
+ // src/resources/tasks.ts
124
+ var DEFAULT_POLL_INTERVAL_MS = 2e3;
125
+ var DEFAULT_WAIT_TIMEOUT_MS = 6e5;
126
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
127
+ function validateWaitArgs(pollInterval, timeout) {
128
+ if (pollInterval < 0) {
129
+ throw new SoniloError(`pollInterval must be >= 0, got ${pollInterval}`);
130
+ }
131
+ if (timeout < 0) {
132
+ throw new SoniloError(`timeout must be >= 0, got ${timeout}`);
133
+ }
134
+ }
135
+ var Tasks = class {
136
+ constructor(client) {
137
+ this.client = client;
138
+ }
139
+ /** Fetch current task state. Never throws on a failed status. */
140
+ async get(taskId) {
141
+ const res = await this.client.request(`/v1/tasks/${encodeURIComponent(taskId)}`);
142
+ return await res.json();
143
+ }
144
+ /** Poll until the task is terminal; throw on failure or deadline. */
145
+ async wait(taskId, opts = {}) {
146
+ const pollInterval = opts.pollInterval ?? DEFAULT_POLL_INTERVAL_MS;
147
+ const timeout = opts.timeout ?? DEFAULT_WAIT_TIMEOUT_MS;
148
+ validateWaitArgs(pollInterval, timeout);
149
+ const deadline = performance.now() + timeout;
150
+ for (; ; ) {
151
+ const result = await this.get(taskId);
152
+ if (result.status === "succeeded") return result;
153
+ if (result.status === "failed") {
154
+ const message = result.error?.message || "Generation failed";
155
+ throw new TaskFailedError(`Task ${taskId} failed: ${message}`, {
156
+ code: result.error?.code,
157
+ taskId,
158
+ refunded: result.refunded
159
+ });
160
+ }
161
+ const remaining = deadline - performance.now();
162
+ if (remaining <= 0) {
163
+ throw new TaskTimeoutError(
164
+ `Task ${taskId} still processing after ${timeout}ms; it may finish later \u2014 resume with tasks.wait or tasks.get`,
165
+ taskId
166
+ );
167
+ }
168
+ await sleep(Math.min(pollInterval, remaining));
169
+ }
170
+ }
171
+ };
172
+
81
173
  // src/streaming.ts
82
174
  function decodeBase64(b64) {
83
175
  const bin = atob(b64);
@@ -86,9 +178,14 @@ function decodeBase64(b64) {
86
178
  return out;
87
179
  }
88
180
  function toEvent(line) {
89
- const raw = JSON.parse(line);
181
+ const parsed = JSON.parse(line);
182
+ if (typeof parsed !== "object" || parsed === null) return null;
183
+ const raw = parsed;
90
184
  if (raw.type === "audio_chunk" && typeof raw.data === "string") {
91
- return { ...raw, type: "audio_chunk", data: decodeBase64(raw.data) };
185
+ try {
186
+ return { ...raw, type: "audio_chunk", data: decodeBase64(raw.data) };
187
+ } catch {
188
+ }
92
189
  }
93
190
  return raw;
94
191
  }
@@ -105,12 +202,18 @@ async function* parseNdjson(body) {
105
202
  while ((nl = buffer.indexOf("\n")) !== -1) {
106
203
  const line = buffer.slice(0, nl).trim();
107
204
  buffer = buffer.slice(nl + 1);
108
- if (line) yield toEvent(line);
205
+ if (line) {
206
+ const ev = toEvent(line);
207
+ if (ev !== null) yield ev;
208
+ }
109
209
  }
110
210
  }
111
211
  buffer += decoder.decode();
112
212
  const tail = buffer.trim();
113
- if (tail) yield toEvent(tail);
213
+ if (tail) {
214
+ const ev = toEvent(tail);
215
+ if (ev !== null) yield ev;
216
+ }
114
217
  } finally {
115
218
  await reader.cancel().catch(() => {
116
219
  });
@@ -122,7 +225,12 @@ async function collectTrack(events) {
122
225
  let cost;
123
226
  let sawComplete = false;
124
227
  for await (const ev of events) {
125
- if (ev.type === "audio_chunk" && ev.data instanceof Uint8Array) {
228
+ if (ev.type === "audio_chunk") {
229
+ if (!(ev.data instanceof Uint8Array)) {
230
+ throw new GenerationError(
231
+ "received a malformed audio_chunk event (missing or non-decodable data)"
232
+ );
233
+ }
126
234
  chunks.push(ev.data);
127
235
  } else if (ev.type === "title" && typeof ev.title === "string") {
128
236
  title = ev.title;
@@ -130,7 +238,7 @@ async function collectTrack(events) {
130
238
  const { type: _type, ...rest } = ev;
131
239
  cost = rest;
132
240
  } else if (ev.type === "error") {
133
- const message = typeof ev.message === "string" ? ev.message : "generation failed";
241
+ const message = typeof ev.message === "string" && ev.message !== "" ? ev.message : "generation failed";
134
242
  const code = typeof ev.code === "string" ? ev.code : void 0;
135
243
  throw new GenerationError(message, code);
136
244
  } else if (ev.type === "complete") {
@@ -163,10 +271,11 @@ var TextToMusic = class {
163
271
  if (params.segments !== void 0) {
164
272
  form.set("segments", JSON.stringify(params.segments));
165
273
  }
166
- const res = await this.client.request("/v1/text-to-music", {
167
- method: "POST",
168
- body: form
169
- });
274
+ const res = await this.client.request(
275
+ "/v1/text-to-music",
276
+ { method: "POST", body: form, signal: params.signal },
277
+ { timeout: null }
278
+ );
170
279
  if (!res.body) throw new SoniloError("Response has no body");
171
280
  yield* parseNdjson(res.body);
172
281
  }
@@ -234,10 +343,11 @@ var VideoToMusic = class {
234
343
  if (params.segments !== void 0) {
235
344
  form.set("segments", JSON.stringify(params.segments));
236
345
  }
237
- const res = await this.client.request("/v1/video-to-music", {
238
- method: "POST",
239
- body: form
240
- });
346
+ const res = await this.client.request(
347
+ "/v1/video-to-music",
348
+ { method: "POST", body: form, signal: params.signal },
349
+ { timeout: null }
350
+ );
241
351
  if (!res.body) throw new SoniloError("Response has no body");
242
352
  yield* parseNdjson(res.body);
243
353
  }
@@ -246,11 +356,67 @@ var VideoToMusic = class {
246
356
  }
247
357
  };
248
358
 
359
+ // src/resources/textToSfx.ts
360
+ var TextToSfx = class {
361
+ constructor(client) {
362
+ this.client = client;
363
+ }
364
+ async submit(params) {
365
+ const form = new FormData();
366
+ form.set("prompt", params.prompt);
367
+ form.set("duration", String(params.duration));
368
+ if (params.audioFormat !== void 0) form.set("audio_format", params.audioFormat);
369
+ const res = await this.client.request("/v1/text-to-sfx", {
370
+ method: "POST",
371
+ body: form
372
+ });
373
+ return await res.json();
374
+ }
375
+ async generate(params, opts) {
376
+ const task = await this.submit(params);
377
+ return this.client.tasks.wait(task.task_id, opts);
378
+ }
379
+ };
380
+
381
+ // src/resources/videoToSfx.ts
382
+ var VideoToSfx = class {
383
+ constructor(client) {
384
+ this.client = client;
385
+ }
386
+ async submit(params) {
387
+ if (params.video === void 0 === (params.videoUrl === void 0)) {
388
+ throw new SoniloError("Provide exactly one of video or videoUrl");
389
+ }
390
+ const form = new FormData();
391
+ if (params.video !== void 0) {
392
+ const { blob, filename } = await toUploadBlob(params.video);
393
+ form.set("video", blob, filename);
394
+ } else {
395
+ form.set("video_url", params.videoUrl);
396
+ }
397
+ if (params.prompt !== void 0) form.set("prompt", params.prompt);
398
+ if (params.segments !== void 0) {
399
+ form.set("segments", JSON.stringify(params.segments));
400
+ }
401
+ if (params.audioFormat !== void 0) form.set("audio_format", params.audioFormat);
402
+ const res = await this.client.request("/v1/video-to-sfx", {
403
+ method: "POST",
404
+ body: form
405
+ });
406
+ return await res.json();
407
+ }
408
+ async generate(params, opts) {
409
+ const task = await this.submit(params);
410
+ return this.client.tasks.wait(task.task_id, opts);
411
+ }
412
+ };
413
+
249
414
  // src/version.ts
250
- var VERSION = "0.1.0";
415
+ var VERSION = "0.2.0";
251
416
 
252
417
  // src/client.ts
253
418
  var DEFAULT_BASE_URL = "https://api.sonilo.com";
419
+ var DEFAULT_TIMEOUT_MS = 6e5;
254
420
  var SoniloClient = class {
255
421
  constructor(options = {}) {
256
422
  const envKey = typeof process !== "undefined" ? process.env?.SONILO_API_KEY : void 0;
@@ -263,22 +429,63 @@ var SoniloClient = class {
263
429
  this.apiKey = apiKey;
264
430
  this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
265
431
  this.fetchFn = (options.fetch ?? globalThis.fetch).bind(globalThis);
432
+ this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;
266
433
  this.account = new Account(this);
434
+ this.tasks = new Tasks(this);
267
435
  this.textToMusic = new TextToMusic(this);
268
436
  this.videoToMusic = new VideoToMusic(this);
437
+ this.textToSfx = new TextToSfx(this);
438
+ this.videoToSfx = new VideoToSfx(this);
269
439
  }
270
- /** Perform an authenticated request; throws a typed error on non-2xx. */
271
- async request(path, init = {}) {
440
+ /**
441
+ * Perform an authenticated request; throws a typed error on non-2xx.
442
+ *
443
+ * `opts.timeout` overrides the client's default timeout for this call;
444
+ * pass `null` to disable the abort-on-timeout behavior entirely (used by
445
+ * the streaming music endpoints — see textToMusic.ts / videoToMusic.ts).
446
+ * A caller-supplied `init.signal` always wins over any timeout signal.
447
+ */
448
+ async request(path, init = {}, opts = {}) {
272
449
  const headers = new Headers(init.headers);
273
450
  headers.set("Authorization", `Bearer ${this.apiKey}`);
274
451
  headers.set("X-Sonilo-Client", "sdk-js");
275
452
  headers.set("X-Sonilo-Client-Version", VERSION);
276
- const res = await this.fetchFn(`${this.baseUrl}${path}`, { ...init, headers });
277
- if (!res.ok) throw await errorFromResponse(res);
278
- return res;
453
+ const timeout = opts.timeout === void 0 ? this.timeout : opts.timeout;
454
+ const ownsSignal = init.signal == null && timeout !== null;
455
+ const signal = init.signal ?? (timeout === null ? void 0 : AbortSignal.timeout(timeout));
456
+ try {
457
+ const res = await this.fetchFn(`${this.baseUrl}${path}`, { ...init, headers, signal });
458
+ if (!res.ok) throw await errorFromResponse(res);
459
+ return res;
460
+ } catch (err) {
461
+ if (ownsSignal && isTimeoutSignalError(err)) {
462
+ throw new RequestTimeoutError(`Request to ${path} timed out after ${timeout}ms`);
463
+ }
464
+ throw err;
465
+ }
279
466
  }
280
467
  };
281
468
 
469
+ // src/download.ts
470
+ async function download(media, fetchFn = globalThis.fetch, timeout = DEFAULT_TIMEOUT_MS) {
471
+ if (!media?.url) {
472
+ throw new SoniloError("No media to download");
473
+ }
474
+ let res;
475
+ try {
476
+ res = await fetchFn(media.url, { signal: AbortSignal.timeout(timeout) });
477
+ } catch (err) {
478
+ if (isTimeoutSignalError(err)) {
479
+ throw new RequestTimeoutError(`Download of ${media.url} timed out after ${timeout}ms`);
480
+ }
481
+ throw err;
482
+ }
483
+ if (!res.ok) {
484
+ throw new SoniloError(`Download failed: HTTP ${res.status}`);
485
+ }
486
+ return new Uint8Array(await res.arrayBuffer());
487
+ }
488
+
282
489
  // src/types.ts
283
490
  function isAudioChunkEvent(event) {
284
491
  return event.type === "audio_chunk" && event.data instanceof Uint8Array;
@@ -290,12 +497,17 @@ export {
290
497
  APIError,
291
498
  AuthenticationError,
292
499
  BadRequestError,
500
+ DEFAULT_TIMEOUT_MS,
293
501
  GenerationError,
294
502
  PaymentRequiredError,
295
503
  RateLimitError,
504
+ RequestTimeoutError,
296
505
  SoniloClient,
297
506
  SoniloError,
507
+ TaskFailedError,
508
+ TaskTimeoutError,
298
509
  VERSION,
510
+ download,
299
511
  isAudioChunkEvent,
300
512
  isErrorEvent
301
513
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/resources/account.ts","../src/streaming.ts","../src/resources/textToMusic.ts","../src/upload.ts","../src/resources/videoToMusic.ts","../src/version.ts","../src/client.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\n constructor(message: string, status: number, body?: unknown) {\n super(message);\n this.status = status;\n this.body = body;\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 { detail?: unknown } | undefined;\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\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 detail =\n typeof (body as { detail?: unknown })?.detail === \"string\"\n ? (body as { detail: string }).detail\n : res.statusText || \"request failed\";\n const message = `HTTP ${res.status}: ${detail}`;\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 { 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\nfunction toEvent(line: string): StreamEvent {\n const raw = JSON.parse(line) as { type: string; [key: string]: unknown };\n if (raw.type === \"audio_chunk\" && typeof raw.data === \"string\") {\n return { ...raw, type: \"audio_chunk\", data: decodeBase64(raw.data) };\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) yield toEvent(line);\n }\n }\n buffer += decoder.decode();\n const tail = buffer.trim();\n if (tail) yield toEvent(tail);\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\" && ev.data instanceof Uint8Array) {\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 : \"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 { 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 const res = await this.client.request(\"/v1/text-to-music\", {\n method: \"POST\",\n body: form,\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","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 { 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 const res = await this.client.request(\"/v1/video-to-music\", {\n method: \"POST\",\n body: form,\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","export const VERSION = \"0.1.0\";\n","import { SoniloError, errorFromResponse } from \"./errors.js\";\nimport { Account } from \"./resources/account.js\";\nimport { TextToMusic } from \"./resources/textToMusic.js\";\nimport { VideoToMusic } from \"./resources/videoToMusic.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}\n\nconst DEFAULT_BASE_URL = \"https://api.sonilo.com\";\n\nexport class SoniloClient {\n readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly fetchFn: typeof globalThis.fetch;\n readonly account: Account;\n readonly textToMusic: TextToMusic;\n readonly videoToMusic: VideoToMusic;\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.account = new Account(this);\n this.textToMusic = new TextToMusic(this);\n this.videoToMusic = new VideoToMusic(this);\n }\n\n /** Perform an authenticated request; throws a typed error on non-2xx. */\n async request(path: string, init: RequestInit = {}): Promise<Response> {\n const headers = new Headers(init.headers);\n headers.set(\"Authorization\", `Bearer ${this.apiKey}`);\n headers.set(\"X-Sonilo-Client\", \"sdk-js\");\n headers.set(\"X-Sonilo-Client-Version\", VERSION);\n const res = await this.fetchFn(`${this.baseUrl}${path}`, { ...init, headers });\n if (!res.ok) throw await errorFromResponse(res);\n return res;\n }\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}\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}\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}\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"],"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/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 { 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 /** Fetch current task state. Never throws on a failed status. */\n async get(taskId: string): Promise<SfxResult> {\n const res = await this.client.request(`/v1/tasks/${encodeURIComponent(taskId)}`);\n return (await res.json()) as SfxResult;\n }\n\n /** Poll until the task is terminal; throw on failure or deadline. */\n async wait(taskId: string, opts: WaitOptions = {}): Promise<SfxResult> {\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(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 { 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","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 { 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","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","export const VERSION = \"0.2.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 { 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\nconst DEFAULT_BASE_URL = \"https://api.sonilo.com\";\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 readonly account: Account;\n readonly tasks: Tasks;\n readonly textToMusic: TextToMusic;\n readonly videoToMusic: VideoToMusic;\n readonly textToSfx: TextToSfx;\n readonly videoToSfx: VideoToSfx;\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.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 }\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\", \"sdk-js\");\n headers.set(\"X-Sonilo-Client-Version\", VERSION);\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. */\nexport async function download(\n media: SfxMedia | undefined,\n fetchFn: typeof globalThis.fetch = globalThis.fetch,\n timeout: number = DEFAULT_TIMEOUT_MS,\n): Promise<Uint8Array> {\n if (!media?.url) {\n throw new SoniloError(\"No media to download\");\n }\n let res: Response;\n try {\n res = await fetchFn(media.url, { signal: AbortSignal.timeout(timeout) });\n } catch (err) {\n if (isTimeoutSignalError(err)) {\n throw new RequestTimeoutError(`Download of ${media.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 /** 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. */\n signal?: AbortSignal;\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}\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/** State of an SFX task (`tasks.get`) or its final result (`wait`/`generate`). */\nexport interface SfxResult {\n task_id: string;\n type?: string;\n status: \"processing\" | \"succeeded\" | \"failed\" | (string & {});\n audio?: SfxMedia;\n /** Kept for backward compatibility; no longer populated — video-to-sfx returns audio only. */\n video?: SfxMedia;\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\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\nexport interface WaitOptions {\n /** Milliseconds between polls. Default 2000. */\n pollInterval?: number;\n /** Overall deadline in milliseconds. Default 600000. */\n timeout?: number;\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.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "Official TypeScript/JavaScript client for the Sonilo API",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -13,8 +13,14 @@
13
13
  "types": "./dist/index.d.ts",
14
14
  "exports": {
15
15
  ".": {
16
- "import": { "types": "./dist/index.d.ts", "default": "./dist/index.js" },
17
- "require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" }
16
+ "import": {
17
+ "types": "./dist/index.d.ts",
18
+ "default": "./dist/index.js"
19
+ },
20
+ "require": {
21
+ "types": "./dist/index.d.cts",
22
+ "default": "./dist/index.cjs"
23
+ }
18
24
  }
19
25
  },
20
26
  "files": [
@@ -41,6 +47,8 @@
41
47
  "generation",
42
48
  "text-to-music",
43
49
  "video-to-music",
44
- "ai"
50
+ "ai",
51
+ "sfx",
52
+ "sound-effects"
45
53
  ]
46
54
  }