@audd/sdk 1.5.7 → 1.5.9

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/longpoll.cjs CHANGED
@@ -394,7 +394,7 @@ async function retry(fn, policy) {
394
394
  }
395
395
 
396
396
  // src/version.ts
397
- var VERSION = "1.4.6";
397
+ var VERSION = "1.5.8";
398
398
 
399
399
  // src/userAgent.ts
400
400
  function userAgent() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/models.ts","../src/longpollCore.ts","../src/retry.ts","../src/version.ts","../src/userAgent.ts","../src/longpoll.ts"],"names":[],"mappings":"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","file":"longpoll.cjs","sourcesContent":["/** Exception hierarchy for AudD API errors. */\n\nexport interface AudDApiErrorFields {\n errorCode: number;\n message: string;\n httpStatus: number;\n requestId: string | null;\n requestedParams: Record<string, unknown>;\n requestMethod: string | null;\n brandedMessage: string | null;\n rawResponse: unknown;\n}\n\nexport type AudDApiErrorInit = Partial<AudDApiErrorFields> &\n Pick<AudDApiErrorFields, \"errorCode\" | \"message\" | \"httpStatus\">;\n\n/** Base for everything thrown by this SDK. */\nexport class AudDError extends Error {\n override name = \"AudDError\";\n}\n\n/** Server returned `status: error`. Carries the AudD error code + the full echo. */\nexport class AudDAPIError extends AudDError {\n override name = \"AudDAPIError\";\n errorCode: number;\n httpStatus: number;\n requestId: string | null;\n requestedParams: Record<string, unknown>;\n requestMethod: string | null;\n brandedMessage: string | null;\n rawResponse: unknown;\n /** Original `error_message` from the server. (`Error.message` may be overridden by subclasses.) */\n serverMessage: string;\n\n constructor(init: AudDApiErrorInit) {\n super(`[#${init.errorCode}] ${init.message}`);\n this.errorCode = init.errorCode;\n this.serverMessage = init.message;\n this.httpStatus = init.httpStatus;\n this.requestId = init.requestId ?? null;\n this.requestedParams = init.requestedParams ?? {};\n this.requestMethod = init.requestMethod ?? null;\n this.brandedMessage = init.brandedMessage ?? null;\n this.rawResponse = init.rawResponse ?? null;\n }\n}\n\nexport class AudDAuthenticationError extends AudDAPIError {\n override name = \"AudDAuthenticationError\";\n}\nexport class AudDQuotaError extends AudDAPIError {\n override name = \"AudDQuotaError\";\n}\nexport class AudDSubscriptionError extends AudDAPIError {\n override name = \"AudDSubscriptionError\";\n}\nexport class AudDCustomCatalogAccessError extends AudDSubscriptionError {\n override name = \"AudDCustomCatalogAccessError\";\n}\nexport class AudDInvalidRequestError extends AudDAPIError {\n override name = \"AudDInvalidRequestError\";\n}\nexport class AudDInvalidAudioError extends AudDAPIError {\n override name = \"AudDInvalidAudioError\";\n}\nexport class AudDRateLimitError extends AudDAPIError {\n override name = \"AudDRateLimitError\";\n}\nexport class AudDStreamLimitError extends AudDAPIError {\n override name = \"AudDStreamLimitError\";\n}\nexport class AudDNotReleasedError extends AudDAPIError {\n override name = \"AudDNotReleasedError\";\n}\nexport class AudDBlockedError extends AudDAPIError {\n override name = \"AudDBlockedError\";\n}\nexport class AudDNeedsUpdateError extends AudDAPIError {\n override name = \"AudDNeedsUpdateError\";\n}\nexport class AudDServerError extends AudDAPIError {\n override name = \"AudDServerError\";\n}\n\nexport class AudDConnectionError extends AudDError {\n override name = \"AudDConnectionError\";\n override cause?: unknown;\n constructor(message: string, cause?: unknown) {\n super(message);\n this.cause = cause;\n }\n}\n\nexport class AudDSerializationError extends AudDError {\n override name = \"AudDSerializationError\";\n rawText: string;\n constructor(message: string, rawText = \"\") {\n super(message);\n this.rawText = rawText;\n }\n}\n\nexport type AudDAPIErrorCtor = new (init: AudDApiErrorInit) => AudDAPIError;\n\nconst CODE_MAP: Record<number, AudDAPIErrorCtor> = {\n 900: AudDAuthenticationError,\n 901: AudDAuthenticationError,\n 903: AudDAuthenticationError,\n 902: AudDQuotaError,\n 904: AudDSubscriptionError,\n 905: AudDSubscriptionError,\n 50: AudDInvalidRequestError,\n 51: AudDInvalidRequestError,\n 600: AudDInvalidRequestError,\n 601: AudDInvalidRequestError,\n 602: AudDInvalidRequestError,\n 700: AudDInvalidRequestError,\n 701: AudDInvalidRequestError,\n 702: AudDInvalidRequestError,\n 906: AudDInvalidRequestError,\n 300: AudDInvalidAudioError,\n 400: AudDInvalidAudioError,\n 500: AudDInvalidAudioError,\n 610: AudDStreamLimitError,\n 611: AudDRateLimitError,\n 907: AudDNotReleasedError,\n 19: AudDBlockedError,\n 31337: AudDBlockedError,\n 20: AudDNeedsUpdateError,\n 100: AudDServerError,\n 1000: AudDServerError,\n};\n\nexport function errorClassForCode(code: number): AudDAPIErrorCtor {\n return CODE_MAP[code] ?? AudDServerError;\n}\n\nfunction brandedMessageOf(result: unknown): string | null {\n if (typeof result !== \"object\" || result === null) return null;\n const r = result as { artist?: unknown; title?: unknown };\n const parts: string[] = [];\n if (typeof r.artist === \"string\" && r.artist.length > 0) parts.push(r.artist);\n if (typeof r.title === \"string\" && r.title.length > 0) parts.push(r.title);\n return parts.length === 0 ? null : parts.join(\" — \");\n}\n\nexport interface ServerErrorBody {\n error?: { error_code?: number | undefined; error_message?: string | undefined } | undefined;\n result?: unknown;\n request_params?: Record<string, unknown> | undefined;\n requested_params?: Record<string, unknown> | undefined;\n request_api_method?: string | undefined;\n}\n\nexport interface RaiseFromErrorOpts {\n httpStatus: number;\n requestId: string | null;\n customCatalogContext?: boolean;\n}\n\nconst CUSTOM_CATALOG_PREFIX =\n \"Adding songs to your custom catalog requires enterprise access that isn't enabled on your account.\\n\\n\" +\n \"Note: the custom-catalog endpoint is for adding songs to your private fingerprint database, not for music recognition. \" +\n \"If you intended to identify music, use recognize(...) (or recognizeEnterprise(...) for files longer than 25 seconds) instead.\\n\\n\" +\n \"To request custom-catalog access, contact api@audd.io.\\n\\n\";\n\nexport function raiseFromErrorResponse(body: ServerErrorBody, opts: RaiseFromErrorOpts): never {\n const code = body.error?.error_code ?? 0;\n const message = body.error?.error_message ?? \"\";\n const requestedParams = body.request_params ?? body.requested_params ?? {};\n const requestMethod = body.request_api_method ?? null;\n const branded = brandedMessageOf(body.result);\n\n const fields: AudDApiErrorFields = {\n errorCode: code,\n message,\n httpStatus: opts.httpStatus,\n requestId: opts.requestId,\n requestedParams,\n requestMethod,\n brandedMessage: branded,\n rawResponse: body,\n };\n\n const Cls = errorClassForCode(code);\n if (opts.customCatalogContext === true && Cls === AudDSubscriptionError) {\n const overridden = `${CUSTOM_CATALOG_PREFIX}[Server message: ${message}]`;\n throw new AudDCustomCatalogAccessError({ ...fields, message: overridden });\n }\n throw new Cls(fields);\n}\n","/**\n * Typed models. Forward-compatible: each model captures unknown keys into\n * `extras`, mirroring audd-python's Pydantic `extra=\"allow\"` pattern.\n */\n\nfunction pickExtras(\n raw: Record<string, unknown>,\n knownKeys: ReadonlyArray<string>,\n): Record<string, unknown> {\n const known = new Set(knownKeys);\n const extras: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(raw)) {\n if (!known.has(k)) extras[k] = v;\n }\n return extras;\n}\n\nfunction asObject(raw: unknown): Record<string, unknown> | undefined {\n if (typeof raw === \"object\" && raw !== null && !Array.isArray(raw)) {\n return raw as Record<string, unknown>;\n }\n return undefined;\n}\n\nfunction requireObject(raw: unknown, what: string): Record<string, unknown> {\n const o = asObject(raw);\n if (o === undefined) throw new TypeError(`${what}: expected object`);\n return o;\n}\n\nfunction asString(v: unknown): string | undefined {\n return typeof v === \"string\" ? v : undefined;\n}\nfunction asNumber(v: unknown): number | undefined {\n return typeof v === \"number\" ? v : undefined;\n}\nfunction asBoolean(v: unknown): boolean | undefined {\n return typeof v === \"boolean\" ? v : undefined;\n}\n\n/** Streaming providers supported by the lis.tn redirect helper. */\nexport type StreamingProvider =\n | \"spotify\"\n | \"apple_music\"\n | \"deezer\"\n | \"napster\"\n | \"youtube\";\n\nconst STREAMING_PROVIDERS: readonly StreamingProvider[] = [\n \"spotify\",\n \"apple_music\",\n \"deezer\",\n \"napster\",\n \"youtube\",\n] as const;\n\nfunction lisTnStreamingUrl(songLink: string | undefined, provider: string): string | null {\n if (songLink === undefined || songLink === \"\") return null;\n let parsed: URL;\n try {\n parsed = new URL(songLink);\n } catch {\n return null;\n }\n if (parsed.hostname !== \"lis.tn\") return null;\n const sep = parsed.search ? \"&\" : \"?\";\n return `${songLink}${sep}${provider}`;\n}\n\nexport interface RecognitionResult {\n /** Always present on a match. */\n timecode: string;\n /** Set on custom-catalog matches. */\n audioId?: number | undefined;\n artist?: string | undefined;\n title?: string | undefined;\n album?: string | undefined;\n releaseDate?: string | undefined;\n label?: string | undefined;\n songLink?: string | undefined;\n isrc?: string | undefined;\n upc?: string | undefined;\n appleMusic?: Record<string, unknown> | undefined;\n spotify?: Record<string, unknown> | undefined;\n deezer?: Record<string, unknown> | undefined;\n napster?: Record<string, unknown> | undefined;\n musicbrainz?: ReadonlyArray<Record<string, unknown>> | undefined;\n /** Forward-compat: any unknown keys from the server. */\n extras: Record<string, unknown>;\n /** Full unparsed payload for the caller's own inspection. */\n rawResponse: Record<string, unknown>;\n /** True when `audioId` is set (custom-catalog match). */\n readonly isCustomMatch: boolean;\n /** True when `audioId` is unset and `artist` or `title` are present. */\n readonly isPublicMatch: boolean;\n /** Cover-art URL for `lis.tn`-hosted song_links, else `null`. */\n readonly thumbnailUrl: string | null;\n /**\n * Direct or redirect URL for a streaming provider, with smart fallback.\n *\n * Resolution order:\n * 1. Direct URL from the metadata block (e.g. `apple_music.url`,\n * `spotify.external_urls.spotify`, `deezer.link`, `napster.href`) when\n * the user requested that provider via `return=`.\n * 2. lis.tn redirect (`{songLink}?{provider}`) when `songLink` is on lis.tn.\n * 3. `null` otherwise. YouTube has only the lis.tn-redirect path.\n */\n streamingUrl(provider: StreamingProvider): string | null;\n /** Map of every provider with a resolvable URL — direct or via lis.tn redirect. */\n streamingUrls(): Partial<Record<StreamingProvider, string>>;\n /**\n * First available 30-second preview URL across providers, in priority order:\n * `apple_music.previews[0].url` → `spotify.preview_url` → `deezer.preview`.\n *\n * **Note:** previews are governed by the respective providers' terms of use.\n * The SDK consumer is responsible for honoring those terms (caching limits,\n * attribution, redistribution constraints).\n */\n previewUrl(): string | null;\n}\n\nfunction directStreamingUrl(\n result: Pick<RecognitionResult, \"appleMusic\" | \"spotify\" | \"deezer\" | \"napster\">,\n provider: string,\n): string | null {\n if (provider === \"apple_music\" && result.appleMusic !== undefined) {\n const url = result.appleMusic[\"url\"];\n if (typeof url === \"string\" && url.length > 0) return url;\n } else if (provider === \"spotify\" && result.spotify !== undefined) {\n const ext = result.spotify[\"external_urls\"];\n if (typeof ext === \"object\" && ext !== null) {\n const sp = (ext as Record<string, unknown>)[\"spotify\"];\n if (typeof sp === \"string\" && sp.length > 0) return sp;\n }\n const uri = result.spotify[\"uri\"];\n if (typeof uri === \"string\" && uri.length > 0) return uri;\n } else if (provider === \"deezer\" && result.deezer !== undefined) {\n const link = result.deezer[\"link\"];\n if (typeof link === \"string\" && link.length > 0) return link;\n } else if (provider === \"napster\" && result.napster !== undefined) {\n const href = result.napster[\"href\"];\n if (typeof href === \"string\" && href.length > 0) return href;\n }\n return null;\n}\n\nfunction previewFrom(result: Pick<RecognitionResult, \"appleMusic\" | \"spotify\" | \"deezer\">): string | null {\n if (result.appleMusic !== undefined) {\n const previews = result.appleMusic[\"previews\"];\n if (Array.isArray(previews) && previews.length > 0) {\n const first = previews[0];\n if (typeof first === \"object\" && first !== null) {\n const url = (first as Record<string, unknown>)[\"url\"];\n if (typeof url === \"string\" && url.length > 0) return url;\n }\n }\n }\n if (result.spotify !== undefined) {\n const url = result.spotify[\"preview_url\"];\n if (typeof url === \"string\" && url.length > 0) return url;\n }\n if (result.deezer !== undefined) {\n const url = result.deezer[\"preview\"];\n if (typeof url === \"string\" && url.length > 0) return url;\n }\n return null;\n}\n\nconst RECOGNITION_KEYS = [\n \"timecode\",\n \"audio_id\",\n \"artist\",\n \"title\",\n \"album\",\n \"release_date\",\n \"label\",\n \"song_link\",\n \"isrc\",\n \"upc\",\n \"apple_music\",\n \"spotify\",\n \"deezer\",\n \"napster\",\n \"musicbrainz\",\n] as const;\n\nexport function parseRecognitionResult(raw: unknown): RecognitionResult {\n const r = requireObject(raw, \"RecognitionResult\");\n const timecode = asString(r.timecode);\n if (timecode === undefined) {\n throw new TypeError(\"RecognitionResult: timecode missing or not string\");\n }\n const audioId = asNumber(r.audio_id);\n const artist = asString(r.artist);\n const title = asString(r.title);\n const songLink = asString(r.song_link);\n const musicbrainz = Array.isArray(r.musicbrainz)\n ? (r.musicbrainz.filter((x): x is Record<string, unknown> => asObject(x) !== undefined) as\n | Record<string, unknown>[]\n | undefined)\n : undefined;\n\n const result: RecognitionResult = {\n timecode,\n audioId,\n artist,\n title,\n album: asString(r.album),\n releaseDate: asString(r.release_date),\n label: asString(r.label),\n songLink,\n isrc: asString(r.isrc),\n upc: asString(r.upc),\n appleMusic: asObject(r.apple_music),\n spotify: asObject(r.spotify),\n deezer: asObject(r.deezer),\n napster: asObject(r.napster),\n musicbrainz,\n extras: pickExtras(r, RECOGNITION_KEYS),\n rawResponse: r,\n get isCustomMatch() {\n return audioId !== undefined;\n },\n get isPublicMatch() {\n return audioId === undefined && (artist !== undefined || title !== undefined);\n },\n get thumbnailUrl() {\n return lisTnStreamingUrl(songLink, \"thumb\");\n },\n streamingUrl(provider: StreamingProvider): string | null {\n if (!STREAMING_PROVIDERS.includes(provider)) {\n throw new TypeError(\n `Unknown streaming provider: ${String(provider)}. ` +\n `Valid: ${STREAMING_PROVIDERS.join(\", \")}`,\n );\n }\n const direct = directStreamingUrl(result, provider);\n if (direct !== null) return direct;\n return lisTnStreamingUrl(songLink, provider);\n },\n streamingUrls(): Partial<Record<StreamingProvider, string>> {\n const out: Partial<Record<StreamingProvider, string>> = {};\n for (const p of STREAMING_PROVIDERS) {\n const url = result.streamingUrl(p);\n if (url !== null) out[p] = url;\n }\n return out;\n },\n previewUrl(): string | null {\n return previewFrom(result);\n },\n };\n return result;\n}\n\nexport interface EnterpriseMatch {\n score: number;\n timecode: string;\n artist?: string | undefined;\n title?: string | undefined;\n album?: string | undefined;\n releaseDate?: string | undefined;\n label?: string | undefined;\n isrc?: string | undefined;\n upc?: string | undefined;\n songLink?: string | undefined;\n startOffset?: number | undefined;\n endOffset?: number | undefined;\n extras: Record<string, unknown>;\n rawResponse: Record<string, unknown>;\n readonly thumbnailUrl: string | null;\n /** lis.tn redirect URL for the given streaming provider, or null if `songLink` is non-lis.tn. */\n streamingUrl(provider: StreamingProvider): string | null;\n /** All providers with a resolvable lis.tn redirect URL (or empty when `songLink` is off lis.tn). */\n streamingUrls(): Partial<Record<StreamingProvider, string>>;\n}\n\nconst ENTERPRISE_MATCH_KEYS = [\n \"score\",\n \"timecode\",\n \"artist\",\n \"title\",\n \"album\",\n \"release_date\",\n \"label\",\n \"isrc\",\n \"upc\",\n \"song_link\",\n \"start_offset\",\n \"end_offset\",\n] as const;\n\nexport function parseEnterpriseMatch(raw: unknown): EnterpriseMatch {\n const r = requireObject(raw, \"EnterpriseMatch\");\n const score = asNumber(r.score);\n const timecode = asString(r.timecode);\n if (score === undefined) throw new TypeError(\"EnterpriseMatch: score not number\");\n if (timecode === undefined) throw new TypeError(\"EnterpriseMatch: timecode not string\");\n const songLink = asString(r.song_link);\n return {\n score,\n timecode,\n artist: asString(r.artist),\n title: asString(r.title),\n album: asString(r.album),\n releaseDate: asString(r.release_date),\n label: asString(r.label),\n isrc: asString(r.isrc),\n upc: asString(r.upc),\n songLink,\n startOffset: asNumber(r.start_offset),\n endOffset: asNumber(r.end_offset),\n extras: pickExtras(r, ENTERPRISE_MATCH_KEYS),\n rawResponse: r,\n streamingUrl(provider: StreamingProvider): string | null {\n if (!STREAMING_PROVIDERS.includes(provider)) {\n throw new TypeError(`Unknown streaming provider: ${String(provider)}`);\n }\n return lisTnStreamingUrl(songLink, provider);\n },\n streamingUrls(): Partial<Record<StreamingProvider, string>> {\n const out: Partial<Record<StreamingProvider, string>> = {};\n for (const p of STREAMING_PROVIDERS) {\n const url = lisTnStreamingUrl(songLink, p);\n if (url !== null) out[p] = url;\n }\n return out;\n },\n get thumbnailUrl() {\n if (songLink === undefined || songLink === \"\") return null;\n try {\n const parsed = new URL(songLink);\n if (parsed.hostname !== \"lis.tn\") return null;\n const sep = parsed.search ? \"&\" : \"?\";\n return `${songLink}${sep}thumb`;\n } catch {\n return null;\n }\n },\n };\n}\n\nexport interface EnterpriseChunkResult {\n songs: EnterpriseMatch[];\n offset: string;\n extras: Record<string, unknown>;\n rawResponse: Record<string, unknown>;\n}\n\nconst ENTERPRISE_CHUNK_KEYS = [\"songs\", \"offset\"] as const;\n\nexport function parseEnterpriseChunkResult(raw: unknown): EnterpriseChunkResult {\n const r = requireObject(raw, \"EnterpriseChunkResult\");\n const songsRaw = r.songs;\n if (!Array.isArray(songsRaw)) {\n throw new TypeError(\"EnterpriseChunkResult: songs not array\");\n }\n const offset = asString(r.offset);\n if (offset === undefined) throw new TypeError(\"EnterpriseChunkResult: offset not string\");\n return {\n songs: songsRaw.map(parseEnterpriseMatch),\n offset,\n extras: pickExtras(r, ENTERPRISE_CHUNK_KEYS),\n rawResponse: r,\n };\n}\n\nexport interface Stream {\n radioId: number;\n url: string;\n streamRunning: boolean;\n longpollCategory?: string | undefined;\n extras: Record<string, unknown>;\n rawResponse: Record<string, unknown>;\n}\n\nconst STREAM_KEYS = [\"radio_id\", \"url\", \"stream_running\", \"longpoll_category\"] as const;\n\nexport function parseStream(raw: unknown): Stream {\n const r = requireObject(raw, \"Stream\");\n const radioId = asNumber(r.radio_id);\n const url = asString(r.url);\n const streamRunning = asBoolean(r.stream_running);\n if (radioId === undefined) throw new TypeError(\"Stream: radio_id not number\");\n if (url === undefined) throw new TypeError(\"Stream: url not string\");\n if (streamRunning === undefined) throw new TypeError(\"Stream: stream_running not boolean\");\n return {\n radioId,\n url,\n streamRunning,\n longpollCategory: asString(r.longpoll_category),\n extras: pickExtras(r, STREAM_KEYS),\n rawResponse: r,\n };\n}\n\n/**\n * One candidate song in a recognition match.\n *\n * Almost every match has exactly one Song; the rare extra candidates that\n * appear under {@link StreamCallbackMatch.alternatives} may have a *different*\n * artist or title from the top song — they're variant catalog releases of the\n * same recording (e.g. a \"feat.\" credit vs. the bare-artist re-release, or\n * regional edits with different titles), not lower-confidence guesses at the\n * same track.\n */\nexport interface StreamCallbackSong {\n artist: string;\n title: string;\n score: number;\n album?: string | undefined;\n releaseDate?: string | undefined;\n label?: string | undefined;\n songLink?: string | undefined;\n isrc?: string | undefined;\n upc?: string | undefined;\n appleMusic?: Record<string, unknown> | undefined;\n spotify?: Record<string, unknown> | undefined;\n deezer?: Record<string, unknown> | undefined;\n napster?: Record<string, unknown> | undefined;\n musicbrainz?: ReadonlyArray<Record<string, unknown>> | undefined;\n extras: Record<string, unknown>;\n}\n\nconst STREAM_CALLBACK_SONG_KEYS = [\n \"artist\",\n \"title\",\n \"score\",\n \"album\",\n \"release_date\",\n \"label\",\n \"song_link\",\n \"isrc\",\n \"upc\",\n \"apple_music\",\n \"spotify\",\n \"deezer\",\n \"napster\",\n \"musicbrainz\",\n] as const;\n\nfunction parseStreamCallbackSong(raw: unknown): StreamCallbackSong {\n const r = requireObject(raw, \"StreamCallbackSong\");\n const artist = asString(r.artist);\n const title = asString(r.title);\n const score = asNumber(r.score);\n if (artist === undefined) throw new TypeError(\"StreamCallbackSong: artist not string\");\n if (title === undefined) throw new TypeError(\"StreamCallbackSong: title not string\");\n if (score === undefined) throw new TypeError(\"StreamCallbackSong: score not number\");\n const musicbrainz = Array.isArray(r.musicbrainz)\n ? (r.musicbrainz.filter((x): x is Record<string, unknown> => asObject(x) !== undefined) as\n | Record<string, unknown>[]\n | undefined)\n : undefined;\n return {\n artist,\n title,\n score,\n album: asString(r.album),\n releaseDate: asString(r.release_date),\n label: asString(r.label),\n songLink: asString(r.song_link),\n isrc: asString(r.isrc),\n upc: asString(r.upc),\n appleMusic: asObject(r.apple_music),\n spotify: asObject(r.spotify),\n deezer: asObject(r.deezer),\n napster: asObject(r.napster),\n musicbrainz,\n extras: pickExtras(r, STREAM_CALLBACK_SONG_KEYS),\n };\n}\n\n/**\n * One recognition event from a stream callback or longpoll.\n *\n * The top match lives in {@link song}; rare extra candidates live in\n * {@link alternatives}. Alternatives entries may have a different artist or\n * title from the top song — they're variant catalog releases of the same\n * recording, not lower-confidence guesses at the same track.\n */\nexport interface StreamCallbackMatch {\n radioId: number;\n timestamp?: string | undefined;\n playLength?: number | undefined;\n /** Top match — always present. */\n song: StreamCallbackSong;\n /** Variant catalog releases (may have different artist/title); empty array when only one match. */\n alternatives: StreamCallbackSong[];\n extras: Record<string, unknown>;\n rawResponse: Record<string, unknown>;\n}\n\nconst STREAM_CALLBACK_MATCH_KEYS = [\n \"radio_id\",\n \"timestamp\",\n \"play_length\",\n \"results\",\n] as const;\n\nexport function parseStreamCallbackMatch(raw: unknown): StreamCallbackMatch {\n const r = requireObject(raw, \"StreamCallbackMatch\");\n const radioId = asNumber(r.radio_id);\n if (radioId === undefined) throw new TypeError(\"StreamCallbackMatch: radio_id not number\");\n const resultsRaw = r.results;\n if (!Array.isArray(resultsRaw)) throw new TypeError(\"StreamCallbackMatch: results not array\");\n if (resultsRaw.length === 0) throw new TypeError(\"StreamCallbackMatch: results is empty\");\n const songs = resultsRaw.map(parseStreamCallbackSong);\n const [first, ...rest] = songs;\n if (first === undefined) throw new TypeError(\"StreamCallbackMatch: results is empty\");\n return {\n radioId,\n timestamp: asString(r.timestamp),\n playLength: asNumber(r.play_length),\n song: first,\n alternatives: rest,\n extras: pickExtras(r, STREAM_CALLBACK_MATCH_KEYS),\n rawResponse: r,\n };\n}\n\nexport interface StreamCallbackNotification {\n radioId: number;\n streamRunning?: boolean | undefined;\n notificationCode: number;\n notificationMessage: string;\n /** Outer `time` field on the callback envelope (epoch seconds). */\n time?: number | undefined;\n extras: Record<string, unknown>;\n rawResponse: Record<string, unknown>;\n}\n\nconst STREAM_CALLBACK_NOTIFICATION_KEYS = [\n \"radio_id\",\n \"stream_running\",\n \"notification_code\",\n \"notification_message\",\n] as const;\n\nexport function parseStreamCallbackNotification(raw: unknown): StreamCallbackNotification {\n const r = requireObject(raw, \"StreamCallbackNotification\");\n const radioId = asNumber(r.radio_id);\n if (radioId === undefined)\n throw new TypeError(\"StreamCallbackNotification: radio_id not number\");\n const code = asNumber(r.notification_code);\n if (code === undefined)\n throw new TypeError(\"StreamCallbackNotification: notification_code not number\");\n const message = asString(r.notification_message);\n if (message === undefined)\n throw new TypeError(\"StreamCallbackNotification: notification_message not string\");\n return {\n radioId,\n streamRunning: asBoolean(r.stream_running),\n notificationCode: code,\n notificationMessage: message,\n extras: pickExtras(r, STREAM_CALLBACK_NOTIFICATION_KEYS),\n rawResponse: r,\n };\n}\n\nexport interface LyricsResult {\n artist: string;\n title: string;\n lyrics?: string | undefined;\n songId?: number | undefined;\n fullTitle?: string | undefined;\n artistId?: number | undefined;\n songLink?: string | undefined;\n media?: string | undefined;\n extras: Record<string, unknown>;\n rawResponse: Record<string, unknown>;\n}\n\nconst LYRICS_KEYS = [\n \"artist\",\n \"title\",\n \"lyrics\",\n \"song_id\",\n \"full_title\",\n \"artist_id\",\n \"song_link\",\n \"media\",\n] as const;\n\nexport function parseLyricsResult(raw: unknown): LyricsResult {\n const r = requireObject(raw, \"LyricsResult\");\n const artist = asString(r.artist);\n const title = asString(r.title);\n if (artist === undefined) throw new TypeError(\"LyricsResult: artist not string\");\n if (title === undefined) throw new TypeError(\"LyricsResult: title not string\");\n return {\n artist,\n title,\n lyrics: asString(r.lyrics),\n songId: asNumber(r.song_id),\n fullTitle: asString(r.full_title),\n artistId: asNumber(r.artist_id),\n songLink: asString(r.song_link),\n media: asString(r.media),\n extras: pickExtras(r, LYRICS_KEYS),\n rawResponse: r,\n };\n}\n","/**\n * Shared longpoll loop + handle, used by both the authenticated `Streams`\n * namespace (token in URL via `HttpClient.get`) and the tokenless\n * `LongpollConsumer` exported from `audd/longpoll`.\n *\n * Browser-safe: no node:crypto, no node:fs, no node:http imports. The whole\n * file relies on `fetch`-style I/O the caller injects.\n */\n\nimport {\n AudDConnectionError,\n AudDSerializationError,\n AudDServerError,\n} from \"./errors.js\";\nimport type { HttpResponse } from \"./http.js\";\nimport type {\n StreamCallbackMatch,\n StreamCallbackNotification,\n} from \"./models.js\";\nimport {\n parseStreamCallbackMatch,\n parseStreamCallbackNotification,\n} from \"./models.js\";\n\nconst HTTP_CLIENT_ERROR_FLOOR = 400;\n\n/**\n * Active long-poll subscription. Two typed `AsyncIterable`s carry the\n * happy-path output and a third carries any terminal error.\n *\n * Consume `matches` and `notifications` independently or in parallel:\n *\n * ```ts\n * const poll = await audd.streams.longpoll(category);\n * for await (const m of poll.matches) {\n * console.log(m.song.artist, m.song.title);\n * }\n * ```\n *\n * Concurrent consumption:\n *\n * ```ts\n * await Promise.all([\n * (async () => { for await (const m of poll.matches) {} })(),\n * (async () => { for await (const n of poll.notifications) {} })(),\n * (async () => { for await (const e of poll.errors) console.error(e); })(),\n * ]);\n * ```\n *\n * `close()` (or the `await using` resource-management form) tears down the\n * background loop and closes all three iterables.\n */\nexport interface LongpollPoll {\n /** Recognition events. */\n readonly matches: AsyncIterable<StreamCallbackMatch>;\n /** Stream-lifecycle events (\"stream stopped\", \"can't connect\", ...). */\n readonly notifications: AsyncIterable<StreamCallbackNotification>;\n /**\n * Terminal errors. The poll keeps polling on transient HTTP/JSON failures\n * (subject to the retry policy); errors that surface here are the ones the\n * loop gives up on. Each fired error is followed by closure of all three\n * iterables.\n */\n readonly errors: AsyncIterable<Error>;\n /** Stop the background loop. Idempotent. */\n close(): void;\n /** `await using` support — calls `close()`. */\n [Symbol.asyncDispose](): Promise<void>;\n}\n\n/**\n * Caller-supplied bits the loop needs:\n * - `fetchOnce` — performs a single longpoll HTTP GET, with caller-managed\n * auth (token in URL, Bearer header, etc.) and retry policy.\n * - `getInitialSince` — initial `since_time` to send (often `undefined`).\n * - `timeout` — server-side longpoll timeout in seconds.\n * - `category` — the longpoll category derived from `(token, radio_id)`.\n * - `signal` — aborts the in-flight HTTP when the poll is closed.\n */\nexport interface LongpollLoopConfig {\n category: string;\n timeout: number;\n sinceTime: number | undefined;\n fetchOnce: (\n params: Record<string, string | undefined>,\n signal: AbortSignal,\n ) => Promise<HttpResponse>;\n}\n\n/**\n * Internal: a single-consumer-friendly bounded queue used to demultiplex\n * the loop output onto separate AsyncIterables.\n */\nclass AsyncQueue<T> {\n private readonly items: T[] = [];\n private readonly waiters: ((v: IteratorResult<T>) => void)[] = [];\n private done = false;\n\n push(value: T): void {\n if (this.done) return;\n const w = this.waiters.shift();\n if (w !== undefined) {\n w({ value, done: false });\n return;\n }\n this.items.push(value);\n }\n\n finish(): void {\n if (this.done) return;\n this.done = true;\n while (this.waiters.length > 0) {\n const w = this.waiters.shift();\n if (w !== undefined) w({ value: undefined as never, done: true });\n }\n }\n\n next(): Promise<IteratorResult<T>> {\n const item = this.items.shift();\n if (item !== undefined) return Promise.resolve({ value: item, done: false });\n if (this.done) return Promise.resolve({ value: undefined as never, done: true });\n return new Promise((resolve) => {\n this.waiters.push(resolve);\n });\n }\n\n toIterable(): AsyncIterable<T> {\n const next = (): Promise<IteratorResult<T>> => this.next();\n return {\n [Symbol.asyncIterator](): AsyncIterator<T> {\n return { next };\n },\n };\n }\n}\n\n/**\n * Decode one longpoll HTTP response into a Match | Notification | null\n * (null = keep-alive `{timeout, timestamp}` or any non-event body — caller\n * keeps polling). Throws on HTTP non-2xx and JSON-shape errors.\n */\nfunction decodeOne(\n resp: HttpResponse,\n): { kind: \"match\"; match: StreamCallbackMatch } | { kind: \"notification\"; notification: StreamCallbackNotification } | { kind: \"keepalive\" } {\n if (resp.httpStatus >= HTTP_CLIENT_ERROR_FLOOR) {\n throw new AudDServerError({\n errorCode: 0,\n message: `Longpoll endpoint returned HTTP ${String(resp.httpStatus)}`,\n httpStatus: resp.httpStatus,\n requestId: resp.requestId,\n rawResponse: resp.jsonBody ?? resp.rawText,\n });\n }\n const body = resp.jsonBody;\n if (typeof body !== \"object\" || body === null || Array.isArray(body)) {\n throw new AudDSerializationError(\n \"Longpoll response was not a JSON object\",\n resp.rawText,\n );\n }\n const dict = body as Record<string, unknown>;\n if (\"notification\" in dict) {\n const notification = parseStreamCallbackNotification(dict.notification);\n const t = dict[\"time\"];\n if (typeof t === \"number\") notification.time = t;\n return { kind: \"notification\", notification };\n }\n if (\"result\" in dict) {\n return { kind: \"match\", match: parseStreamCallbackMatch(dict.result) };\n }\n // Either a `{timeout, timestamp}` keep-alive or an empty/unknown body —\n // skip silently and keep polling.\n return { kind: \"keepalive\" };\n}\n\n/**\n * Start the longpoll loop on a background async task. Returns a\n * {@link LongpollPoll} handle whose iterables are filled as events arrive.\n * The caller's `fetchOnce` is responsible for retries and auth.\n */\nexport function startLongpoll(cfg: LongpollLoopConfig): LongpollPoll {\n const matches = new AsyncQueue<StreamCallbackMatch>();\n const notifications = new AsyncQueue<StreamCallbackNotification>();\n const errors = new AsyncQueue<Error>();\n\n const controller = new AbortController();\n let closed = false;\n\n const finishAll = (): void => {\n matches.finish();\n notifications.finish();\n errors.finish();\n };\n\n const close = (): void => {\n if (closed) return;\n closed = true;\n controller.abort();\n finishAll();\n };\n\n const run = async (): Promise<void> => {\n let curSince = cfg.sinceTime;\n while (!closed) {\n const params: Record<string, string | undefined> = {\n category: cfg.category,\n timeout: String(cfg.timeout),\n };\n if (curSince !== undefined) params[\"since_time\"] = String(curSince);\n\n let resp: HttpResponse;\n try {\n resp = await cfg.fetchOnce(params, controller.signal);\n } catch (err) {\n if (closed) return;\n if (err instanceof TypeError) {\n errors.push(new AudDConnectionError(`Network error: ${err.message}`, err));\n } else if (\n err !== null &&\n typeof err === \"object\" &&\n (err as { name?: string }).name === \"AbortError\"\n ) {\n // Closed-from-outside path — drop quietly.\n if (closed) return;\n errors.push(new AudDConnectionError(\"Request was aborted (timeout)\", err));\n } else if (err instanceof Error) {\n errors.push(err);\n } else {\n errors.push(new Error(String(err)));\n }\n finishAll();\n return;\n }\n\n try {\n const decoded = decodeOne(resp);\n if (decoded.kind === \"match\") matches.push(decoded.match);\n else if (decoded.kind === \"notification\") notifications.push(decoded.notification);\n // else keep-alive: skip.\n } catch (err) {\n errors.push(err instanceof Error ? err : new Error(String(err)));\n finishAll();\n return;\n }\n\n // Bump since_time off the response body's timestamp, as the audd-go\n // reference does — keeps reconnects from re-replaying old events.\n const dict = resp.jsonBody;\n if (typeof dict === \"object\" && dict !== null && !Array.isArray(dict)) {\n const ts = (dict as Record<string, unknown>)[\"timestamp\"];\n if (typeof ts === \"number\") curSince = ts;\n }\n }\n };\n\n // Fire-and-forget. Failures land on the `errors` iterable.\n void run();\n\n return {\n matches: matches.toIterable(),\n notifications: notifications.toIterable(),\n errors: errors.toIterable(),\n close,\n async [Symbol.asyncDispose](): Promise<void> {\n close();\n await Promise.resolve();\n },\n };\n}\n","import type { HttpResponse } from \"./http.js\";\n\n/**\n * Cost-aware retry classes.\n *\n * - READ — idempotent reads (`streams.list`, `streams.getCallbackUrl`):\n * retry on 408/429/5xx + any connection error.\n * - RECOGNITION — `recognize`, `recognizeEnterprise`, `advanced.findLyrics`:\n * retry on pre-upload connection failures + 5xx.\n * DO NOT retry on read-timeout-after-upload (cost protection).\n * - MUTATING — `streams.add`, `streams.delete`, etc.:\n * retry only on pre-upload connection failures. DO NOT retry\n * 5xx (the side effect may have happened).\n * - NONE — `customCatalog.add`: never retry. Custom-catalog upload is\n * metered; auto-retry on transport failure could double-charge\n * for the same audio fingerprinting. Surface a clean error and\n * let the caller decide.\n */\nexport type RetryClass = \"read\" | \"recognition\" | \"mutating\" | \"none\";\n\nexport interface RetryPolicy {\n retryClass: RetryClass;\n maxAttempts: number;\n backoffFactorMs: number;\n backoffMaxMs: number;\n}\n\nexport const DEFAULT_BACKOFF_FACTOR_MS = 500;\nexport const DEFAULT_BACKOFF_MAX_MS = 30_000;\nexport const DEFAULT_MAX_ATTEMPTS = 3;\n\nconst HTTP_REQUEST_TIMEOUT = 408;\nconst HTTP_TOO_MANY_REQUESTS = 429;\nconst HTTP_SERVER_ERROR_FLOOR = 500;\n\nexport function defaultPolicy(retryClass: RetryClass): RetryPolicy {\n return {\n retryClass,\n maxAttempts: DEFAULT_MAX_ATTEMPTS,\n backoffFactorMs: DEFAULT_BACKOFF_FACTOR_MS,\n backoffMaxMs: DEFAULT_BACKOFF_MAX_MS,\n };\n}\n\nfunction backoffDelayMs(attempt: number, policy: RetryPolicy): number {\n const base = Math.min(policy.backoffFactorMs * 2 ** attempt, policy.backoffMaxMs);\n return base * (0.5 + Math.random());\n}\n\n/**\n * `fetch()` raises `TypeError(\"fetch failed\")` when DNS/TCP/TLS failed before\n * the request body finished. AbortError (or DOMException/AbortError) means the\n * caller's AbortSignal fired — could be pre- or post-upload, treated as\n * post-upload conservatively for cost-protection.\n */\nfunction isAbortError(err: unknown): boolean {\n if (err === null || typeof err !== \"object\") return false;\n const e = err as { name?: unknown };\n return e.name === \"AbortError\";\n}\n\nfunction isPreUploadConnectionError(err: unknown): boolean {\n if (isAbortError(err)) return false;\n // Node fetch wraps DNS/TCP/TLS errors as TypeError. Browsers do too.\n return err instanceof TypeError;\n}\n\nfunction shouldRetryResponse(resp: HttpResponse, retryClass: RetryClass): boolean {\n const s = resp.httpStatus;\n switch (retryClass) {\n case \"read\":\n return (\n s === HTTP_REQUEST_TIMEOUT ||\n s === HTTP_TOO_MANY_REQUESTS ||\n s >= HTTP_SERVER_ERROR_FLOOR\n );\n case \"recognition\":\n return s >= HTTP_SERVER_ERROR_FLOOR;\n case \"mutating\":\n return false;\n case \"none\":\n return false;\n }\n}\n\nfunction shouldRetryError(err: unknown, retryClass: RetryClass): boolean {\n switch (retryClass) {\n case \"read\":\n // Pre-upload connection errors and post-upload read timeouts are both\n // safe-ish: idempotent reads can be retried freely.\n return isPreUploadConnectionError(err) || isAbortError(err);\n case \"recognition\":\n // Pre-upload only — explicitly NOT post-upload AbortError (cost protection).\n return isPreUploadConnectionError(err);\n case \"mutating\":\n // Pre-upload only — server-side side-effect may have happened.\n return isPreUploadConnectionError(err);\n case \"none\":\n // Metered upload — never retry on transport failure (could double-charge).\n return false;\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function retry<T extends HttpResponse>(\n fn: () => Promise<T>,\n policy: RetryPolicy,\n): Promise<T> {\n let lastError: unknown;\n let lastResp: T | undefined;\n let haveResp = false;\n for (let attempt = 0; attempt < policy.maxAttempts; attempt++) {\n try {\n const resp = await fn();\n if (!shouldRetryResponse(resp, policy.retryClass)) return resp;\n lastResp = resp;\n haveResp = true;\n lastError = undefined;\n } catch (err) {\n if (!shouldRetryError(err, policy.retryClass)) throw err;\n lastError = err;\n haveResp = false;\n if (attempt + 1 >= policy.maxAttempts) throw err;\n }\n if (attempt + 1 >= policy.maxAttempts) break;\n await sleep(backoffDelayMs(attempt, policy));\n }\n if (haveResp && lastResp !== undefined) return lastResp;\n throw lastError;\n}\n","export const VERSION = \"1.4.6\";\n","import { VERSION } from \"./version.js\";\n\nexport function userAgent(): string {\n const node =\n typeof process !== \"undefined\" && process.version\n ? process.version.replace(/^v/, \"\")\n : \"unknown\";\n const platform =\n typeof process !== \"undefined\" && process.platform ? process.platform : \"browser\";\n return `audd-node/${VERSION} node/${node} (${platform})`;\n}\n","/**\n * Tokenless longpoll consumer for browser/widget/extension use cases.\n *\n * Carries no api_token. The category alone authorizes the subscription. The\n * user/server who derived the category is responsible for ensuring a\n * callback URL is set on their account (we can't preflight that without a\n * token).\n *\n * Behavior:\n * - HTTP non-2xx → terminal {@link AudDServerError} on the `errors` iterable\n * (no silent infinite loop).\n * - JSON decode failure on 2xx → terminal {@link AudDSerializationError}.\n * - READ-class retries on 5xx + connection failures, configurable via\n * `maxRetries` / `backoffFactorMs`.\n * - `[Symbol.asyncDispose]()` + manual `close()` for resource cleanup.\n *\n * Imported from `audd/longpoll` (browser-safe sub-entry, NOT the main\n * `audd` module — bundlers tree-shake the auth client out).\n */\n\nimport {\n AudDConnectionError,\n} from \"./errors.js\";\nimport type { FetchLike, HttpResponse } from \"./http.js\";\nimport {\n startLongpoll,\n type LongpollPoll,\n} from \"./longpollCore.js\";\nimport { defaultPolicy, retry, type RetryPolicy } from \"./retry.js\";\nimport { userAgent } from \"./userAgent.js\";\n\nexport type { LongpollPoll } from \"./longpollCore.js\";\n\nconst LONGPOLL_URL = \"https://api.audd.io/longpoll/\";\n\nexport interface LongpollConsumerOptions {\n /** Maximum retry attempts (default 3). */\n maxRetries?: number;\n /** Initial backoff in ms (default 500), jittered, exponential. */\n backoffFactorMs?: number;\n /** Custom fetch (e.g., for proxy/mTLS). */\n fetch?: FetchLike;\n}\n\nexport interface IterateOptions {\n sinceTime?: number;\n /** Server-side timeout in seconds (default 50). */\n timeout?: number;\n}\n\n/**\n * Tokenless longpoll consumer.\n *\n * ```ts\n * import { LongpollConsumer } from 'audd/longpoll';\n *\n * const consumer = new LongpollConsumer(\"abc123def\");\n * const poll = consumer.iterate({ timeout: 30 });\n * for await (const m of poll.matches) {\n * console.log(m.song.artist, m.song.title);\n * }\n * ```\n *\n * Or iterate matches and notifications concurrently:\n *\n * ```ts\n * await Promise.all([\n * (async () => { for await (const m of poll.matches) { ... } })(),\n * (async () => { for await (const n of poll.notifications) { ... } })(),\n * ]);\n * ```\n */\nexport class LongpollConsumer {\n private readonly fetchImpl: FetchLike;\n private readonly policy: RetryPolicy;\n\n constructor(public readonly category: string, opts: LongpollConsumerOptions = {}) {\n this.fetchImpl = opts.fetch ?? ((globalThis.fetch as FetchLike).bind(globalThis));\n const base = defaultPolicy(\"read\");\n this.policy = {\n ...base,\n maxAttempts: opts.maxRetries ?? base.maxAttempts,\n backoffFactorMs: opts.backoffFactorMs ?? base.backoffFactorMs,\n };\n }\n\n iterate(opts: IterateOptions = {}): LongpollPoll {\n const fetchImpl = this.fetchImpl;\n const policy = this.policy;\n const timeoutSec = opts.timeout ?? 50;\n\n const fetchOnceRaw = async (\n params: Record<string, string | undefined>,\n signal: AbortSignal,\n ): Promise<HttpResponse> => {\n const u = new URL(LONGPOLL_URL);\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined) u.searchParams.set(k, v);\n }\n const response = await fetchImpl(u.toString(), {\n method: \"GET\",\n headers: { \"User-Agent\": userAgent() },\n signal,\n });\n const text = await response.text();\n let json: unknown = null;\n if (text !== \"\") {\n try {\n json = JSON.parse(text);\n } catch {\n json = null;\n }\n }\n return {\n jsonBody: json,\n httpStatus: response.status,\n requestId: response.headers.get(\"x-request-id\"),\n rawText: text,\n };\n };\n\n const fetchOnce = async (\n params: Record<string, string | undefined>,\n signal: AbortSignal,\n ): Promise<HttpResponse> => {\n try {\n return await retry(() => fetchOnceRaw(params, signal), policy);\n } catch (err) {\n if (err instanceof TypeError) {\n throw new AudDConnectionError(`Network error: ${err.message}`, err);\n }\n if (\n err !== null &&\n typeof err === \"object\" &&\n (err as { name?: string }).name === \"AbortError\"\n ) {\n throw new AudDConnectionError(\"Request was aborted (timeout)\", err);\n }\n throw err;\n }\n };\n\n return startLongpoll({\n category: this.category,\n timeout: timeoutSec,\n sinceTime: opts.sinceTime,\n fetchOnce,\n });\n }\n\n /** Release any underlying resources. */\n close(): void {\n /* no persistent connections in fetch */\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n this.close();\n await Promise.resolve();\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/models.ts","../src/longpollCore.ts","../src/retry.ts","../src/version.ts","../src/userAgent.ts","../src/longpoll.ts"],"names":[],"mappings":"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","file":"longpoll.cjs","sourcesContent":["/** Exception hierarchy for AudD API errors. */\n\nexport interface AudDApiErrorFields {\n errorCode: number;\n message: string;\n httpStatus: number;\n requestId: string | null;\n requestedParams: Record<string, unknown>;\n requestMethod: string | null;\n brandedMessage: string | null;\n rawResponse: unknown;\n}\n\nexport type AudDApiErrorInit = Partial<AudDApiErrorFields> &\n Pick<AudDApiErrorFields, \"errorCode\" | \"message\" | \"httpStatus\">;\n\n/** Base for everything thrown by this SDK. */\nexport class AudDError extends Error {\n override name = \"AudDError\";\n}\n\n/** Server returned `status: error`. Carries the AudD error code + the full echo. */\nexport class AudDAPIError extends AudDError {\n override name = \"AudDAPIError\";\n errorCode: number;\n httpStatus: number;\n requestId: string | null;\n requestedParams: Record<string, unknown>;\n requestMethod: string | null;\n brandedMessage: string | null;\n rawResponse: unknown;\n /** Original `error_message` from the server. (`Error.message` may be overridden by subclasses.) */\n serverMessage: string;\n\n constructor(init: AudDApiErrorInit) {\n super(`[#${init.errorCode}] ${init.message}`);\n this.errorCode = init.errorCode;\n this.serverMessage = init.message;\n this.httpStatus = init.httpStatus;\n this.requestId = init.requestId ?? null;\n this.requestedParams = init.requestedParams ?? {};\n this.requestMethod = init.requestMethod ?? null;\n this.brandedMessage = init.brandedMessage ?? null;\n this.rawResponse = init.rawResponse ?? null;\n }\n}\n\nexport class AudDAuthenticationError extends AudDAPIError {\n override name = \"AudDAuthenticationError\";\n}\nexport class AudDQuotaError extends AudDAPIError {\n override name = \"AudDQuotaError\";\n}\nexport class AudDSubscriptionError extends AudDAPIError {\n override name = \"AudDSubscriptionError\";\n}\nexport class AudDCustomCatalogAccessError extends AudDSubscriptionError {\n override name = \"AudDCustomCatalogAccessError\";\n}\nexport class AudDInvalidRequestError extends AudDAPIError {\n override name = \"AudDInvalidRequestError\";\n}\nexport class AudDInvalidAudioError extends AudDAPIError {\n override name = \"AudDInvalidAudioError\";\n}\nexport class AudDRateLimitError extends AudDAPIError {\n override name = \"AudDRateLimitError\";\n}\nexport class AudDStreamLimitError extends AudDAPIError {\n override name = \"AudDStreamLimitError\";\n}\nexport class AudDNotReleasedError extends AudDAPIError {\n override name = \"AudDNotReleasedError\";\n}\nexport class AudDBlockedError extends AudDAPIError {\n override name = \"AudDBlockedError\";\n}\nexport class AudDNeedsUpdateError extends AudDAPIError {\n override name = \"AudDNeedsUpdateError\";\n}\nexport class AudDServerError extends AudDAPIError {\n override name = \"AudDServerError\";\n}\n\nexport class AudDConnectionError extends AudDError {\n override name = \"AudDConnectionError\";\n override cause?: unknown;\n constructor(message: string, cause?: unknown) {\n super(message);\n this.cause = cause;\n }\n}\n\nexport class AudDSerializationError extends AudDError {\n override name = \"AudDSerializationError\";\n rawText: string;\n constructor(message: string, rawText = \"\") {\n super(message);\n this.rawText = rawText;\n }\n}\n\nexport type AudDAPIErrorCtor = new (init: AudDApiErrorInit) => AudDAPIError;\n\nconst CODE_MAP: Record<number, AudDAPIErrorCtor> = {\n 900: AudDAuthenticationError,\n 901: AudDAuthenticationError,\n 903: AudDAuthenticationError,\n 902: AudDQuotaError,\n 904: AudDSubscriptionError,\n 905: AudDSubscriptionError,\n 50: AudDInvalidRequestError,\n 51: AudDInvalidRequestError,\n 600: AudDInvalidRequestError,\n 601: AudDInvalidRequestError,\n 602: AudDInvalidRequestError,\n 700: AudDInvalidRequestError,\n 701: AudDInvalidRequestError,\n 702: AudDInvalidRequestError,\n 906: AudDInvalidRequestError,\n 300: AudDInvalidAudioError,\n 400: AudDInvalidAudioError,\n 500: AudDInvalidAudioError,\n 610: AudDStreamLimitError,\n 611: AudDRateLimitError,\n 907: AudDNotReleasedError,\n 19: AudDBlockedError,\n 31337: AudDBlockedError,\n 20: AudDNeedsUpdateError,\n 100: AudDServerError,\n 1000: AudDServerError,\n};\n\nexport function errorClassForCode(code: number): AudDAPIErrorCtor {\n return CODE_MAP[code] ?? AudDServerError;\n}\n\nfunction brandedMessageOf(result: unknown): string | null {\n if (typeof result !== \"object\" || result === null) return null;\n const r = result as { artist?: unknown; title?: unknown };\n const parts: string[] = [];\n if (typeof r.artist === \"string\" && r.artist.length > 0) parts.push(r.artist);\n if (typeof r.title === \"string\" && r.title.length > 0) parts.push(r.title);\n return parts.length === 0 ? null : parts.join(\" — \");\n}\n\nexport interface ServerErrorBody {\n error?: { error_code?: number | undefined; error_message?: string | undefined } | undefined;\n result?: unknown;\n request_params?: Record<string, unknown> | undefined;\n requested_params?: Record<string, unknown> | undefined;\n request_api_method?: string | undefined;\n}\n\nexport interface RaiseFromErrorOpts {\n httpStatus: number;\n requestId: string | null;\n customCatalogContext?: boolean;\n}\n\nconst CUSTOM_CATALOG_PREFIX =\n \"Adding songs to your custom catalog requires enterprise access that isn't enabled on your account.\\n\\n\" +\n \"Note: the custom-catalog endpoint is for adding songs to your private fingerprint database, not for music recognition. \" +\n \"If you intended to identify music, use recognize(...) (or recognizeEnterprise(...) for files longer than 25 seconds) instead.\\n\\n\" +\n \"To request custom-catalog access, contact api@audd.io.\\n\\n\";\n\nexport function raiseFromErrorResponse(body: ServerErrorBody, opts: RaiseFromErrorOpts): never {\n const code = body.error?.error_code ?? 0;\n const message = body.error?.error_message ?? \"\";\n const requestedParams = body.request_params ?? body.requested_params ?? {};\n const requestMethod = body.request_api_method ?? null;\n const branded = brandedMessageOf(body.result);\n\n const fields: AudDApiErrorFields = {\n errorCode: code,\n message,\n httpStatus: opts.httpStatus,\n requestId: opts.requestId,\n requestedParams,\n requestMethod,\n brandedMessage: branded,\n rawResponse: body,\n };\n\n const Cls = errorClassForCode(code);\n if (opts.customCatalogContext === true && Cls === AudDSubscriptionError) {\n const overridden = `${CUSTOM_CATALOG_PREFIX}[Server message: ${message}]`;\n throw new AudDCustomCatalogAccessError({ ...fields, message: overridden });\n }\n throw new Cls(fields);\n}\n","/**\n * Typed models. Forward-compatible: each model captures unknown keys into\n * `extras`, mirroring audd-python's Pydantic `extra=\"allow\"` pattern.\n */\n\nfunction pickExtras(\n raw: Record<string, unknown>,\n knownKeys: ReadonlyArray<string>,\n): Record<string, unknown> {\n const known = new Set(knownKeys);\n const extras: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(raw)) {\n if (!known.has(k)) extras[k] = v;\n }\n return extras;\n}\n\nfunction asObject(raw: unknown): Record<string, unknown> | undefined {\n if (typeof raw === \"object\" && raw !== null && !Array.isArray(raw)) {\n return raw as Record<string, unknown>;\n }\n return undefined;\n}\n\nfunction requireObject(raw: unknown, what: string): Record<string, unknown> {\n const o = asObject(raw);\n if (o === undefined) throw new TypeError(`${what}: expected object`);\n return o;\n}\n\nfunction asString(v: unknown): string | undefined {\n return typeof v === \"string\" ? v : undefined;\n}\nfunction asNumber(v: unknown): number | undefined {\n return typeof v === \"number\" ? v : undefined;\n}\nfunction asBoolean(v: unknown): boolean | undefined {\n return typeof v === \"boolean\" ? v : undefined;\n}\n\n/** Streaming providers supported by the lis.tn redirect helper. */\nexport type StreamingProvider =\n | \"spotify\"\n | \"apple_music\"\n | \"deezer\"\n | \"napster\"\n | \"youtube\";\n\nconst STREAMING_PROVIDERS: readonly StreamingProvider[] = [\n \"spotify\",\n \"apple_music\",\n \"deezer\",\n \"napster\",\n \"youtube\",\n] as const;\n\nfunction lisTnStreamingUrl(songLink: string | undefined, provider: string): string | null {\n if (songLink === undefined || songLink === \"\") return null;\n let parsed: URL;\n try {\n parsed = new URL(songLink);\n } catch {\n return null;\n }\n if (parsed.hostname !== \"lis.tn\") return null;\n const sep = parsed.search ? \"&\" : \"?\";\n return `${songLink}${sep}${provider}`;\n}\n\nexport interface RecognitionResult {\n /** Always present on a match. */\n timecode: string;\n /** Set on custom-catalog matches. */\n audioId?: number | undefined;\n artist?: string | undefined;\n title?: string | undefined;\n album?: string | undefined;\n releaseDate?: string | undefined;\n label?: string | undefined;\n songLink?: string | undefined;\n isrc?: string | undefined;\n upc?: string | undefined;\n appleMusic?: Record<string, unknown> | undefined;\n spotify?: Record<string, unknown> | undefined;\n deezer?: Record<string, unknown> | undefined;\n napster?: Record<string, unknown> | undefined;\n musicbrainz?: ReadonlyArray<Record<string, unknown>> | undefined;\n /** Forward-compat: any unknown keys from the server. */\n extras: Record<string, unknown>;\n /** Full unparsed payload for the caller's own inspection. */\n rawResponse: Record<string, unknown>;\n /** True when `audioId` is set (custom-catalog match). */\n readonly isCustomMatch: boolean;\n /** True when `audioId` is unset and `artist` or `title` are present. */\n readonly isPublicMatch: boolean;\n /** Cover-art URL for `lis.tn`-hosted song_links, else `null`. */\n readonly thumbnailUrl: string | null;\n /**\n * Direct or redirect URL for a streaming provider, with smart fallback.\n *\n * Resolution order:\n * 1. Direct URL from the metadata block (e.g. `apple_music.url`,\n * `spotify.external_urls.spotify`, `deezer.link`, `napster.href`) when\n * the user requested that provider via `return=`.\n * 2. lis.tn redirect (`{songLink}?{provider}`) when `songLink` is on lis.tn.\n * 3. `null` otherwise. YouTube has only the lis.tn-redirect path.\n */\n streamingUrl(provider: StreamingProvider): string | null;\n /** Map of every provider with a resolvable URL — direct or via lis.tn redirect. */\n streamingUrls(): Partial<Record<StreamingProvider, string>>;\n /**\n * First available 30-second preview URL across providers, in priority order:\n * `apple_music.previews[0].url` → `spotify.preview_url` → `deezer.preview`.\n *\n * **Note:** previews are governed by the respective providers' terms of use.\n * The SDK consumer is responsible for honoring those terms (caching limits,\n * attribution, redistribution constraints).\n */\n previewUrl(): string | null;\n}\n\nfunction directStreamingUrl(\n result: Pick<RecognitionResult, \"appleMusic\" | \"spotify\" | \"deezer\" | \"napster\">,\n provider: string,\n): string | null {\n if (provider === \"apple_music\" && result.appleMusic !== undefined) {\n const url = result.appleMusic[\"url\"];\n if (typeof url === \"string\" && url.length > 0) return url;\n } else if (provider === \"spotify\" && result.spotify !== undefined) {\n const ext = result.spotify[\"external_urls\"];\n if (typeof ext === \"object\" && ext !== null) {\n const sp = (ext as Record<string, unknown>)[\"spotify\"];\n if (typeof sp === \"string\" && sp.length > 0) return sp;\n }\n const uri = result.spotify[\"uri\"];\n if (typeof uri === \"string\" && uri.length > 0) return uri;\n } else if (provider === \"deezer\" && result.deezer !== undefined) {\n const link = result.deezer[\"link\"];\n if (typeof link === \"string\" && link.length > 0) return link;\n } else if (provider === \"napster\" && result.napster !== undefined) {\n const href = result.napster[\"href\"];\n if (typeof href === \"string\" && href.length > 0) return href;\n }\n return null;\n}\n\nfunction previewFrom(result: Pick<RecognitionResult, \"appleMusic\" | \"spotify\" | \"deezer\">): string | null {\n if (result.appleMusic !== undefined) {\n const previews = result.appleMusic[\"previews\"];\n if (Array.isArray(previews) && previews.length > 0) {\n const first = previews[0];\n if (typeof first === \"object\" && first !== null) {\n const url = (first as Record<string, unknown>)[\"url\"];\n if (typeof url === \"string\" && url.length > 0) return url;\n }\n }\n }\n if (result.spotify !== undefined) {\n const url = result.spotify[\"preview_url\"];\n if (typeof url === \"string\" && url.length > 0) return url;\n }\n if (result.deezer !== undefined) {\n const url = result.deezer[\"preview\"];\n if (typeof url === \"string\" && url.length > 0) return url;\n }\n return null;\n}\n\nconst RECOGNITION_KEYS = [\n \"timecode\",\n \"audio_id\",\n \"artist\",\n \"title\",\n \"album\",\n \"release_date\",\n \"label\",\n \"song_link\",\n \"isrc\",\n \"upc\",\n \"apple_music\",\n \"spotify\",\n \"deezer\",\n \"napster\",\n \"musicbrainz\",\n] as const;\n\nexport function parseRecognitionResult(raw: unknown): RecognitionResult {\n const r = requireObject(raw, \"RecognitionResult\");\n const timecode = asString(r.timecode);\n if (timecode === undefined) {\n throw new TypeError(\"RecognitionResult: timecode missing or not string\");\n }\n const audioId = asNumber(r.audio_id);\n const artist = asString(r.artist);\n const title = asString(r.title);\n const songLink = asString(r.song_link);\n const musicbrainz = Array.isArray(r.musicbrainz)\n ? (r.musicbrainz.filter((x): x is Record<string, unknown> => asObject(x) !== undefined) as\n | Record<string, unknown>[]\n | undefined)\n : undefined;\n\n const result: RecognitionResult = {\n timecode,\n audioId,\n artist,\n title,\n album: asString(r.album),\n releaseDate: asString(r.release_date),\n label: asString(r.label),\n songLink,\n isrc: asString(r.isrc),\n upc: asString(r.upc),\n appleMusic: asObject(r.apple_music),\n spotify: asObject(r.spotify),\n deezer: asObject(r.deezer),\n napster: asObject(r.napster),\n musicbrainz,\n extras: pickExtras(r, RECOGNITION_KEYS),\n rawResponse: r,\n get isCustomMatch() {\n return audioId !== undefined;\n },\n get isPublicMatch() {\n return audioId === undefined && (artist !== undefined || title !== undefined);\n },\n get thumbnailUrl() {\n return lisTnStreamingUrl(songLink, \"thumb\");\n },\n streamingUrl(provider: StreamingProvider): string | null {\n if (!STREAMING_PROVIDERS.includes(provider)) {\n throw new TypeError(\n `Unknown streaming provider: ${String(provider)}. ` +\n `Valid: ${STREAMING_PROVIDERS.join(\", \")}`,\n );\n }\n const direct = directStreamingUrl(result, provider);\n if (direct !== null) return direct;\n return lisTnStreamingUrl(songLink, provider);\n },\n streamingUrls(): Partial<Record<StreamingProvider, string>> {\n const out: Partial<Record<StreamingProvider, string>> = {};\n for (const p of STREAMING_PROVIDERS) {\n const url = result.streamingUrl(p);\n if (url !== null) out[p] = url;\n }\n return out;\n },\n previewUrl(): string | null {\n return previewFrom(result);\n },\n };\n return result;\n}\n\nexport interface EnterpriseMatch {\n score: number;\n timecode: string;\n artist?: string | undefined;\n title?: string | undefined;\n album?: string | undefined;\n releaseDate?: string | undefined;\n label?: string | undefined;\n isrc?: string | undefined;\n upc?: string | undefined;\n songLink?: string | undefined;\n startOffset?: number | undefined;\n endOffset?: number | undefined;\n extras: Record<string, unknown>;\n rawResponse: Record<string, unknown>;\n readonly thumbnailUrl: string | null;\n /** lis.tn redirect URL for the given streaming provider, or null if `songLink` is non-lis.tn. */\n streamingUrl(provider: StreamingProvider): string | null;\n /** All providers with a resolvable lis.tn redirect URL (or empty when `songLink` is off lis.tn). */\n streamingUrls(): Partial<Record<StreamingProvider, string>>;\n}\n\nconst ENTERPRISE_MATCH_KEYS = [\n \"score\",\n \"timecode\",\n \"artist\",\n \"title\",\n \"album\",\n \"release_date\",\n \"label\",\n \"isrc\",\n \"upc\",\n \"song_link\",\n \"start_offset\",\n \"end_offset\",\n] as const;\n\nexport function parseEnterpriseMatch(raw: unknown): EnterpriseMatch {\n const r = requireObject(raw, \"EnterpriseMatch\");\n const score = asNumber(r.score);\n const timecode = asString(r.timecode);\n if (score === undefined) throw new TypeError(\"EnterpriseMatch: score not number\");\n if (timecode === undefined) throw new TypeError(\"EnterpriseMatch: timecode not string\");\n const songLink = asString(r.song_link);\n return {\n score,\n timecode,\n artist: asString(r.artist),\n title: asString(r.title),\n album: asString(r.album),\n releaseDate: asString(r.release_date),\n label: asString(r.label),\n isrc: asString(r.isrc),\n upc: asString(r.upc),\n songLink,\n startOffset: asNumber(r.start_offset),\n endOffset: asNumber(r.end_offset),\n extras: pickExtras(r, ENTERPRISE_MATCH_KEYS),\n rawResponse: r,\n streamingUrl(provider: StreamingProvider): string | null {\n if (!STREAMING_PROVIDERS.includes(provider)) {\n throw new TypeError(`Unknown streaming provider: ${String(provider)}`);\n }\n return lisTnStreamingUrl(songLink, provider);\n },\n streamingUrls(): Partial<Record<StreamingProvider, string>> {\n const out: Partial<Record<StreamingProvider, string>> = {};\n for (const p of STREAMING_PROVIDERS) {\n const url = lisTnStreamingUrl(songLink, p);\n if (url !== null) out[p] = url;\n }\n return out;\n },\n get thumbnailUrl() {\n if (songLink === undefined || songLink === \"\") return null;\n try {\n const parsed = new URL(songLink);\n if (parsed.hostname !== \"lis.tn\") return null;\n const sep = parsed.search ? \"&\" : \"?\";\n return `${songLink}${sep}thumb`;\n } catch {\n return null;\n }\n },\n };\n}\n\nexport interface EnterpriseChunkResult {\n songs: EnterpriseMatch[];\n offset: string;\n extras: Record<string, unknown>;\n rawResponse: Record<string, unknown>;\n}\n\nconst ENTERPRISE_CHUNK_KEYS = [\"songs\", \"offset\"] as const;\n\nexport function parseEnterpriseChunkResult(raw: unknown): EnterpriseChunkResult {\n const r = requireObject(raw, \"EnterpriseChunkResult\");\n const songsRaw = r.songs;\n if (!Array.isArray(songsRaw)) {\n throw new TypeError(\"EnterpriseChunkResult: songs not array\");\n }\n const offset = asString(r.offset);\n if (offset === undefined) throw new TypeError(\"EnterpriseChunkResult: offset not string\");\n return {\n songs: songsRaw.map(parseEnterpriseMatch),\n offset,\n extras: pickExtras(r, ENTERPRISE_CHUNK_KEYS),\n rawResponse: r,\n };\n}\n\nexport interface Stream {\n radioId: number;\n url: string;\n streamRunning: boolean;\n longpollCategory?: string | undefined;\n extras: Record<string, unknown>;\n rawResponse: Record<string, unknown>;\n}\n\nconst STREAM_KEYS = [\"radio_id\", \"url\", \"stream_running\", \"longpoll_category\"] as const;\n\nexport function parseStream(raw: unknown): Stream {\n const r = requireObject(raw, \"Stream\");\n const radioId = asNumber(r.radio_id);\n const url = asString(r.url);\n const streamRunning = asBoolean(r.stream_running);\n if (radioId === undefined) throw new TypeError(\"Stream: radio_id not number\");\n if (url === undefined) throw new TypeError(\"Stream: url not string\");\n if (streamRunning === undefined) throw new TypeError(\"Stream: stream_running not boolean\");\n return {\n radioId,\n url,\n streamRunning,\n longpollCategory: asString(r.longpoll_category),\n extras: pickExtras(r, STREAM_KEYS),\n rawResponse: r,\n };\n}\n\n/**\n * One candidate song in a recognition match.\n *\n * Almost every match has exactly one Song; the rare extra candidates that\n * appear under {@link StreamCallbackMatch.alternatives} may have a *different*\n * artist or title from the top song — they're variant catalog releases of the\n * same recording (e.g. a \"feat.\" credit vs. the bare-artist re-release, or\n * regional edits with different titles), not lower-confidence guesses at the\n * same track.\n */\nexport interface StreamCallbackSong {\n artist: string;\n title: string;\n score: number;\n album?: string | undefined;\n releaseDate?: string | undefined;\n label?: string | undefined;\n songLink?: string | undefined;\n isrc?: string | undefined;\n upc?: string | undefined;\n appleMusic?: Record<string, unknown> | undefined;\n spotify?: Record<string, unknown> | undefined;\n deezer?: Record<string, unknown> | undefined;\n napster?: Record<string, unknown> | undefined;\n musicbrainz?: ReadonlyArray<Record<string, unknown>> | undefined;\n extras: Record<string, unknown>;\n}\n\nconst STREAM_CALLBACK_SONG_KEYS = [\n \"artist\",\n \"title\",\n \"score\",\n \"album\",\n \"release_date\",\n \"label\",\n \"song_link\",\n \"isrc\",\n \"upc\",\n \"apple_music\",\n \"spotify\",\n \"deezer\",\n \"napster\",\n \"musicbrainz\",\n] as const;\n\nfunction parseStreamCallbackSong(raw: unknown): StreamCallbackSong {\n const r = requireObject(raw, \"StreamCallbackSong\");\n const artist = asString(r.artist);\n const title = asString(r.title);\n const score = asNumber(r.score);\n if (artist === undefined) throw new TypeError(\"StreamCallbackSong: artist not string\");\n if (title === undefined) throw new TypeError(\"StreamCallbackSong: title not string\");\n if (score === undefined) throw new TypeError(\"StreamCallbackSong: score not number\");\n const musicbrainz = Array.isArray(r.musicbrainz)\n ? (r.musicbrainz.filter((x): x is Record<string, unknown> => asObject(x) !== undefined) as\n | Record<string, unknown>[]\n | undefined)\n : undefined;\n return {\n artist,\n title,\n score,\n album: asString(r.album),\n releaseDate: asString(r.release_date),\n label: asString(r.label),\n songLink: asString(r.song_link),\n isrc: asString(r.isrc),\n upc: asString(r.upc),\n appleMusic: asObject(r.apple_music),\n spotify: asObject(r.spotify),\n deezer: asObject(r.deezer),\n napster: asObject(r.napster),\n musicbrainz,\n extras: pickExtras(r, STREAM_CALLBACK_SONG_KEYS),\n };\n}\n\n/**\n * One recognition event from a stream callback or longpoll.\n *\n * The top match lives in {@link song}; rare extra candidates live in\n * {@link alternatives}. Alternatives entries may have a different artist or\n * title from the top song — they're variant catalog releases of the same\n * recording, not lower-confidence guesses at the same track.\n */\nexport interface StreamCallbackMatch {\n radioId: number;\n timestamp?: string | undefined;\n playLength?: number | undefined;\n /** Top match — always present. */\n song: StreamCallbackSong;\n /** Variant catalog releases (may have different artist/title); empty array when only one match. */\n alternatives: StreamCallbackSong[];\n extras: Record<string, unknown>;\n rawResponse: Record<string, unknown>;\n}\n\nconst STREAM_CALLBACK_MATCH_KEYS = [\n \"radio_id\",\n \"timestamp\",\n \"play_length\",\n \"results\",\n] as const;\n\nexport function parseStreamCallbackMatch(raw: unknown): StreamCallbackMatch {\n const r = requireObject(raw, \"StreamCallbackMatch\");\n const radioId = asNumber(r.radio_id);\n if (radioId === undefined) throw new TypeError(\"StreamCallbackMatch: radio_id not number\");\n const resultsRaw = r.results;\n if (!Array.isArray(resultsRaw)) throw new TypeError(\"StreamCallbackMatch: results not array\");\n if (resultsRaw.length === 0) throw new TypeError(\"StreamCallbackMatch: results is empty\");\n const songs = resultsRaw.map(parseStreamCallbackSong);\n const [first, ...rest] = songs;\n if (first === undefined) throw new TypeError(\"StreamCallbackMatch: results is empty\");\n return {\n radioId,\n timestamp: asString(r.timestamp),\n playLength: asNumber(r.play_length),\n song: first,\n alternatives: rest,\n extras: pickExtras(r, STREAM_CALLBACK_MATCH_KEYS),\n rawResponse: r,\n };\n}\n\nexport interface StreamCallbackNotification {\n radioId: number;\n streamRunning?: boolean | undefined;\n notificationCode: number;\n notificationMessage: string;\n /** Outer `time` field on the callback envelope (epoch seconds). */\n time?: number | undefined;\n extras: Record<string, unknown>;\n rawResponse: Record<string, unknown>;\n}\n\nconst STREAM_CALLBACK_NOTIFICATION_KEYS = [\n \"radio_id\",\n \"stream_running\",\n \"notification_code\",\n \"notification_message\",\n] as const;\n\nexport function parseStreamCallbackNotification(raw: unknown): StreamCallbackNotification {\n const r = requireObject(raw, \"StreamCallbackNotification\");\n const radioId = asNumber(r.radio_id);\n if (radioId === undefined)\n throw new TypeError(\"StreamCallbackNotification: radio_id not number\");\n const code = asNumber(r.notification_code);\n if (code === undefined)\n throw new TypeError(\"StreamCallbackNotification: notification_code not number\");\n const message = asString(r.notification_message);\n if (message === undefined)\n throw new TypeError(\"StreamCallbackNotification: notification_message not string\");\n return {\n radioId,\n streamRunning: asBoolean(r.stream_running),\n notificationCode: code,\n notificationMessage: message,\n extras: pickExtras(r, STREAM_CALLBACK_NOTIFICATION_KEYS),\n rawResponse: r,\n };\n}\n\nexport interface LyricsResult {\n artist: string;\n title: string;\n lyrics?: string | undefined;\n songId?: number | undefined;\n fullTitle?: string | undefined;\n artistId?: number | undefined;\n songLink?: string | undefined;\n media?: string | undefined;\n extras: Record<string, unknown>;\n rawResponse: Record<string, unknown>;\n}\n\nconst LYRICS_KEYS = [\n \"artist\",\n \"title\",\n \"lyrics\",\n \"song_id\",\n \"full_title\",\n \"artist_id\",\n \"song_link\",\n \"media\",\n] as const;\n\nexport function parseLyricsResult(raw: unknown): LyricsResult {\n const r = requireObject(raw, \"LyricsResult\");\n const artist = asString(r.artist);\n const title = asString(r.title);\n if (artist === undefined) throw new TypeError(\"LyricsResult: artist not string\");\n if (title === undefined) throw new TypeError(\"LyricsResult: title not string\");\n return {\n artist,\n title,\n lyrics: asString(r.lyrics),\n songId: asNumber(r.song_id),\n fullTitle: asString(r.full_title),\n artistId: asNumber(r.artist_id),\n songLink: asString(r.song_link),\n media: asString(r.media),\n extras: pickExtras(r, LYRICS_KEYS),\n rawResponse: r,\n };\n}\n","/**\n * Shared longpoll loop + handle, used by both the authenticated `Streams`\n * namespace (token in URL via `HttpClient.get`) and the tokenless\n * `LongpollConsumer` exported from `audd/longpoll`.\n *\n * Browser-safe: no node:crypto, no node:fs, no node:http imports. The whole\n * file relies on `fetch`-style I/O the caller injects.\n */\n\nimport {\n AudDConnectionError,\n AudDSerializationError,\n AudDServerError,\n} from \"./errors.js\";\nimport type { HttpResponse } from \"./http.js\";\nimport type {\n StreamCallbackMatch,\n StreamCallbackNotification,\n} from \"./models.js\";\nimport {\n parseStreamCallbackMatch,\n parseStreamCallbackNotification,\n} from \"./models.js\";\n\nconst HTTP_CLIENT_ERROR_FLOOR = 400;\n\n/**\n * Active long-poll subscription. Two typed `AsyncIterable`s carry the\n * happy-path output and a third carries any terminal error.\n *\n * Consume `matches` and `notifications` independently or in parallel:\n *\n * ```ts\n * const poll = await audd.streams.longpoll(category);\n * for await (const m of poll.matches) {\n * console.log(m.song.artist, m.song.title);\n * }\n * ```\n *\n * Concurrent consumption:\n *\n * ```ts\n * await Promise.all([\n * (async () => { for await (const m of poll.matches) {} })(),\n * (async () => { for await (const n of poll.notifications) {} })(),\n * (async () => { for await (const e of poll.errors) console.error(e); })(),\n * ]);\n * ```\n *\n * `close()` (or the `await using` resource-management form) tears down the\n * background loop and closes all three iterables.\n */\nexport interface LongpollPoll {\n /** Recognition events. */\n readonly matches: AsyncIterable<StreamCallbackMatch>;\n /** Stream-lifecycle events (\"stream stopped\", \"can't connect\", ...). */\n readonly notifications: AsyncIterable<StreamCallbackNotification>;\n /**\n * Terminal errors. The poll keeps polling on transient HTTP/JSON failures\n * (subject to the retry policy); errors that surface here are the ones the\n * loop gives up on. Each fired error is followed by closure of all three\n * iterables.\n */\n readonly errors: AsyncIterable<Error>;\n /** Stop the background loop. Idempotent. */\n close(): void;\n /** `await using` support — calls `close()`. */\n [Symbol.asyncDispose](): Promise<void>;\n}\n\n/**\n * Caller-supplied bits the loop needs:\n * - `fetchOnce` — performs a single longpoll HTTP GET, with caller-managed\n * auth (token in URL, Bearer header, etc.) and retry policy.\n * - `getInitialSince` — initial `since_time` to send (often `undefined`).\n * - `timeout` — server-side longpoll timeout in seconds.\n * - `category` — the longpoll category derived from `(token, radio_id)`.\n * - `signal` — aborts the in-flight HTTP when the poll is closed.\n */\nexport interface LongpollLoopConfig {\n category: string;\n timeout: number;\n sinceTime: number | undefined;\n fetchOnce: (\n params: Record<string, string | undefined>,\n signal: AbortSignal,\n ) => Promise<HttpResponse>;\n}\n\n/**\n * Internal: a single-consumer-friendly bounded queue used to demultiplex\n * the loop output onto separate AsyncIterables.\n */\nclass AsyncQueue<T> {\n private readonly items: T[] = [];\n private readonly waiters: ((v: IteratorResult<T>) => void)[] = [];\n private done = false;\n\n push(value: T): void {\n if (this.done) return;\n const w = this.waiters.shift();\n if (w !== undefined) {\n w({ value, done: false });\n return;\n }\n this.items.push(value);\n }\n\n finish(): void {\n if (this.done) return;\n this.done = true;\n while (this.waiters.length > 0) {\n const w = this.waiters.shift();\n if (w !== undefined) w({ value: undefined as never, done: true });\n }\n }\n\n next(): Promise<IteratorResult<T>> {\n const item = this.items.shift();\n if (item !== undefined) return Promise.resolve({ value: item, done: false });\n if (this.done) return Promise.resolve({ value: undefined as never, done: true });\n return new Promise((resolve) => {\n this.waiters.push(resolve);\n });\n }\n\n toIterable(): AsyncIterable<T> {\n const next = (): Promise<IteratorResult<T>> => this.next();\n return {\n [Symbol.asyncIterator](): AsyncIterator<T> {\n return { next };\n },\n };\n }\n}\n\n/**\n * Decode one longpoll HTTP response into a Match | Notification | null\n * (null = keep-alive `{timeout, timestamp}` or any non-event body — caller\n * keeps polling). Throws on HTTP non-2xx and JSON-shape errors.\n */\nfunction decodeOne(\n resp: HttpResponse,\n): { kind: \"match\"; match: StreamCallbackMatch } | { kind: \"notification\"; notification: StreamCallbackNotification } | { kind: \"keepalive\" } {\n if (resp.httpStatus >= HTTP_CLIENT_ERROR_FLOOR) {\n throw new AudDServerError({\n errorCode: 0,\n message: `Longpoll endpoint returned HTTP ${String(resp.httpStatus)}`,\n httpStatus: resp.httpStatus,\n requestId: resp.requestId,\n rawResponse: resp.jsonBody ?? resp.rawText,\n });\n }\n const body = resp.jsonBody;\n if (typeof body !== \"object\" || body === null || Array.isArray(body)) {\n throw new AudDSerializationError(\n \"Longpoll response was not a JSON object\",\n resp.rawText,\n );\n }\n const dict = body as Record<string, unknown>;\n if (\"notification\" in dict) {\n const notification = parseStreamCallbackNotification(dict.notification);\n const t = dict[\"time\"];\n if (typeof t === \"number\") notification.time = t;\n return { kind: \"notification\", notification };\n }\n if (\"result\" in dict) {\n return { kind: \"match\", match: parseStreamCallbackMatch(dict.result) };\n }\n // Either a `{timeout, timestamp}` keep-alive or an empty/unknown body —\n // skip silently and keep polling.\n return { kind: \"keepalive\" };\n}\n\n/**\n * Start the longpoll loop on a background async task. Returns a\n * {@link LongpollPoll} handle whose iterables are filled as events arrive.\n * The caller's `fetchOnce` is responsible for retries and auth.\n */\nexport function startLongpoll(cfg: LongpollLoopConfig): LongpollPoll {\n const matches = new AsyncQueue<StreamCallbackMatch>();\n const notifications = new AsyncQueue<StreamCallbackNotification>();\n const errors = new AsyncQueue<Error>();\n\n const controller = new AbortController();\n let closed = false;\n\n const finishAll = (): void => {\n matches.finish();\n notifications.finish();\n errors.finish();\n };\n\n const close = (): void => {\n if (closed) return;\n closed = true;\n controller.abort();\n finishAll();\n };\n\n const run = async (): Promise<void> => {\n let curSince = cfg.sinceTime;\n while (!closed) {\n const params: Record<string, string | undefined> = {\n category: cfg.category,\n timeout: String(cfg.timeout),\n };\n if (curSince !== undefined) params[\"since_time\"] = String(curSince);\n\n let resp: HttpResponse;\n try {\n resp = await cfg.fetchOnce(params, controller.signal);\n } catch (err) {\n if (closed) return;\n if (err instanceof TypeError) {\n errors.push(new AudDConnectionError(`Network error: ${err.message}`, err));\n } else if (\n err !== null &&\n typeof err === \"object\" &&\n (err as { name?: string }).name === \"AbortError\"\n ) {\n // Closed-from-outside path — drop quietly.\n if (closed) return;\n errors.push(new AudDConnectionError(\"Request was aborted (timeout)\", err));\n } else if (err instanceof Error) {\n errors.push(err);\n } else {\n errors.push(new Error(String(err)));\n }\n finishAll();\n return;\n }\n\n try {\n const decoded = decodeOne(resp);\n if (decoded.kind === \"match\") matches.push(decoded.match);\n else if (decoded.kind === \"notification\") notifications.push(decoded.notification);\n // else keep-alive: skip.\n } catch (err) {\n errors.push(err instanceof Error ? err : new Error(String(err)));\n finishAll();\n return;\n }\n\n // Bump since_time off the response body's timestamp, as the audd-go\n // reference does — keeps reconnects from re-replaying old events.\n const dict = resp.jsonBody;\n if (typeof dict === \"object\" && dict !== null && !Array.isArray(dict)) {\n const ts = (dict as Record<string, unknown>)[\"timestamp\"];\n if (typeof ts === \"number\") curSince = ts;\n }\n }\n };\n\n // Fire-and-forget. Failures land on the `errors` iterable.\n void run();\n\n return {\n matches: matches.toIterable(),\n notifications: notifications.toIterable(),\n errors: errors.toIterable(),\n close,\n async [Symbol.asyncDispose](): Promise<void> {\n close();\n await Promise.resolve();\n },\n };\n}\n","import type { HttpResponse } from \"./http.js\";\n\n/**\n * Cost-aware retry classes.\n *\n * - READ — idempotent reads (`streams.list`, `streams.getCallbackUrl`):\n * retry on 408/429/5xx + any connection error.\n * - RECOGNITION — `recognize`, `recognizeEnterprise`, `advanced.findLyrics`:\n * retry on pre-upload connection failures + 5xx.\n * DO NOT retry on read-timeout-after-upload (cost protection).\n * - MUTATING — `streams.add`, `streams.delete`, etc.:\n * retry only on pre-upload connection failures. DO NOT retry\n * 5xx (the side effect may have happened).\n * - NONE — `customCatalog.add`: never retry. Custom-catalog upload is\n * metered; auto-retry on transport failure could double-charge\n * for the same audio fingerprinting. Surface a clean error and\n * let the caller decide.\n */\nexport type RetryClass = \"read\" | \"recognition\" | \"mutating\" | \"none\";\n\nexport interface RetryPolicy {\n retryClass: RetryClass;\n maxAttempts: number;\n backoffFactorMs: number;\n backoffMaxMs: number;\n}\n\nexport const DEFAULT_BACKOFF_FACTOR_MS = 500;\nexport const DEFAULT_BACKOFF_MAX_MS = 30_000;\nexport const DEFAULT_MAX_ATTEMPTS = 3;\n\nconst HTTP_REQUEST_TIMEOUT = 408;\nconst HTTP_TOO_MANY_REQUESTS = 429;\nconst HTTP_SERVER_ERROR_FLOOR = 500;\n\nexport function defaultPolicy(retryClass: RetryClass): RetryPolicy {\n return {\n retryClass,\n maxAttempts: DEFAULT_MAX_ATTEMPTS,\n backoffFactorMs: DEFAULT_BACKOFF_FACTOR_MS,\n backoffMaxMs: DEFAULT_BACKOFF_MAX_MS,\n };\n}\n\nfunction backoffDelayMs(attempt: number, policy: RetryPolicy): number {\n const base = Math.min(policy.backoffFactorMs * 2 ** attempt, policy.backoffMaxMs);\n return base * (0.5 + Math.random());\n}\n\n/**\n * `fetch()` raises `TypeError(\"fetch failed\")` when DNS/TCP/TLS failed before\n * the request body finished. AbortError (or DOMException/AbortError) means the\n * caller's AbortSignal fired — could be pre- or post-upload, treated as\n * post-upload conservatively for cost-protection.\n */\nfunction isAbortError(err: unknown): boolean {\n if (err === null || typeof err !== \"object\") return false;\n const e = err as { name?: unknown };\n return e.name === \"AbortError\";\n}\n\nfunction isPreUploadConnectionError(err: unknown): boolean {\n if (isAbortError(err)) return false;\n // Node fetch wraps DNS/TCP/TLS errors as TypeError. Browsers do too.\n return err instanceof TypeError;\n}\n\nfunction shouldRetryResponse(resp: HttpResponse, retryClass: RetryClass): boolean {\n const s = resp.httpStatus;\n switch (retryClass) {\n case \"read\":\n return (\n s === HTTP_REQUEST_TIMEOUT ||\n s === HTTP_TOO_MANY_REQUESTS ||\n s >= HTTP_SERVER_ERROR_FLOOR\n );\n case \"recognition\":\n return s >= HTTP_SERVER_ERROR_FLOOR;\n case \"mutating\":\n return false;\n case \"none\":\n return false;\n }\n}\n\nfunction shouldRetryError(err: unknown, retryClass: RetryClass): boolean {\n switch (retryClass) {\n case \"read\":\n // Pre-upload connection errors and post-upload read timeouts are both\n // safe-ish: idempotent reads can be retried freely.\n return isPreUploadConnectionError(err) || isAbortError(err);\n case \"recognition\":\n // Pre-upload only — explicitly NOT post-upload AbortError (cost protection).\n return isPreUploadConnectionError(err);\n case \"mutating\":\n // Pre-upload only — server-side side-effect may have happened.\n return isPreUploadConnectionError(err);\n case \"none\":\n // Metered upload — never retry on transport failure (could double-charge).\n return false;\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function retry<T extends HttpResponse>(\n fn: () => Promise<T>,\n policy: RetryPolicy,\n): Promise<T> {\n let lastError: unknown;\n let lastResp: T | undefined;\n let haveResp = false;\n for (let attempt = 0; attempt < policy.maxAttempts; attempt++) {\n try {\n const resp = await fn();\n if (!shouldRetryResponse(resp, policy.retryClass)) return resp;\n lastResp = resp;\n haveResp = true;\n lastError = undefined;\n } catch (err) {\n if (!shouldRetryError(err, policy.retryClass)) throw err;\n lastError = err;\n haveResp = false;\n if (attempt + 1 >= policy.maxAttempts) throw err;\n }\n if (attempt + 1 >= policy.maxAttempts) break;\n await sleep(backoffDelayMs(attempt, policy));\n }\n if (haveResp && lastResp !== undefined) return lastResp;\n throw lastError;\n}\n","export const VERSION = \"1.5.8\";\n","import { VERSION } from \"./version.js\";\n\nexport function userAgent(): string {\n const node =\n typeof process !== \"undefined\" && process.version\n ? process.version.replace(/^v/, \"\")\n : \"unknown\";\n const platform =\n typeof process !== \"undefined\" && process.platform ? process.platform : \"browser\";\n return `audd-node/${VERSION} node/${node} (${platform})`;\n}\n","/**\n * Tokenless longpoll consumer for browser/widget/extension use cases.\n *\n * Carries no api_token. The category alone authorizes the subscription. The\n * user/server who derived the category is responsible for ensuring a\n * callback URL is set on their account (we can't preflight that without a\n * token).\n *\n * Behavior:\n * - HTTP non-2xx → terminal {@link AudDServerError} on the `errors` iterable\n * (no silent infinite loop).\n * - JSON decode failure on 2xx → terminal {@link AudDSerializationError}.\n * - READ-class retries on 5xx + connection failures, configurable via\n * `maxRetries` / `backoffFactorMs`.\n * - `[Symbol.asyncDispose]()` + manual `close()` for resource cleanup.\n *\n * Imported from `audd/longpoll` (browser-safe sub-entry, NOT the main\n * `audd` module — bundlers tree-shake the auth client out).\n */\n\nimport {\n AudDConnectionError,\n} from \"./errors.js\";\nimport type { FetchLike, HttpResponse } from \"./http.js\";\nimport {\n startLongpoll,\n type LongpollPoll,\n} from \"./longpollCore.js\";\nimport { defaultPolicy, retry, type RetryPolicy } from \"./retry.js\";\nimport { userAgent } from \"./userAgent.js\";\n\nexport type { LongpollPoll } from \"./longpollCore.js\";\n\nconst LONGPOLL_URL = \"https://api.audd.io/longpoll/\";\n\nexport interface LongpollConsumerOptions {\n /** Maximum retry attempts (default 3). */\n maxRetries?: number;\n /** Initial backoff in ms (default 500), jittered, exponential. */\n backoffFactorMs?: number;\n /** Custom fetch (e.g., for proxy/mTLS). */\n fetch?: FetchLike;\n}\n\nexport interface IterateOptions {\n sinceTime?: number;\n /** Server-side timeout in seconds (default 50). */\n timeout?: number;\n}\n\n/**\n * Tokenless longpoll consumer.\n *\n * ```ts\n * import { LongpollConsumer } from 'audd/longpoll';\n *\n * const consumer = new LongpollConsumer(\"abc123def\");\n * const poll = consumer.iterate({ timeout: 30 });\n * for await (const m of poll.matches) {\n * console.log(m.song.artist, m.song.title);\n * }\n * ```\n *\n * Or iterate matches and notifications concurrently:\n *\n * ```ts\n * await Promise.all([\n * (async () => { for await (const m of poll.matches) { ... } })(),\n * (async () => { for await (const n of poll.notifications) { ... } })(),\n * ]);\n * ```\n */\nexport class LongpollConsumer {\n private readonly fetchImpl: FetchLike;\n private readonly policy: RetryPolicy;\n\n constructor(public readonly category: string, opts: LongpollConsumerOptions = {}) {\n this.fetchImpl = opts.fetch ?? ((globalThis.fetch as FetchLike).bind(globalThis));\n const base = defaultPolicy(\"read\");\n this.policy = {\n ...base,\n maxAttempts: opts.maxRetries ?? base.maxAttempts,\n backoffFactorMs: opts.backoffFactorMs ?? base.backoffFactorMs,\n };\n }\n\n iterate(opts: IterateOptions = {}): LongpollPoll {\n const fetchImpl = this.fetchImpl;\n const policy = this.policy;\n const timeoutSec = opts.timeout ?? 50;\n\n const fetchOnceRaw = async (\n params: Record<string, string | undefined>,\n signal: AbortSignal,\n ): Promise<HttpResponse> => {\n const u = new URL(LONGPOLL_URL);\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined) u.searchParams.set(k, v);\n }\n const response = await fetchImpl(u.toString(), {\n method: \"GET\",\n headers: { \"User-Agent\": userAgent() },\n signal,\n });\n const text = await response.text();\n let json: unknown = null;\n if (text !== \"\") {\n try {\n json = JSON.parse(text);\n } catch {\n json = null;\n }\n }\n return {\n jsonBody: json,\n httpStatus: response.status,\n requestId: response.headers.get(\"x-request-id\"),\n rawText: text,\n };\n };\n\n const fetchOnce = async (\n params: Record<string, string | undefined>,\n signal: AbortSignal,\n ): Promise<HttpResponse> => {\n try {\n return await retry(() => fetchOnceRaw(params, signal), policy);\n } catch (err) {\n if (err instanceof TypeError) {\n throw new AudDConnectionError(`Network error: ${err.message}`, err);\n }\n if (\n err !== null &&\n typeof err === \"object\" &&\n (err as { name?: string }).name === \"AbortError\"\n ) {\n throw new AudDConnectionError(\"Request was aborted (timeout)\", err);\n }\n throw err;\n }\n };\n\n return startLongpoll({\n category: this.category,\n timeout: timeoutSec,\n sinceTime: opts.sinceTime,\n fetchOnce,\n });\n }\n\n /** Release any underlying resources. */\n close(): void {\n /* no persistent connections in fetch */\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n this.close();\n await Promise.resolve();\n }\n}\n"]}
package/dist/longpoll.js CHANGED
@@ -392,7 +392,7 @@ async function retry(fn, policy) {
392
392
  }
393
393
 
394
394
  // src/version.ts
395
- var VERSION = "1.4.6";
395
+ var VERSION = "1.5.8";
396
396
 
397
397
  // src/userAgent.ts
398
398
  function userAgent() {