@audd/sdk 1.4.7 → 1.5.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.
@@ -0,0 +1,251 @@
1
+ interface HttpResponse {
2
+ jsonBody: unknown;
3
+ httpStatus: number;
4
+ requestId: string | null;
5
+ rawText: string;
6
+ }
7
+ type FetchLike = typeof globalThis.fetch;
8
+ interface HttpClientOptions {
9
+ apiToken: string;
10
+ fetch?: FetchLike;
11
+ /** Per-call timeout in ms. Defaults: 60_000 standard, 3_600_000 enterprise. */
12
+ defaultTimeoutMs?: number;
13
+ }
14
+ /**
15
+ * Form-data field value. Strings go through directly; Blob carries binary
16
+ * payloads with a filename when constructed via `new File()`.
17
+ */
18
+ type FormFieldValue = string | Blob | undefined;
19
+ declare class HttpClient {
20
+ private apiToken;
21
+ private readonly fetchImpl;
22
+ private readonly defaultTimeoutMs;
23
+ constructor(opts: HttpClientOptions);
24
+ /** Atomically swap the token used for subsequent requests. */
25
+ setApiToken(newToken: string): void;
26
+ postForm(url: string, fields: Record<string, FormFieldValue>, opts?: {
27
+ timeoutMs?: number;
28
+ signal?: AbortSignal;
29
+ }): Promise<HttpResponse>;
30
+ get(url: string, params: Record<string, string | undefined>, opts?: {
31
+ timeoutMs?: number;
32
+ signal?: AbortSignal;
33
+ }): Promise<HttpResponse>;
34
+ private send;
35
+ }
36
+
37
+ /**
38
+ * Typed models. Forward-compatible: each model captures unknown keys into
39
+ * `extras`, mirroring audd-python's Pydantic `extra="allow"` pattern.
40
+ */
41
+ /** Streaming providers supported by the lis.tn redirect helper. */
42
+ type StreamingProvider = "spotify" | "apple_music" | "deezer" | "napster" | "youtube";
43
+ interface RecognitionResult {
44
+ /** Always present on a match. */
45
+ timecode: string;
46
+ /** Set on custom-catalog matches. */
47
+ audioId?: number | undefined;
48
+ artist?: string | undefined;
49
+ title?: string | undefined;
50
+ album?: string | undefined;
51
+ releaseDate?: string | undefined;
52
+ label?: string | undefined;
53
+ songLink?: string | undefined;
54
+ isrc?: string | undefined;
55
+ upc?: string | undefined;
56
+ appleMusic?: Record<string, unknown> | undefined;
57
+ spotify?: Record<string, unknown> | undefined;
58
+ deezer?: Record<string, unknown> | undefined;
59
+ napster?: Record<string, unknown> | undefined;
60
+ musicbrainz?: ReadonlyArray<Record<string, unknown>> | undefined;
61
+ /** Forward-compat: any unknown keys from the server. */
62
+ extras: Record<string, unknown>;
63
+ /** Full unparsed payload for the caller's own inspection. */
64
+ rawResponse: Record<string, unknown>;
65
+ /** True when `audioId` is set (custom-catalog match). */
66
+ readonly isCustomMatch: boolean;
67
+ /** True when `audioId` is unset and `artist` or `title` are present. */
68
+ readonly isPublicMatch: boolean;
69
+ /** Cover-art URL for `lis.tn`-hosted song_links, else `null`. */
70
+ readonly thumbnailUrl: string | null;
71
+ /**
72
+ * Direct or redirect URL for a streaming provider, with smart fallback.
73
+ *
74
+ * Resolution order:
75
+ * 1. Direct URL from the metadata block (e.g. `apple_music.url`,
76
+ * `spotify.external_urls.spotify`, `deezer.link`, `napster.href`) when
77
+ * the user requested that provider via `return=`.
78
+ * 2. lis.tn redirect (`{songLink}?{provider}`) when `songLink` is on lis.tn.
79
+ * 3. `null` otherwise. YouTube has only the lis.tn-redirect path.
80
+ */
81
+ streamingUrl(provider: StreamingProvider): string | null;
82
+ /** Map of every provider with a resolvable URL — direct or via lis.tn redirect. */
83
+ streamingUrls(): Partial<Record<StreamingProvider, string>>;
84
+ /**
85
+ * First available 30-second preview URL across providers, in priority order:
86
+ * `apple_music.previews[0].url` → `spotify.preview_url` → `deezer.preview`.
87
+ *
88
+ * **Note:** previews are governed by the respective providers' terms of use.
89
+ * The SDK consumer is responsible for honoring those terms (caching limits,
90
+ * attribution, redistribution constraints).
91
+ */
92
+ previewUrl(): string | null;
93
+ }
94
+ interface EnterpriseMatch {
95
+ score: number;
96
+ timecode: string;
97
+ artist?: string | undefined;
98
+ title?: string | undefined;
99
+ album?: string | undefined;
100
+ releaseDate?: string | undefined;
101
+ label?: string | undefined;
102
+ isrc?: string | undefined;
103
+ upc?: string | undefined;
104
+ songLink?: string | undefined;
105
+ startOffset?: number | undefined;
106
+ endOffset?: number | undefined;
107
+ extras: Record<string, unknown>;
108
+ rawResponse: Record<string, unknown>;
109
+ readonly thumbnailUrl: string | null;
110
+ /** lis.tn redirect URL for the given streaming provider, or null if `songLink` is non-lis.tn. */
111
+ streamingUrl(provider: StreamingProvider): string | null;
112
+ /** All providers with a resolvable lis.tn redirect URL (or empty when `songLink` is off lis.tn). */
113
+ streamingUrls(): Partial<Record<StreamingProvider, string>>;
114
+ }
115
+ interface EnterpriseChunkResult {
116
+ songs: EnterpriseMatch[];
117
+ offset: string;
118
+ extras: Record<string, unknown>;
119
+ rawResponse: Record<string, unknown>;
120
+ }
121
+ interface Stream {
122
+ radioId: number;
123
+ url: string;
124
+ streamRunning: boolean;
125
+ longpollCategory?: string | undefined;
126
+ extras: Record<string, unknown>;
127
+ rawResponse: Record<string, unknown>;
128
+ }
129
+ /**
130
+ * One candidate song in a recognition match.
131
+ *
132
+ * Almost every match has exactly one Song; the rare extra candidates that
133
+ * appear under {@link StreamCallbackMatch.alternatives} may have a *different*
134
+ * artist or title from the top song — they're variant catalog releases of the
135
+ * same recording (e.g. a "feat." credit vs. the bare-artist re-release, or
136
+ * regional edits with different titles), not lower-confidence guesses at the
137
+ * same track.
138
+ */
139
+ interface StreamCallbackSong {
140
+ artist: string;
141
+ title: string;
142
+ score: number;
143
+ album?: string | undefined;
144
+ releaseDate?: string | undefined;
145
+ label?: string | undefined;
146
+ songLink?: string | undefined;
147
+ isrc?: string | undefined;
148
+ upc?: string | undefined;
149
+ appleMusic?: Record<string, unknown> | undefined;
150
+ spotify?: Record<string, unknown> | undefined;
151
+ deezer?: Record<string, unknown> | undefined;
152
+ napster?: Record<string, unknown> | undefined;
153
+ musicbrainz?: ReadonlyArray<Record<string, unknown>> | undefined;
154
+ extras: Record<string, unknown>;
155
+ }
156
+ /**
157
+ * One recognition event from a stream callback or longpoll.
158
+ *
159
+ * The top match lives in {@link song}; rare extra candidates live in
160
+ * {@link alternatives}. Alternatives entries may have a different artist or
161
+ * title from the top song — they're variant catalog releases of the same
162
+ * recording, not lower-confidence guesses at the same track.
163
+ */
164
+ interface StreamCallbackMatch {
165
+ radioId: number;
166
+ timestamp?: string | undefined;
167
+ playLength?: number | undefined;
168
+ /** Top match — always present. */
169
+ song: StreamCallbackSong;
170
+ /** Variant catalog releases (may have different artist/title); empty array when only one match. */
171
+ alternatives: StreamCallbackSong[];
172
+ extras: Record<string, unknown>;
173
+ rawResponse: Record<string, unknown>;
174
+ }
175
+ interface StreamCallbackNotification {
176
+ radioId: number;
177
+ streamRunning?: boolean | undefined;
178
+ notificationCode: number;
179
+ notificationMessage: string;
180
+ /** Outer `time` field on the callback envelope (epoch seconds). */
181
+ time?: number | undefined;
182
+ extras: Record<string, unknown>;
183
+ rawResponse: Record<string, unknown>;
184
+ }
185
+ interface LyricsResult {
186
+ artist: string;
187
+ title: string;
188
+ lyrics?: string | undefined;
189
+ songId?: number | undefined;
190
+ fullTitle?: string | undefined;
191
+ artistId?: number | undefined;
192
+ songLink?: string | undefined;
193
+ media?: string | undefined;
194
+ extras: Record<string, unknown>;
195
+ rawResponse: Record<string, unknown>;
196
+ }
197
+
198
+ /**
199
+ * Shared longpoll loop + handle, used by both the authenticated `Streams`
200
+ * namespace (token in URL via `HttpClient.get`) and the tokenless
201
+ * `LongpollConsumer` exported from `audd/longpoll`.
202
+ *
203
+ * Browser-safe: no node:crypto, no node:fs, no node:http imports. The whole
204
+ * file relies on `fetch`-style I/O the caller injects.
205
+ */
206
+
207
+ /**
208
+ * Active long-poll subscription. Two typed `AsyncIterable`s carry the
209
+ * happy-path output and a third carries any terminal error.
210
+ *
211
+ * Consume `matches` and `notifications` independently or in parallel:
212
+ *
213
+ * ```ts
214
+ * const poll = await audd.streams.longpoll(category);
215
+ * for await (const m of poll.matches) {
216
+ * console.log(m.song.artist, m.song.title);
217
+ * }
218
+ * ```
219
+ *
220
+ * Concurrent consumption:
221
+ *
222
+ * ```ts
223
+ * await Promise.all([
224
+ * (async () => { for await (const m of poll.matches) {} })(),
225
+ * (async () => { for await (const n of poll.notifications) {} })(),
226
+ * (async () => { for await (const e of poll.errors) console.error(e); })(),
227
+ * ]);
228
+ * ```
229
+ *
230
+ * `close()` (or the `await using` resource-management form) tears down the
231
+ * background loop and closes all three iterables.
232
+ */
233
+ interface LongpollPoll {
234
+ /** Recognition events. */
235
+ readonly matches: AsyncIterable<StreamCallbackMatch>;
236
+ /** Stream-lifecycle events ("stream stopped", "can't connect", ...). */
237
+ readonly notifications: AsyncIterable<StreamCallbackNotification>;
238
+ /**
239
+ * Terminal errors. The poll keeps polling on transient HTTP/JSON failures
240
+ * (subject to the retry policy); errors that surface here are the ones the
241
+ * loop gives up on. Each fired error is followed by closure of all three
242
+ * iterables.
243
+ */
244
+ readonly errors: AsyncIterable<Error>;
245
+ /** Stop the background loop. Idempotent. */
246
+ close(): void;
247
+ /** `await using` support — calls `close()`. */
248
+ [Symbol.asyncDispose](): Promise<void>;
249
+ }
250
+
251
+ export { type EnterpriseMatch as E, type FetchLike as F, HttpClient as H, type LongpollPoll as L, type RecognitionResult as R, type StreamCallbackMatch as S, type StreamCallbackNotification as a, type Stream as b, type LyricsResult as c, type EnterpriseChunkResult as d, type StreamCallbackSong as e, type StreamingProvider as f };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@audd/sdk",
3
- "version": "1.4.7",
3
+ "version": "1.5.0",
4
4
  "description": "Official TypeScript SDK for the AudD music recognition API.",
5
5
  "license": "MIT",
6
6
  "author": "AudD <api@audd.io>",
@@ -1,37 +0,0 @@
1
- interface HttpResponse {
2
- jsonBody: unknown;
3
- httpStatus: number;
4
- requestId: string | null;
5
- rawText: string;
6
- }
7
- type FetchLike = typeof globalThis.fetch;
8
- interface HttpClientOptions {
9
- apiToken: string;
10
- fetch?: FetchLike;
11
- /** Per-call timeout in ms. Defaults: 60_000 standard, 3_600_000 enterprise. */
12
- defaultTimeoutMs?: number;
13
- }
14
- /**
15
- * Form-data field value. Strings go through directly; Blob carries binary
16
- * payloads with a filename when constructed via `new File()`.
17
- */
18
- type FormFieldValue = string | Blob | undefined;
19
- declare class HttpClient {
20
- private apiToken;
21
- private readonly fetchImpl;
22
- private readonly defaultTimeoutMs;
23
- constructor(opts: HttpClientOptions);
24
- /** Atomically swap the token used for subsequent requests. */
25
- setApiToken(newToken: string): void;
26
- postForm(url: string, fields: Record<string, FormFieldValue>, opts?: {
27
- timeoutMs?: number;
28
- signal?: AbortSignal;
29
- }): Promise<HttpResponse>;
30
- get(url: string, params: Record<string, string | undefined>, opts?: {
31
- timeoutMs?: number;
32
- signal?: AbortSignal;
33
- }): Promise<HttpResponse>;
34
- private send;
35
- }
36
-
37
- export { type FetchLike as F, HttpClient as H };
@@ -1,37 +0,0 @@
1
- interface HttpResponse {
2
- jsonBody: unknown;
3
- httpStatus: number;
4
- requestId: string | null;
5
- rawText: string;
6
- }
7
- type FetchLike = typeof globalThis.fetch;
8
- interface HttpClientOptions {
9
- apiToken: string;
10
- fetch?: FetchLike;
11
- /** Per-call timeout in ms. Defaults: 60_000 standard, 3_600_000 enterprise. */
12
- defaultTimeoutMs?: number;
13
- }
14
- /**
15
- * Form-data field value. Strings go through directly; Blob carries binary
16
- * payloads with a filename when constructed via `new File()`.
17
- */
18
- type FormFieldValue = string | Blob | undefined;
19
- declare class HttpClient {
20
- private apiToken;
21
- private readonly fetchImpl;
22
- private readonly defaultTimeoutMs;
23
- constructor(opts: HttpClientOptions);
24
- /** Atomically swap the token used for subsequent requests. */
25
- setApiToken(newToken: string): void;
26
- postForm(url: string, fields: Record<string, FormFieldValue>, opts?: {
27
- timeoutMs?: number;
28
- signal?: AbortSignal;
29
- }): Promise<HttpResponse>;
30
- get(url: string, params: Record<string, string | undefined>, opts?: {
31
- timeoutMs?: number;
32
- signal?: AbortSignal;
33
- }): Promise<HttpResponse>;
34
- private send;
35
- }
36
-
37
- export { type FetchLike as F, HttpClient as H };