songbrain 0.1.1 → 0.2.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 +51 -5
- package/dist/index.cjs +109 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +118 -31
- package/dist/index.d.ts +118 -31
- package/dist/index.js +109 -19
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -96,16 +96,6 @@ interface Timeline {
|
|
|
96
96
|
vocal_timeline: VocalChange[];
|
|
97
97
|
lyric_hooks: LyricHook[] | null;
|
|
98
98
|
}
|
|
99
|
-
interface PlatformFit {
|
|
100
|
-
tiktok: number;
|
|
101
|
-
instagram_reels: number;
|
|
102
|
-
youtube_shorts: number;
|
|
103
|
-
}
|
|
104
|
-
interface CaptionIdeas {
|
|
105
|
-
curiosity?: string;
|
|
106
|
-
hype?: string;
|
|
107
|
-
storytelling?: string;
|
|
108
|
-
}
|
|
109
99
|
interface BestMoment {
|
|
110
100
|
/** 1 = strongest. */
|
|
111
101
|
rank: number;
|
|
@@ -116,16 +106,14 @@ interface BestMoment {
|
|
|
116
106
|
kind: string;
|
|
117
107
|
/** 0-100. */
|
|
118
108
|
score: number;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
109
|
+
/** One sentence: why this moment works. */
|
|
110
|
+
reason: string | null;
|
|
111
|
+
/** The measured audio signals behind the pick, e.g. "strong sustained energy after impact". */
|
|
112
|
+
signals: string[] | null;
|
|
122
113
|
/** The words sung inside the window. */
|
|
123
114
|
sung: string | null;
|
|
124
|
-
platform_fit: PlatformFit;
|
|
125
115
|
/** Beats inside the window. Omitted in view=summary. */
|
|
126
116
|
beat_grid_sec?: number[];
|
|
127
|
-
caption_ideas: CaptionIdeas | null;
|
|
128
|
-
hashtags: string[] | null;
|
|
129
117
|
}
|
|
130
118
|
interface Word {
|
|
131
119
|
w: string;
|
|
@@ -285,6 +273,8 @@ interface ShotPlan {
|
|
|
285
273
|
interface ErrorInfo {
|
|
286
274
|
code: string;
|
|
287
275
|
message: string;
|
|
276
|
+
/** "req_…", also in the Songbrain-Request-Id header. */
|
|
277
|
+
request_id?: string;
|
|
288
278
|
}
|
|
289
279
|
/**
|
|
290
280
|
* The song document. While processing, only `id`, `status`, `progress` and
|
|
@@ -310,6 +300,8 @@ interface Song {
|
|
|
310
300
|
created_at?: string | null;
|
|
311
301
|
external_ref?: string | null;
|
|
312
302
|
billing?: Billing;
|
|
303
|
+
/** false for test-mode songs. */
|
|
304
|
+
livemode?: boolean;
|
|
313
305
|
}
|
|
314
306
|
/** The 202 body of POST /songs. */
|
|
315
307
|
interface SongCreated {
|
|
@@ -320,6 +312,7 @@ interface SongCreated {
|
|
|
320
312
|
billing: Billing;
|
|
321
313
|
external_ref?: string | null;
|
|
322
314
|
url: string;
|
|
315
|
+
livemode?: boolean;
|
|
323
316
|
}
|
|
324
317
|
/** GET /songs/{id}/shot-plan and GET /examples/{id}/shot-plan. */
|
|
325
318
|
interface SongShotPlan {
|
|
@@ -335,10 +328,14 @@ interface SongListItem {
|
|
|
335
328
|
external_ref: string | null;
|
|
336
329
|
created_at: string | null;
|
|
337
330
|
billing: Billing;
|
|
331
|
+
livemode?: boolean;
|
|
338
332
|
}
|
|
339
333
|
interface SongList {
|
|
340
334
|
object: "list";
|
|
341
335
|
data: SongListItem[];
|
|
336
|
+
has_more?: boolean;
|
|
337
|
+
/** Pass as `startingAfter` for the next page. */
|
|
338
|
+
next_cursor?: string | null;
|
|
342
339
|
}
|
|
343
340
|
interface DeleteResult {
|
|
344
341
|
id: string;
|
|
@@ -395,11 +392,44 @@ interface Pricing {
|
|
|
395
392
|
}
|
|
396
393
|
/** A webhook event body. */
|
|
397
394
|
interface WebhookEvent<T = Record<string, unknown>> {
|
|
398
|
-
|
|
395
|
+
/** "evt_…". Stays the same across retries of one event: dedupe on it. */
|
|
396
|
+
id: string;
|
|
397
|
+
type: "song.done" | "song.failed" | "account.low_balance" | "ping" | (string & {});
|
|
399
398
|
/** Unix seconds. */
|
|
400
399
|
created: number;
|
|
400
|
+
livemode: boolean;
|
|
401
401
|
data: T;
|
|
402
402
|
}
|
|
403
|
+
/** From the X-RateLimit-* headers. See `Songbrain.lastRateLimit`. */
|
|
404
|
+
interface RateLimitInfo {
|
|
405
|
+
/** Requests per minute. */
|
|
406
|
+
limit: number;
|
|
407
|
+
remaining: number | null;
|
|
408
|
+
/** Seconds until the window has room again. */
|
|
409
|
+
reset: number | null;
|
|
410
|
+
}
|
|
411
|
+
/** POST /webhooks/test. */
|
|
412
|
+
interface WebhookTestResult {
|
|
413
|
+
delivered: boolean;
|
|
414
|
+
status_code: number | null;
|
|
415
|
+
latency_ms: number;
|
|
416
|
+
event_id: string;
|
|
417
|
+
}
|
|
418
|
+
interface WebhookDelivery {
|
|
419
|
+
event_id: string;
|
|
420
|
+
type: WebhookEvent["type"];
|
|
421
|
+
song_id: string | null;
|
|
422
|
+
url: string;
|
|
423
|
+
attempt: number;
|
|
424
|
+
status_code: number | null;
|
|
425
|
+
delivered: boolean;
|
|
426
|
+
latency_ms: number | null;
|
|
427
|
+
created_at: string;
|
|
428
|
+
}
|
|
429
|
+
interface WebhookDeliveryList {
|
|
430
|
+
object: "list";
|
|
431
|
+
data: WebhookDelivery[];
|
|
432
|
+
}
|
|
403
433
|
|
|
404
434
|
declare const DEFAULT_BASE_URL = "https://api.songbrain.ai/v1";
|
|
405
435
|
/** A Blob/File, a Buffer or bytes, or a local file path (Node). */
|
|
@@ -411,7 +441,10 @@ interface SongbrainOptions {
|
|
|
411
441
|
baseUrl?: string;
|
|
412
442
|
/** Timeout for each HTTP request in ms (uploads included). Default 60 000. */
|
|
413
443
|
timeoutMs?: number;
|
|
414
|
-
/**
|
|
444
|
+
/**
|
|
445
|
+
* How often to retry network errors, 429 and 5xx responses, with backoff. Default 3.
|
|
446
|
+
* Song creation is retried too, because every create sends an `Idempotency-Key`.
|
|
447
|
+
*/
|
|
415
448
|
maxRetries?: number;
|
|
416
449
|
/** A custom fetch implementation. Defaults to the global fetch. */
|
|
417
450
|
fetch?: typeof fetch;
|
|
@@ -429,6 +462,18 @@ interface AnalyzeOptions {
|
|
|
429
462
|
externalRef?: string;
|
|
430
463
|
/** File name for an upload. Its extension must match the audio format. Taken from the path or File name, or guessed from the bytes. */
|
|
431
464
|
filename?: string;
|
|
465
|
+
/**
|
|
466
|
+
* Test mode: free, never charged, no audio needed. The song is done right away and
|
|
467
|
+
* returns the Sugar Rush example analysis with `livemode: false`. `song.done` is
|
|
468
|
+
* still sent to `webhookUrl`. Made for CI and integration tests.
|
|
469
|
+
*/
|
|
470
|
+
test?: boolean;
|
|
471
|
+
/**
|
|
472
|
+
* Sent as `Idempotency-Key`. By default a random UUID per call, reused across the
|
|
473
|
+
* client's own retries, so a retried create never makes a second song. Pass your
|
|
474
|
+
* own (e.g. your job id) to make retries across processes safe too (24 h window).
|
|
475
|
+
*/
|
|
476
|
+
idempotencyKey?: string;
|
|
432
477
|
/** Wait until the song is done and return the full document (default true). */
|
|
433
478
|
wait?: boolean;
|
|
434
479
|
/** Time between status checks while waiting. Default 5 000. */
|
|
@@ -440,6 +485,18 @@ interface WaitOptions {
|
|
|
440
485
|
pollIntervalMs?: number;
|
|
441
486
|
timeoutMs?: number;
|
|
442
487
|
}
|
|
488
|
+
interface ListSongsOptions {
|
|
489
|
+
/** Page size, 1-100. Default 20. */
|
|
490
|
+
limit?: number;
|
|
491
|
+
/** A song id, usually the previous page's `next_cursor`. Returns the songs after it. */
|
|
492
|
+
startingAfter?: string;
|
|
493
|
+
}
|
|
494
|
+
interface IterSongsOptions {
|
|
495
|
+
/** Songs per request, 1-100. Default 100. */
|
|
496
|
+
pageSize?: number;
|
|
497
|
+
/** Start after this song id. */
|
|
498
|
+
startingAfter?: string;
|
|
499
|
+
}
|
|
443
500
|
interface GetSongOptions {
|
|
444
501
|
/** "summary" drops word timings and beat arrays (about 3x smaller). */
|
|
445
502
|
view?: "full" | "summary";
|
|
@@ -462,11 +519,19 @@ declare class Songbrain {
|
|
|
462
519
|
readonly timeoutMs: number;
|
|
463
520
|
readonly maxRetries: number;
|
|
464
521
|
private readonly fetchImpl;
|
|
522
|
+
/**
|
|
523
|
+
* `{ limit, remaining, reset }` from the `X-RateLimit-*` headers of the last response
|
|
524
|
+
* that had them (null before that). `reset` is seconds until the window has room.
|
|
525
|
+
*/
|
|
526
|
+
lastRateLimit: RateLimitInfo | null;
|
|
527
|
+
/** The `Songbrain-Request-Id` of the last response (null before the first one). */
|
|
528
|
+
lastRequestId: string | null;
|
|
465
529
|
/** @internal Overridable in tests. */
|
|
466
530
|
_sleep: (ms: number) => Promise<void>;
|
|
467
531
|
constructor(options?: SongbrainOptions);
|
|
468
532
|
/**
|
|
469
|
-
* Analyse a song from a file or a public URL. Pass exactly one of `file` or `audioUrl
|
|
533
|
+
* Analyse a song from a file or a public URL. Pass exactly one of `file` or `audioUrl`
|
|
534
|
+
* (or neither with `test: true`).
|
|
470
535
|
* Typically 60-90 s. With `wait: true` (default) resolves to the full document;
|
|
471
536
|
* with `wait: false` to the 202 body `{ id, status: "processing", eta_sec, billing }`.
|
|
472
537
|
*/
|
|
@@ -483,16 +548,31 @@ declare class Songbrain {
|
|
|
483
548
|
getSong(songId: string, options?: GetSongOptions): Promise<Song>;
|
|
484
549
|
/** Only the story and the shot plan: `{ id, status, song, story, shot_plan }`. */
|
|
485
550
|
shotPlan(songId: string): Promise<SongShotPlan>;
|
|
486
|
-
/**
|
|
487
|
-
listSongs(options?:
|
|
488
|
-
|
|
489
|
-
|
|
551
|
+
/** One page of your songs, newest first: `{ object: "list", data, has_more, next_cursor }`. */
|
|
552
|
+
listSongs(options?: ListSongsOptions): Promise<SongList>;
|
|
553
|
+
/**
|
|
554
|
+
* All your songs, newest first, fetching pages as needed.
|
|
555
|
+
*
|
|
556
|
+
* ```ts
|
|
557
|
+
* for await (const item of sb.iterSongs()) console.log(item.id, item.status);
|
|
558
|
+
* ```
|
|
559
|
+
*/
|
|
560
|
+
iterSongs(options?: IterSongsOptions): AsyncGenerator<SongListItem, void, undefined>;
|
|
490
561
|
/** Delete a song's audio and analysis now. 409 `still_processing` while it runs. */
|
|
491
562
|
deleteSong(songId: string): Promise<DeleteResult>;
|
|
492
563
|
/** Free songs left this month, credit balance and price per song. */
|
|
493
564
|
account(): Promise<Account>;
|
|
494
565
|
/** Prices and limits. No key needed. */
|
|
495
566
|
pricing(): Promise<Pricing>;
|
|
567
|
+
/**
|
|
568
|
+
* Send a signed `ping` event to `url` right now:
|
|
569
|
+
* `{ delivered, status_code, latency_ms, event_id }`. Checks your receiver before real songs.
|
|
570
|
+
*/
|
|
571
|
+
testWebhook(url: string): Promise<WebhookTestResult>;
|
|
572
|
+
/** The last webhook delivery attempts for your account, newest first. */
|
|
573
|
+
webhookDeliveries(options?: {
|
|
574
|
+
limit?: number;
|
|
575
|
+
}): Promise<WebhookDeliveryList>;
|
|
496
576
|
/** Example analyses of Songbrain's own songs. No key needed. */
|
|
497
577
|
examples(): Promise<ExampleList>;
|
|
498
578
|
/** A full example document, in the same format as `getSong`. No key needed. */
|
|
@@ -504,9 +584,10 @@ declare class Songbrain {
|
|
|
504
584
|
}
|
|
505
585
|
|
|
506
586
|
/**
|
|
507
|
-
* Every API error has the shape `{ error: { code, message } }`.
|
|
508
|
-
* turns it into a `SongbrainError` (or a subclass) with `status`,
|
|
509
|
-
* `message`.
|
|
587
|
+
* Every API error has the shape `{ error: { code, message, request_id } }`.
|
|
588
|
+
* The client turns it into a `SongbrainError` (or a subclass) with `status`,
|
|
589
|
+
* `code`, `message` and `requestId`. The message ends with
|
|
590
|
+
* ` (request_id: req_…)` when there is one; quote it when you contact support.
|
|
510
591
|
*/
|
|
511
592
|
declare class SongbrainError extends Error {
|
|
512
593
|
/** HTTP status, or 0 when the error did not come from an HTTP response. */
|
|
@@ -515,7 +596,9 @@ declare class SongbrainError extends Error {
|
|
|
515
596
|
readonly code: string;
|
|
516
597
|
/** The parsed response body, when there was one. */
|
|
517
598
|
readonly body: unknown;
|
|
518
|
-
|
|
599
|
+
/** The `Songbrain-Request-Id` of the failed request (`req_…`), or null. */
|
|
600
|
+
readonly requestId: string | null;
|
|
601
|
+
constructor(status: number, code: string, message: string, body?: unknown, requestId?: string | null);
|
|
519
602
|
}
|
|
520
603
|
/** 401: the API key is missing, invalid or revoked. */
|
|
521
604
|
declare class AuthenticationError extends SongbrainError {
|
|
@@ -530,7 +613,7 @@ declare class NotFound extends SongbrainError {
|
|
|
530
613
|
declare class RateLimited extends SongbrainError {
|
|
531
614
|
/** Seconds to wait, from the Retry-After header (null if absent). */
|
|
532
615
|
readonly retryAfter: number | null;
|
|
533
|
-
constructor(status: number, code: string, message: string, body?: unknown, retryAfter?: number | null);
|
|
616
|
+
constructor(status: number, code: string, message: string, body?: unknown, retryAfter?: number | null, requestId?: string | null);
|
|
534
617
|
}
|
|
535
618
|
/** The song was accepted but its analysis failed. Paid credits are refunded automatically. */
|
|
536
619
|
declare class AnalysisFailed extends SongbrainError {
|
|
@@ -558,13 +641,17 @@ type RawBody = string | Uint8Array | ArrayBuffer;
|
|
|
558
641
|
declare function verifyWebhook(rawBody: RawBody, header: string | null | undefined, secret: string, toleranceSec?: number): boolean;
|
|
559
642
|
/**
|
|
560
643
|
* Verify the signature and return the parsed event:
|
|
561
|
-
* `{ type: "song.done" | "song.failed" | "account.low_balance", created, data }`.
|
|
644
|
+
* `{ id, type: "song.done" | "song.failed" | "account.low_balance" | "ping", created, livemode, data }`.
|
|
562
645
|
* Throws if the signature is not valid.
|
|
646
|
+
*
|
|
647
|
+
* `id` (`evt_…`, also the `Songbrain-Event-Id` header) stays the same when
|
|
648
|
+
* Songbrain retries an event (up to 10 attempts over about 3 days): store the
|
|
649
|
+
* ids you have handled and skip repeats.
|
|
563
650
|
*/
|
|
564
651
|
declare function constructWebhookEvent<T = Record<string, unknown>>(rawBody: RawBody, header: string | null | undefined, secret: string, toleranceSec?: number): WebhookEvent<T>;
|
|
565
652
|
/** Build a signature header value. Useful to test your webhook handler. */
|
|
566
653
|
declare function signWebhook(rawBody: RawBody, secret: string, timestampSec?: number): string;
|
|
567
654
|
|
|
568
|
-
declare const VERSION = "0.
|
|
655
|
+
declare const VERSION = "0.2.0";
|
|
569
656
|
|
|
570
|
-
export { type Account, type Act, AnalysisFailed, type AnalyzeOptions, AuthenticationError, type BestMoment, type Billing, type
|
|
657
|
+
export { type Account, type Act, AnalysisFailed, type AnalyzeOptions, AuthenticationError, type BestMoment, type Billing, type Clip, DEFAULT_BASE_URL, type DeleteResult, type ErrorInfo, type ExampleList, type ExampleSummary, type FileInput, type FullSong, type FullSongSection, type GetSongOptions, type Instrument, InsufficientCredits, type IterSongsOptions, type KeyChange, type ListSongsOptions, type LoudnessCheck, type LyricHook, type LyricLine, type Lyrics, NotFound, type Phases, type Pricing, type RateLimitInfo, RateLimited, SIGNATURE_HEADER, type Scene, type SceneKind, type ScoreBlock, type Scores, type Section, type SectionName, type ShotPlan, type ShotStyle, type Song, type SongCreated, type SongDNA, type SongInfo, type SongList, type SongListItem, type SongShotPlan, type SongStatus, Songbrain, SongbrainError, type SongbrainOptions, type SoundsLike, type Story, type StoryBeats, type StoryElement, type Timeline, VERSION, type VocalChange, type WaitOptions, WaitTimeout, type WebhookDelivery, type WebhookDeliveryList, type WebhookEvent, type WebhookTestResult, type WhatToFix, type WhatWorks, type Word, constructWebhookEvent, signWebhook, verifyWebhook };
|
package/dist/index.d.ts
CHANGED
|
@@ -96,16 +96,6 @@ interface Timeline {
|
|
|
96
96
|
vocal_timeline: VocalChange[];
|
|
97
97
|
lyric_hooks: LyricHook[] | null;
|
|
98
98
|
}
|
|
99
|
-
interface PlatformFit {
|
|
100
|
-
tiktok: number;
|
|
101
|
-
instagram_reels: number;
|
|
102
|
-
youtube_shorts: number;
|
|
103
|
-
}
|
|
104
|
-
interface CaptionIdeas {
|
|
105
|
-
curiosity?: string;
|
|
106
|
-
hype?: string;
|
|
107
|
-
storytelling?: string;
|
|
108
|
-
}
|
|
109
99
|
interface BestMoment {
|
|
110
100
|
/** 1 = strongest. */
|
|
111
101
|
rank: number;
|
|
@@ -116,16 +106,14 @@ interface BestMoment {
|
|
|
116
106
|
kind: string;
|
|
117
107
|
/** 0-100. */
|
|
118
108
|
score: number;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
109
|
+
/** One sentence: why this moment works. */
|
|
110
|
+
reason: string | null;
|
|
111
|
+
/** The measured audio signals behind the pick, e.g. "strong sustained energy after impact". */
|
|
112
|
+
signals: string[] | null;
|
|
122
113
|
/** The words sung inside the window. */
|
|
123
114
|
sung: string | null;
|
|
124
|
-
platform_fit: PlatformFit;
|
|
125
115
|
/** Beats inside the window. Omitted in view=summary. */
|
|
126
116
|
beat_grid_sec?: number[];
|
|
127
|
-
caption_ideas: CaptionIdeas | null;
|
|
128
|
-
hashtags: string[] | null;
|
|
129
117
|
}
|
|
130
118
|
interface Word {
|
|
131
119
|
w: string;
|
|
@@ -285,6 +273,8 @@ interface ShotPlan {
|
|
|
285
273
|
interface ErrorInfo {
|
|
286
274
|
code: string;
|
|
287
275
|
message: string;
|
|
276
|
+
/** "req_…", also in the Songbrain-Request-Id header. */
|
|
277
|
+
request_id?: string;
|
|
288
278
|
}
|
|
289
279
|
/**
|
|
290
280
|
* The song document. While processing, only `id`, `status`, `progress` and
|
|
@@ -310,6 +300,8 @@ interface Song {
|
|
|
310
300
|
created_at?: string | null;
|
|
311
301
|
external_ref?: string | null;
|
|
312
302
|
billing?: Billing;
|
|
303
|
+
/** false for test-mode songs. */
|
|
304
|
+
livemode?: boolean;
|
|
313
305
|
}
|
|
314
306
|
/** The 202 body of POST /songs. */
|
|
315
307
|
interface SongCreated {
|
|
@@ -320,6 +312,7 @@ interface SongCreated {
|
|
|
320
312
|
billing: Billing;
|
|
321
313
|
external_ref?: string | null;
|
|
322
314
|
url: string;
|
|
315
|
+
livemode?: boolean;
|
|
323
316
|
}
|
|
324
317
|
/** GET /songs/{id}/shot-plan and GET /examples/{id}/shot-plan. */
|
|
325
318
|
interface SongShotPlan {
|
|
@@ -335,10 +328,14 @@ interface SongListItem {
|
|
|
335
328
|
external_ref: string | null;
|
|
336
329
|
created_at: string | null;
|
|
337
330
|
billing: Billing;
|
|
331
|
+
livemode?: boolean;
|
|
338
332
|
}
|
|
339
333
|
interface SongList {
|
|
340
334
|
object: "list";
|
|
341
335
|
data: SongListItem[];
|
|
336
|
+
has_more?: boolean;
|
|
337
|
+
/** Pass as `startingAfter` for the next page. */
|
|
338
|
+
next_cursor?: string | null;
|
|
342
339
|
}
|
|
343
340
|
interface DeleteResult {
|
|
344
341
|
id: string;
|
|
@@ -395,11 +392,44 @@ interface Pricing {
|
|
|
395
392
|
}
|
|
396
393
|
/** A webhook event body. */
|
|
397
394
|
interface WebhookEvent<T = Record<string, unknown>> {
|
|
398
|
-
|
|
395
|
+
/** "evt_…". Stays the same across retries of one event: dedupe on it. */
|
|
396
|
+
id: string;
|
|
397
|
+
type: "song.done" | "song.failed" | "account.low_balance" | "ping" | (string & {});
|
|
399
398
|
/** Unix seconds. */
|
|
400
399
|
created: number;
|
|
400
|
+
livemode: boolean;
|
|
401
401
|
data: T;
|
|
402
402
|
}
|
|
403
|
+
/** From the X-RateLimit-* headers. See `Songbrain.lastRateLimit`. */
|
|
404
|
+
interface RateLimitInfo {
|
|
405
|
+
/** Requests per minute. */
|
|
406
|
+
limit: number;
|
|
407
|
+
remaining: number | null;
|
|
408
|
+
/** Seconds until the window has room again. */
|
|
409
|
+
reset: number | null;
|
|
410
|
+
}
|
|
411
|
+
/** POST /webhooks/test. */
|
|
412
|
+
interface WebhookTestResult {
|
|
413
|
+
delivered: boolean;
|
|
414
|
+
status_code: number | null;
|
|
415
|
+
latency_ms: number;
|
|
416
|
+
event_id: string;
|
|
417
|
+
}
|
|
418
|
+
interface WebhookDelivery {
|
|
419
|
+
event_id: string;
|
|
420
|
+
type: WebhookEvent["type"];
|
|
421
|
+
song_id: string | null;
|
|
422
|
+
url: string;
|
|
423
|
+
attempt: number;
|
|
424
|
+
status_code: number | null;
|
|
425
|
+
delivered: boolean;
|
|
426
|
+
latency_ms: number | null;
|
|
427
|
+
created_at: string;
|
|
428
|
+
}
|
|
429
|
+
interface WebhookDeliveryList {
|
|
430
|
+
object: "list";
|
|
431
|
+
data: WebhookDelivery[];
|
|
432
|
+
}
|
|
403
433
|
|
|
404
434
|
declare const DEFAULT_BASE_URL = "https://api.songbrain.ai/v1";
|
|
405
435
|
/** A Blob/File, a Buffer or bytes, or a local file path (Node). */
|
|
@@ -411,7 +441,10 @@ interface SongbrainOptions {
|
|
|
411
441
|
baseUrl?: string;
|
|
412
442
|
/** Timeout for each HTTP request in ms (uploads included). Default 60 000. */
|
|
413
443
|
timeoutMs?: number;
|
|
414
|
-
/**
|
|
444
|
+
/**
|
|
445
|
+
* How often to retry network errors, 429 and 5xx responses, with backoff. Default 3.
|
|
446
|
+
* Song creation is retried too, because every create sends an `Idempotency-Key`.
|
|
447
|
+
*/
|
|
415
448
|
maxRetries?: number;
|
|
416
449
|
/** A custom fetch implementation. Defaults to the global fetch. */
|
|
417
450
|
fetch?: typeof fetch;
|
|
@@ -429,6 +462,18 @@ interface AnalyzeOptions {
|
|
|
429
462
|
externalRef?: string;
|
|
430
463
|
/** File name for an upload. Its extension must match the audio format. Taken from the path or File name, or guessed from the bytes. */
|
|
431
464
|
filename?: string;
|
|
465
|
+
/**
|
|
466
|
+
* Test mode: free, never charged, no audio needed. The song is done right away and
|
|
467
|
+
* returns the Sugar Rush example analysis with `livemode: false`. `song.done` is
|
|
468
|
+
* still sent to `webhookUrl`. Made for CI and integration tests.
|
|
469
|
+
*/
|
|
470
|
+
test?: boolean;
|
|
471
|
+
/**
|
|
472
|
+
* Sent as `Idempotency-Key`. By default a random UUID per call, reused across the
|
|
473
|
+
* client's own retries, so a retried create never makes a second song. Pass your
|
|
474
|
+
* own (e.g. your job id) to make retries across processes safe too (24 h window).
|
|
475
|
+
*/
|
|
476
|
+
idempotencyKey?: string;
|
|
432
477
|
/** Wait until the song is done and return the full document (default true). */
|
|
433
478
|
wait?: boolean;
|
|
434
479
|
/** Time between status checks while waiting. Default 5 000. */
|
|
@@ -440,6 +485,18 @@ interface WaitOptions {
|
|
|
440
485
|
pollIntervalMs?: number;
|
|
441
486
|
timeoutMs?: number;
|
|
442
487
|
}
|
|
488
|
+
interface ListSongsOptions {
|
|
489
|
+
/** Page size, 1-100. Default 20. */
|
|
490
|
+
limit?: number;
|
|
491
|
+
/** A song id, usually the previous page's `next_cursor`. Returns the songs after it. */
|
|
492
|
+
startingAfter?: string;
|
|
493
|
+
}
|
|
494
|
+
interface IterSongsOptions {
|
|
495
|
+
/** Songs per request, 1-100. Default 100. */
|
|
496
|
+
pageSize?: number;
|
|
497
|
+
/** Start after this song id. */
|
|
498
|
+
startingAfter?: string;
|
|
499
|
+
}
|
|
443
500
|
interface GetSongOptions {
|
|
444
501
|
/** "summary" drops word timings and beat arrays (about 3x smaller). */
|
|
445
502
|
view?: "full" | "summary";
|
|
@@ -462,11 +519,19 @@ declare class Songbrain {
|
|
|
462
519
|
readonly timeoutMs: number;
|
|
463
520
|
readonly maxRetries: number;
|
|
464
521
|
private readonly fetchImpl;
|
|
522
|
+
/**
|
|
523
|
+
* `{ limit, remaining, reset }` from the `X-RateLimit-*` headers of the last response
|
|
524
|
+
* that had them (null before that). `reset` is seconds until the window has room.
|
|
525
|
+
*/
|
|
526
|
+
lastRateLimit: RateLimitInfo | null;
|
|
527
|
+
/** The `Songbrain-Request-Id` of the last response (null before the first one). */
|
|
528
|
+
lastRequestId: string | null;
|
|
465
529
|
/** @internal Overridable in tests. */
|
|
466
530
|
_sleep: (ms: number) => Promise<void>;
|
|
467
531
|
constructor(options?: SongbrainOptions);
|
|
468
532
|
/**
|
|
469
|
-
* Analyse a song from a file or a public URL. Pass exactly one of `file` or `audioUrl
|
|
533
|
+
* Analyse a song from a file or a public URL. Pass exactly one of `file` or `audioUrl`
|
|
534
|
+
* (or neither with `test: true`).
|
|
470
535
|
* Typically 60-90 s. With `wait: true` (default) resolves to the full document;
|
|
471
536
|
* with `wait: false` to the 202 body `{ id, status: "processing", eta_sec, billing }`.
|
|
472
537
|
*/
|
|
@@ -483,16 +548,31 @@ declare class Songbrain {
|
|
|
483
548
|
getSong(songId: string, options?: GetSongOptions): Promise<Song>;
|
|
484
549
|
/** Only the story and the shot plan: `{ id, status, song, story, shot_plan }`. */
|
|
485
550
|
shotPlan(songId: string): Promise<SongShotPlan>;
|
|
486
|
-
/**
|
|
487
|
-
listSongs(options?:
|
|
488
|
-
|
|
489
|
-
|
|
551
|
+
/** One page of your songs, newest first: `{ object: "list", data, has_more, next_cursor }`. */
|
|
552
|
+
listSongs(options?: ListSongsOptions): Promise<SongList>;
|
|
553
|
+
/**
|
|
554
|
+
* All your songs, newest first, fetching pages as needed.
|
|
555
|
+
*
|
|
556
|
+
* ```ts
|
|
557
|
+
* for await (const item of sb.iterSongs()) console.log(item.id, item.status);
|
|
558
|
+
* ```
|
|
559
|
+
*/
|
|
560
|
+
iterSongs(options?: IterSongsOptions): AsyncGenerator<SongListItem, void, undefined>;
|
|
490
561
|
/** Delete a song's audio and analysis now. 409 `still_processing` while it runs. */
|
|
491
562
|
deleteSong(songId: string): Promise<DeleteResult>;
|
|
492
563
|
/** Free songs left this month, credit balance and price per song. */
|
|
493
564
|
account(): Promise<Account>;
|
|
494
565
|
/** Prices and limits. No key needed. */
|
|
495
566
|
pricing(): Promise<Pricing>;
|
|
567
|
+
/**
|
|
568
|
+
* Send a signed `ping` event to `url` right now:
|
|
569
|
+
* `{ delivered, status_code, latency_ms, event_id }`. Checks your receiver before real songs.
|
|
570
|
+
*/
|
|
571
|
+
testWebhook(url: string): Promise<WebhookTestResult>;
|
|
572
|
+
/** The last webhook delivery attempts for your account, newest first. */
|
|
573
|
+
webhookDeliveries(options?: {
|
|
574
|
+
limit?: number;
|
|
575
|
+
}): Promise<WebhookDeliveryList>;
|
|
496
576
|
/** Example analyses of Songbrain's own songs. No key needed. */
|
|
497
577
|
examples(): Promise<ExampleList>;
|
|
498
578
|
/** A full example document, in the same format as `getSong`. No key needed. */
|
|
@@ -504,9 +584,10 @@ declare class Songbrain {
|
|
|
504
584
|
}
|
|
505
585
|
|
|
506
586
|
/**
|
|
507
|
-
* Every API error has the shape `{ error: { code, message } }`.
|
|
508
|
-
* turns it into a `SongbrainError` (or a subclass) with `status`,
|
|
509
|
-
* `message`.
|
|
587
|
+
* Every API error has the shape `{ error: { code, message, request_id } }`.
|
|
588
|
+
* The client turns it into a `SongbrainError` (or a subclass) with `status`,
|
|
589
|
+
* `code`, `message` and `requestId`. The message ends with
|
|
590
|
+
* ` (request_id: req_…)` when there is one; quote it when you contact support.
|
|
510
591
|
*/
|
|
511
592
|
declare class SongbrainError extends Error {
|
|
512
593
|
/** HTTP status, or 0 when the error did not come from an HTTP response. */
|
|
@@ -515,7 +596,9 @@ declare class SongbrainError extends Error {
|
|
|
515
596
|
readonly code: string;
|
|
516
597
|
/** The parsed response body, when there was one. */
|
|
517
598
|
readonly body: unknown;
|
|
518
|
-
|
|
599
|
+
/** The `Songbrain-Request-Id` of the failed request (`req_…`), or null. */
|
|
600
|
+
readonly requestId: string | null;
|
|
601
|
+
constructor(status: number, code: string, message: string, body?: unknown, requestId?: string | null);
|
|
519
602
|
}
|
|
520
603
|
/** 401: the API key is missing, invalid or revoked. */
|
|
521
604
|
declare class AuthenticationError extends SongbrainError {
|
|
@@ -530,7 +613,7 @@ declare class NotFound extends SongbrainError {
|
|
|
530
613
|
declare class RateLimited extends SongbrainError {
|
|
531
614
|
/** Seconds to wait, from the Retry-After header (null if absent). */
|
|
532
615
|
readonly retryAfter: number | null;
|
|
533
|
-
constructor(status: number, code: string, message: string, body?: unknown, retryAfter?: number | null);
|
|
616
|
+
constructor(status: number, code: string, message: string, body?: unknown, retryAfter?: number | null, requestId?: string | null);
|
|
534
617
|
}
|
|
535
618
|
/** The song was accepted but its analysis failed. Paid credits are refunded automatically. */
|
|
536
619
|
declare class AnalysisFailed extends SongbrainError {
|
|
@@ -558,13 +641,17 @@ type RawBody = string | Uint8Array | ArrayBuffer;
|
|
|
558
641
|
declare function verifyWebhook(rawBody: RawBody, header: string | null | undefined, secret: string, toleranceSec?: number): boolean;
|
|
559
642
|
/**
|
|
560
643
|
* Verify the signature and return the parsed event:
|
|
561
|
-
* `{ type: "song.done" | "song.failed" | "account.low_balance", created, data }`.
|
|
644
|
+
* `{ id, type: "song.done" | "song.failed" | "account.low_balance" | "ping", created, livemode, data }`.
|
|
562
645
|
* Throws if the signature is not valid.
|
|
646
|
+
*
|
|
647
|
+
* `id` (`evt_…`, also the `Songbrain-Event-Id` header) stays the same when
|
|
648
|
+
* Songbrain retries an event (up to 10 attempts over about 3 days): store the
|
|
649
|
+
* ids you have handled and skip repeats.
|
|
563
650
|
*/
|
|
564
651
|
declare function constructWebhookEvent<T = Record<string, unknown>>(rawBody: RawBody, header: string | null | undefined, secret: string, toleranceSec?: number): WebhookEvent<T>;
|
|
565
652
|
/** Build a signature header value. Useful to test your webhook handler. */
|
|
566
653
|
declare function signWebhook(rawBody: RawBody, secret: string, timestampSec?: number): string;
|
|
567
654
|
|
|
568
|
-
declare const VERSION = "0.
|
|
655
|
+
declare const VERSION = "0.2.0";
|
|
569
656
|
|
|
570
|
-
export { type Account, type Act, AnalysisFailed, type AnalyzeOptions, AuthenticationError, type BestMoment, type Billing, type
|
|
657
|
+
export { type Account, type Act, AnalysisFailed, type AnalyzeOptions, AuthenticationError, type BestMoment, type Billing, type Clip, DEFAULT_BASE_URL, type DeleteResult, type ErrorInfo, type ExampleList, type ExampleSummary, type FileInput, type FullSong, type FullSongSection, type GetSongOptions, type Instrument, InsufficientCredits, type IterSongsOptions, type KeyChange, type ListSongsOptions, type LoudnessCheck, type LyricHook, type LyricLine, type Lyrics, NotFound, type Phases, type Pricing, type RateLimitInfo, RateLimited, SIGNATURE_HEADER, type Scene, type SceneKind, type ScoreBlock, type Scores, type Section, type SectionName, type ShotPlan, type ShotStyle, type Song, type SongCreated, type SongDNA, type SongInfo, type SongList, type SongListItem, type SongShotPlan, type SongStatus, Songbrain, SongbrainError, type SongbrainOptions, type SoundsLike, type Story, type StoryBeats, type StoryElement, type Timeline, VERSION, type VocalChange, type WaitOptions, WaitTimeout, type WebhookDelivery, type WebhookDeliveryList, type WebhookEvent, type WebhookTestResult, type WhatToFix, type WhatWorks, type Word, constructWebhookEvent, signWebhook, verifyWebhook };
|