sonovault 2.0.0 → 4.0.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
@@ -37,6 +37,12 @@ for (const link of links) {
37
37
  console.log(link.source, link.url); // spotify https://open.spotify.com/track/...
38
38
  }
39
39
 
40
+ // An album's tracklist, in playing order
41
+ const release = await sv.releases.get(7);
42
+ for (const t of release.tracks ?? []) {
43
+ console.log(t.disc_number, t.track_number, t.title); // 1 1 One More Time
44
+ }
45
+
40
46
  // Recording to composition (ISWC), for royalty and publishing workflows
41
47
  const work = await sv.tracks.iswc({ isrc: "GBDUW0000053" });
42
48
  ```
package/dist/index.cjs CHANGED
@@ -50,7 +50,7 @@ var SonoVaultError = class extends Error {
50
50
  };
51
51
 
52
52
  // src/version.ts
53
- var VERSION = "2.0.0";
53
+ var VERSION = "4.0.0";
54
54
 
55
55
  // src/client.ts
56
56
  var SonoVault = class {
package/dist/index.d.cts CHANGED
@@ -30,8 +30,36 @@ interface Track {
30
30
  artists: TrackArtist[];
31
31
  isrc: string | null;
32
32
  duration: number | null;
33
- genre: string | null;
34
- subgenre: string | null;
33
+ /** Canonical genres. Empty array when the track is unclassified. */
34
+ genre: string[];
35
+ /** Canonical subgenres. Empty array when none apply. */
36
+ subgenre: string[];
37
+ }
38
+ /**
39
+ * A track as embedded in a release, from `GET /v1/releases/:id`.
40
+ *
41
+ * Same as {@link Track} minus the `releases` array (the release is the object
42
+ * you are already looking at), plus this track's position on that release.
43
+ */
44
+ interface ReleaseTrack {
45
+ id: number;
46
+ title: string;
47
+ artists: TrackArtist[];
48
+ isrc: string | null;
49
+ duration: number | null;
50
+ /** Canonical genres. Empty array when the track is unclassified. */
51
+ genre: string[];
52
+ /** Canonical subgenres. Empty array when none apply. */
53
+ subgenre: string[];
54
+ /** Disc the track sits on, counting from 1. Null when the position is unknown. */
55
+ disc_number: number | null;
56
+ /**
57
+ * Position on this release, counting from 1 within its disc. A position
58
+ * belongs to the pairing of track and release rather than to the track, so
59
+ * the same recording can be track 6 on an album and track 2 on a
60
+ * compilation. Null when the position is unknown.
61
+ */
62
+ track_number: number | null;
35
63
  }
36
64
  /** A cursor-paginated page. `next_cursor` is null on the last page. */
37
65
  interface Page<T> {
@@ -41,6 +69,18 @@ interface Page<T> {
41
69
  interface Artist {
42
70
  id: number;
43
71
  name: string;
72
+ /** Country of origin, in English. Null when unknown. */
73
+ country?: string | null;
74
+ /** Year the artist or group started, or birth year for a solo act. */
75
+ formation_year?: number | null;
76
+ /** Full ISO date, present only when day-level precision is known. */
77
+ formation_date?: string | null;
78
+ /** Platform to handle or URL. Which keys appear varies by artist. */
79
+ social_links?: Record<string, string> | null;
80
+ /** Wikidata entity ID, e.g. `Q185828`. Null when unmapped. */
81
+ wikidata_id?: string | null;
82
+ /** MusicBrainz artist MBID. Null when unmapped. */
83
+ musicbrainz_id?: string | null;
44
84
  [key: string]: unknown;
45
85
  }
46
86
  interface Label {
@@ -60,16 +100,33 @@ interface Release {
60
100
  name: string;
61
101
  } | null;
62
102
  release_date?: string | null;
63
- tracks?: Track[];
103
+ /**
104
+ * MusicBrainz release MBIDs, sorted. An array rather than a single value
105
+ * because a SonoVault release groups every edition of an album and each
106
+ * edition carries its own MBID, so you can pick the edition you need. Empty
107
+ * when unmapped. Only returned by `releases.get()`.
108
+ */
109
+ musicbrainz_release_ids?: string[];
110
+ /**
111
+ * MusicBrainz release-group MBIDs: the identity of the album across all its
112
+ * editions, as opposed to any one pressing. Usually a single entry. Empty
113
+ * when unmapped. Only returned by `releases.get()`.
114
+ */
115
+ musicbrainz_release_group_ids?: string[];
116
+ /**
117
+ * The tracklist, in playing order (disc, then track number), with any track
118
+ * whose position is unknown last.
119
+ */
120
+ tracks?: ReleaseTrack[];
64
121
  [key: string]: unknown;
65
122
  }
66
123
  interface Genre {
67
124
  id: number;
68
125
  name: string;
69
- subgenres?: {
70
- id: number;
71
- name: string;
72
- }[];
126
+ /** Whether this is a top-level genre or a subgenre. */
127
+ type: "main" | "subgenre";
128
+ /** Name of the parent genre; null for a top-level genre. */
129
+ parent: string | null;
73
130
  [key: string]: unknown;
74
131
  }
75
132
  /** A track's ID on an external platform, with a deep link. */
@@ -81,6 +138,8 @@ interface PlatformLink {
81
138
  interface PlatformLinksResponse {
82
139
  track_id: number;
83
140
  title: string;
141
+ /** One representative ISRC for the track; null when none is known. */
142
+ isrc: string | null;
84
143
  links: PlatformLink[];
85
144
  [key: string]: unknown;
86
145
  }
@@ -135,11 +194,44 @@ interface IdentifyResponse {
135
194
  }
136
195
  interface Stream {
137
196
  id: string;
138
- url?: string;
139
- name?: string;
140
- status?: string;
197
+ url: string;
198
+ name: string | null;
199
+ status: "active" | "stopped";
200
+ detection_mode: "precise" | "balanced" | "broad";
201
+ /** Whether we email you when this stream goes down and when it recovers. */
202
+ outage_notifications: boolean;
203
+ created_at: string;
204
+ stopped_at: string | null;
141
205
  [key: string]: unknown;
142
206
  }
207
+ /**
208
+ * A stream's live state, as returned by `streams.get()`: the stream fields plus
209
+ * what is playing right now.
210
+ */
211
+ interface StreamStatus extends Stream {
212
+ /** What the monitor is doing now: `pending`, `running`, `errored` or `stopped`. */
213
+ runtime_status: string;
214
+ /** Why it is in that state (e.g. an auth wall on the host); null when it is fine. */
215
+ status_reason: string | null;
216
+ /** Null during ad breaks, talk, or audio we cannot place. */
217
+ now_playing: {
218
+ track: Track;
219
+ started_at: string;
220
+ } | null;
221
+ last_recognized_at: string | null;
222
+ /** Recognition tuning hint in force; null means auto (all recognisers). */
223
+ format: "electronic" | "classical" | "pop" | null;
224
+ }
225
+ /**
226
+ * The response to `streams.update()`. The API echoes back only the fields you
227
+ * changed, so everything but `id` is optional.
228
+ */
229
+ interface StreamUpdateResponse {
230
+ id: string;
231
+ format?: "electronic" | "classical" | "pop" | null;
232
+ detection_mode?: "precise" | "balanced" | "broad";
233
+ outage_notifications?: boolean;
234
+ }
143
235
  interface Webhook {
144
236
  id: string;
145
237
  url: string;
@@ -313,8 +405,8 @@ declare class SonoVault {
313
405
  list: () => Promise<{
314
406
  streams: Stream[];
315
407
  }>;
316
- get: (id: string) => Promise<Stream>;
317
- update: (id: string, body: Record<string, unknown>) => Promise<Stream>;
408
+ get: (id: string) => Promise<StreamStatus>;
409
+ update: (id: string, body: Record<string, unknown>) => Promise<StreamUpdateResponse>;
318
410
  history: (id: string, params?: {
319
411
  since?: string;
320
412
  }) => Promise<Record<string, unknown>>;
@@ -413,4 +505,4 @@ declare function verifyWebhookSignature(options: {
413
505
  */
414
506
  declare function paginate<T>(fetchPage: (cursor: string | undefined) => Promise<Page<T>>): AsyncGenerator<T>;
415
507
 
416
- export { type Artist, type Genre, type IdentifyResponse, type IdentifyResult, type IswcLookupResponse, type Label, type Page, type PlatformLink, type PlatformLinksResponse, type Release, type ResolveInputType, type ResolveRequest, type ResolveResponse, type ResolveResult, SonoVault, SonoVaultError, type SonoVaultOptions, type Stream, type StreamEvent, type Track, type TrackArtist, type TrackRelease, type Webhook, paginate, verifyWebhookSignature };
508
+ export { type Artist, type Genre, type IdentifyResponse, type IdentifyResult, type IswcLookupResponse, type Label, type Page, type PlatformLink, type PlatformLinksResponse, type Release, type ReleaseTrack, type ResolveInputType, type ResolveRequest, type ResolveResponse, type ResolveResult, SonoVault, SonoVaultError, type SonoVaultOptions, type Stream, type StreamEvent, type StreamStatus, type StreamUpdateResponse, type Track, type TrackArtist, type TrackRelease, type Webhook, paginate, verifyWebhookSignature };
package/dist/index.d.ts CHANGED
@@ -30,8 +30,36 @@ interface Track {
30
30
  artists: TrackArtist[];
31
31
  isrc: string | null;
32
32
  duration: number | null;
33
- genre: string | null;
34
- subgenre: string | null;
33
+ /** Canonical genres. Empty array when the track is unclassified. */
34
+ genre: string[];
35
+ /** Canonical subgenres. Empty array when none apply. */
36
+ subgenre: string[];
37
+ }
38
+ /**
39
+ * A track as embedded in a release, from `GET /v1/releases/:id`.
40
+ *
41
+ * Same as {@link Track} minus the `releases` array (the release is the object
42
+ * you are already looking at), plus this track's position on that release.
43
+ */
44
+ interface ReleaseTrack {
45
+ id: number;
46
+ title: string;
47
+ artists: TrackArtist[];
48
+ isrc: string | null;
49
+ duration: number | null;
50
+ /** Canonical genres. Empty array when the track is unclassified. */
51
+ genre: string[];
52
+ /** Canonical subgenres. Empty array when none apply. */
53
+ subgenre: string[];
54
+ /** Disc the track sits on, counting from 1. Null when the position is unknown. */
55
+ disc_number: number | null;
56
+ /**
57
+ * Position on this release, counting from 1 within its disc. A position
58
+ * belongs to the pairing of track and release rather than to the track, so
59
+ * the same recording can be track 6 on an album and track 2 on a
60
+ * compilation. Null when the position is unknown.
61
+ */
62
+ track_number: number | null;
35
63
  }
36
64
  /** A cursor-paginated page. `next_cursor` is null on the last page. */
37
65
  interface Page<T> {
@@ -41,6 +69,18 @@ interface Page<T> {
41
69
  interface Artist {
42
70
  id: number;
43
71
  name: string;
72
+ /** Country of origin, in English. Null when unknown. */
73
+ country?: string | null;
74
+ /** Year the artist or group started, or birth year for a solo act. */
75
+ formation_year?: number | null;
76
+ /** Full ISO date, present only when day-level precision is known. */
77
+ formation_date?: string | null;
78
+ /** Platform to handle or URL. Which keys appear varies by artist. */
79
+ social_links?: Record<string, string> | null;
80
+ /** Wikidata entity ID, e.g. `Q185828`. Null when unmapped. */
81
+ wikidata_id?: string | null;
82
+ /** MusicBrainz artist MBID. Null when unmapped. */
83
+ musicbrainz_id?: string | null;
44
84
  [key: string]: unknown;
45
85
  }
46
86
  interface Label {
@@ -60,16 +100,33 @@ interface Release {
60
100
  name: string;
61
101
  } | null;
62
102
  release_date?: string | null;
63
- tracks?: Track[];
103
+ /**
104
+ * MusicBrainz release MBIDs, sorted. An array rather than a single value
105
+ * because a SonoVault release groups every edition of an album and each
106
+ * edition carries its own MBID, so you can pick the edition you need. Empty
107
+ * when unmapped. Only returned by `releases.get()`.
108
+ */
109
+ musicbrainz_release_ids?: string[];
110
+ /**
111
+ * MusicBrainz release-group MBIDs: the identity of the album across all its
112
+ * editions, as opposed to any one pressing. Usually a single entry. Empty
113
+ * when unmapped. Only returned by `releases.get()`.
114
+ */
115
+ musicbrainz_release_group_ids?: string[];
116
+ /**
117
+ * The tracklist, in playing order (disc, then track number), with any track
118
+ * whose position is unknown last.
119
+ */
120
+ tracks?: ReleaseTrack[];
64
121
  [key: string]: unknown;
65
122
  }
66
123
  interface Genre {
67
124
  id: number;
68
125
  name: string;
69
- subgenres?: {
70
- id: number;
71
- name: string;
72
- }[];
126
+ /** Whether this is a top-level genre or a subgenre. */
127
+ type: "main" | "subgenre";
128
+ /** Name of the parent genre; null for a top-level genre. */
129
+ parent: string | null;
73
130
  [key: string]: unknown;
74
131
  }
75
132
  /** A track's ID on an external platform, with a deep link. */
@@ -81,6 +138,8 @@ interface PlatformLink {
81
138
  interface PlatformLinksResponse {
82
139
  track_id: number;
83
140
  title: string;
141
+ /** One representative ISRC for the track; null when none is known. */
142
+ isrc: string | null;
84
143
  links: PlatformLink[];
85
144
  [key: string]: unknown;
86
145
  }
@@ -135,11 +194,44 @@ interface IdentifyResponse {
135
194
  }
136
195
  interface Stream {
137
196
  id: string;
138
- url?: string;
139
- name?: string;
140
- status?: string;
197
+ url: string;
198
+ name: string | null;
199
+ status: "active" | "stopped";
200
+ detection_mode: "precise" | "balanced" | "broad";
201
+ /** Whether we email you when this stream goes down and when it recovers. */
202
+ outage_notifications: boolean;
203
+ created_at: string;
204
+ stopped_at: string | null;
141
205
  [key: string]: unknown;
142
206
  }
207
+ /**
208
+ * A stream's live state, as returned by `streams.get()`: the stream fields plus
209
+ * what is playing right now.
210
+ */
211
+ interface StreamStatus extends Stream {
212
+ /** What the monitor is doing now: `pending`, `running`, `errored` or `stopped`. */
213
+ runtime_status: string;
214
+ /** Why it is in that state (e.g. an auth wall on the host); null when it is fine. */
215
+ status_reason: string | null;
216
+ /** Null during ad breaks, talk, or audio we cannot place. */
217
+ now_playing: {
218
+ track: Track;
219
+ started_at: string;
220
+ } | null;
221
+ last_recognized_at: string | null;
222
+ /** Recognition tuning hint in force; null means auto (all recognisers). */
223
+ format: "electronic" | "classical" | "pop" | null;
224
+ }
225
+ /**
226
+ * The response to `streams.update()`. The API echoes back only the fields you
227
+ * changed, so everything but `id` is optional.
228
+ */
229
+ interface StreamUpdateResponse {
230
+ id: string;
231
+ format?: "electronic" | "classical" | "pop" | null;
232
+ detection_mode?: "precise" | "balanced" | "broad";
233
+ outage_notifications?: boolean;
234
+ }
143
235
  interface Webhook {
144
236
  id: string;
145
237
  url: string;
@@ -313,8 +405,8 @@ declare class SonoVault {
313
405
  list: () => Promise<{
314
406
  streams: Stream[];
315
407
  }>;
316
- get: (id: string) => Promise<Stream>;
317
- update: (id: string, body: Record<string, unknown>) => Promise<Stream>;
408
+ get: (id: string) => Promise<StreamStatus>;
409
+ update: (id: string, body: Record<string, unknown>) => Promise<StreamUpdateResponse>;
318
410
  history: (id: string, params?: {
319
411
  since?: string;
320
412
  }) => Promise<Record<string, unknown>>;
@@ -413,4 +505,4 @@ declare function verifyWebhookSignature(options: {
413
505
  */
414
506
  declare function paginate<T>(fetchPage: (cursor: string | undefined) => Promise<Page<T>>): AsyncGenerator<T>;
415
507
 
416
- export { type Artist, type Genre, type IdentifyResponse, type IdentifyResult, type IswcLookupResponse, type Label, type Page, type PlatformLink, type PlatformLinksResponse, type Release, type ResolveInputType, type ResolveRequest, type ResolveResponse, type ResolveResult, SonoVault, SonoVaultError, type SonoVaultOptions, type Stream, type StreamEvent, type Track, type TrackArtist, type TrackRelease, type Webhook, paginate, verifyWebhookSignature };
508
+ export { type Artist, type Genre, type IdentifyResponse, type IdentifyResult, type IswcLookupResponse, type Label, type Page, type PlatformLink, type PlatformLinksResponse, type Release, type ReleaseTrack, type ResolveInputType, type ResolveRequest, type ResolveResponse, type ResolveResult, SonoVault, SonoVaultError, type SonoVaultOptions, type Stream, type StreamEvent, type StreamStatus, type StreamUpdateResponse, type Track, type TrackArtist, type TrackRelease, type Webhook, paginate, verifyWebhookSignature };
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ var SonoVaultError = class extends Error {
21
21
  };
22
22
 
23
23
  // src/version.ts
24
- var VERSION = "2.0.0";
24
+ var VERSION = "4.0.0";
25
25
 
26
26
  // src/client.ts
27
27
  var SonoVault = class {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonovault",
3
- "version": "2.0.0",
3
+ "version": "4.0.0",
4
4
  "description": "TypeScript/Node client for the SonoVault music metadata API — ISRC, ISWC, genre, labels, release dates, and cross-platform IDs for 93M+ tracks.",
5
5
  "keywords": [
6
6
  "music",