Skip to content

Commit d1f941e

Browse files
author
AudD
committed
Initial release v1.4.3
0 parents  commit d1f941e

54 files changed

Lines changed: 9526 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
8+
permissions:
9+
contents: read
10+
11+
jobs:
12+
test:
13+
runs-on: ubuntu-latest
14+
strategy:
15+
fail-fast: false
16+
matrix:
17+
node-version: ["20", "22"]
18+
steps:
19+
- uses: actions/checkout@v4
20+
- uses: actions/setup-node@v4
21+
with:
22+
node-version: ${{ matrix.node-version }}
23+
cache: npm
24+
- run: npm ci
25+
- run: npm run lint
26+
- run: npm run typecheck
27+
- run: npm run test
28+
- run: npm run build

.github/workflows/contract.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Contract
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
schedule:
8+
# Daily nightly run at 06:00 UTC catches drift from upstream API changes
9+
# captured into fixtures/ between merges.
10+
- cron: "0 6 * * *"
11+
repository_dispatch:
12+
# Fired by audd-openapi on every merge to main; re-run our parser against
13+
# the latest spec to catch contract drift before it reaches users.
14+
types: [openapi-updated]
15+
16+
permissions:
17+
contents: read
18+
issues: write
19+
20+
jobs:
21+
contract:
22+
runs-on: ubuntu-latest
23+
steps:
24+
- uses: actions/checkout@v4
25+
with:
26+
path: audd-node
27+
- uses: actions/checkout@v4
28+
with:
29+
repository: AudDMusic/audd-openapi
30+
path: audd-openapi
31+
- uses: actions/setup-node@v4
32+
with:
33+
node-version: "20"
34+
cache: npm
35+
cache-dependency-path: audd-node/package-lock.json
36+
- working-directory: audd-node
37+
run: npm ci
38+
- working-directory: audd-node
39+
env:
40+
AUDD_OPENAPI_FIXTURES: ${{ github.workspace }}/audd-openapi/fixtures
41+
run: npx vitest run test/contract.test.ts

.github/workflows/release.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "audd-node/v*"
7+
8+
permissions:
9+
contents: read
10+
id-token: write # for npm provenance via Sigstore
11+
12+
jobs:
13+
publish:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v4
17+
- uses: actions/setup-node@v4
18+
with:
19+
node-version: "20"
20+
cache: npm
21+
registry-url: "https://registry.npmjs.org"
22+
- run: npm ci
23+
- run: npm run lint
24+
- run: npm run typecheck
25+
- run: npm run test
26+
- run: npm run build
27+
- run: npm publish --provenance --access public
28+
env:
29+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
node_modules/
2+
dist/
3+
coverage/
4+
.env
5+
.DS_Store
6+
*.log

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 AudD (https://audd.io)
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
# audd
2+
3+
[![CI](https://github.com/AudDMusic/audd-node/actions/workflows/ci.yml/badge.svg)](https://github.com/AudDMusic/audd-node/actions/workflows/ci.yml)
4+
[![Contract](https://github.com/AudDMusic/audd-node/actions/workflows/contract.yml/badge.svg)](https://github.com/AudDMusic/audd-node/actions/workflows/contract.yml)
5+
[![npm](https://img.shields.io/npm/v/audd.svg)](https://www.npmjs.com/package/audd)
6+
7+
Official TypeScript / Node.js SDK for the [AudD](https://audd.io) music recognition API.
8+
9+
## Quickstart
10+
11+
```bash
12+
npm install audd
13+
```
14+
15+
```ts
16+
import { AudD } from "audd";
17+
18+
const audd = new AudD({ apiToken: "test" }); // grab a real token at https://dashboard.audd.io
19+
const result = await audd.recognize("https://audd.tech/example.mp3");
20+
if (result) {
21+
console.log(`${result.artist} — ${result.title}`);
22+
}
23+
```
24+
25+
## Capabilities
26+
27+
| What | How |
28+
|---|---|
29+
| Recognize a short clip (≤25s) | `audd.recognize(source)` |
30+
| Recognize a long file (hours, days) | `audd.recognizeEnterprise(source, { limit: ... })` |
31+
| Manage real-time stream recognition | `audd.streams.add({ url, radioId })` etc. |
32+
33+
`source` accepts a URL string, a `URL` object, a file path (Node only),
34+
a `Blob` / `File`, or a `Uint8Array` / `Buffer` — auto-detected.
35+
36+
The full TypeScript types ship in the package — no `@types/audd` needed.
37+
38+
## Errors
39+
40+
Every server error becomes a typed exception:
41+
42+
```ts
43+
import { AudD, AudDAuthenticationError, AudDSubscriptionError } from "audd";
44+
45+
try {
46+
await new AudD({ apiToken: "bad" }).recognize("https://x.mp3");
47+
} catch (e) {
48+
if (e instanceof AudDAuthenticationError) {
49+
console.log(`check your token: ${e.errorCode} ${e.serverMessage}`);
50+
} else if (e instanceof AudDSubscriptionError) {
51+
console.log("this endpoint isn't enabled on your token");
52+
} else {
53+
throw e;
54+
}
55+
}
56+
```
57+
58+
The full hierarchy is in [`src/errors.ts`](src/errors.ts). Every
59+
`AudDAPIError` carries `errorCode`, `serverMessage`, `httpStatus`,
60+
`requestId`, `requestedParams`, `requestMethod`, `brandedMessage`, and
61+
`rawResponse`.
62+
63+
## Forward compatibility
64+
65+
Models accept and round-trip unknown server fields via `extras`:
66+
67+
```ts
68+
const result = await audd.recognize("https://example.mp3", { return: ["apple_music"] });
69+
console.log(result?.appleMusic?.url); // typed
70+
console.log(result?.extras); // any unknown server fields
71+
console.log(result?.rawResponse); // full unparsed JSON object
72+
```
73+
74+
If AudD adds a new metadata block tomorrow (e.g., `tidal`), you can read
75+
it as `result.extras.tidal` *today* — no SDK release needed. The next SDK
76+
release adds the typed `tidal` field, and both paths keep working.
77+
78+
## Configuration
79+
80+
```ts
81+
import { AudD } from "audd";
82+
83+
const audd = new AudD({
84+
apiToken: "...",
85+
maxRetries: 3, // retry budget per call
86+
backoffFactorMs: 500, // initial backoff (ms), jittered, exponential
87+
fetch: customFetch, // bring your own fetch (proxy, mTLS, observability)
88+
});
89+
```
90+
91+
A single `AudD` instance is safe to share across concurrent requests;
92+
`setApiToken(...)` rotates the token without aborting in-flight calls.
93+
94+
Default timeouts: 60s for standard endpoints, **1 hour** for the
95+
enterprise endpoint. Pass `timeoutMs` per call to override.
96+
97+
## Streams
98+
99+
Manage real-time stream recognition and consume events:
100+
101+
```ts
102+
await audd.streams.add({ url: "https://stream.example/live.m3u8", radioId: "my-radio" });
103+
104+
for await (const event of audd.streams.longpoll("my-radio")) {
105+
console.log(event);
106+
}
107+
```
108+
109+
### Tokenless longpoll (browser / widget)
110+
111+
For browser or widget builds where you can't ship the api_token, the
112+
`LongpollConsumer` is exported from a separate sub-entry so bundlers
113+
tree-shake the auth client out:
114+
115+
```ts
116+
import { LongpollConsumer } from "audd/longpoll";
117+
118+
// `category` is derived server-side via
119+
// audd.streams.deriveLongpollCategory(radioId), then shipped to the
120+
// browser. The consumer carries no api_token.
121+
const consumer = new LongpollConsumer("abc123def");
122+
for await (const event of consumer.iterate({ timeout: 30 })) {
123+
console.log(event);
124+
}
125+
```
126+
127+
## Custom catalog (advanced — not for music recognition)
128+
129+
> **The custom-catalog endpoint is NOT how you submit audio for music
130+
> recognition.** For recognition, use `recognize()` or
131+
> `recognizeEnterprise()`. The custom-catalog endpoint adds songs to your
132+
> private fingerprint database for *your* account. Requires special
133+
> access — contact api@audd.io if you need it.
134+
135+
```ts
136+
await audd.customCatalog.add({
137+
audioId: 42,
138+
source: "https://my.song.mp3",
139+
});
140+
```
141+
142+
## Advanced
143+
144+
A generic raw-request escape hatch lets you call newly-shipped server
145+
methods before the SDK has a typed wrapper:
146+
147+
```ts
148+
const raw = await audd.advanced.rawRequest("someNewMethod", { q: "x" });
149+
```
150+
151+
## Resource cleanup
152+
153+
Both `AudD` and `LongpollConsumer` support
154+
[`Symbol.asyncDispose`](https://github.com/tc39/proposal-explicit-resource-management)
155+
where the runtime supports it. For older runtimes, call `close()`
156+
manually:
157+
158+
```ts
159+
{
160+
await using audd = new AudD({ apiToken: "..." });
161+
await audd.recognize("...");
162+
} // close() called automatically here
163+
```
164+
165+
## Spec contract
166+
167+
This SDK builds against the
168+
[`audd-openapi`](https://github.com/AudDMusic/audd-openapi) spec. The
169+
contract tests in `test/contract.test.ts` validate the parsers against
170+
the canonical fixture set on every push, on a daily cron, and on every
171+
spec update.
172+
173+
## License
174+
175+
MIT — see [LICENSE](./LICENSE).
176+
177+
## Support
178+
179+
- Documentation: https://docs.audd.io
180+
- Tokens: https://dashboard.audd.io
181+
- Email: api@audd.io

SECURITY.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Security Policy
2+
3+
## Reporting a vulnerability
4+
5+
If you discover a security issue in this SDK, please email **api@audd.io** privately. Do not open a public GitHub issue for security reports.
6+
7+
We will acknowledge receipt within 2 business days and coordinate disclosure with you.
8+
9+
## Scope
10+
11+
- **In scope:** vulnerabilities in this SDK's source code.
12+
- **Out of scope:** issues in upstream dependencies (file those with the upstream maintainer), or issues in the AudD service or API itself (email **api@audd.io** with subject `AudD service: <summary>`).
13+
14+
## Hardening practices
15+
16+
This SDK never logs `api_token`, request bodies, or response bodies. The `onEvent` inspection hook receives request / response / exception lifecycle events with method, URL, HTTP status, elapsed time, and request_id — but never the token or payload bytes.
17+

eslint.config.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import tseslint from "typescript-eslint";
2+
3+
export default tseslint.config(
4+
{
5+
ignores: ["dist/**", "node_modules/**"],
6+
},
7+
...tseslint.configs.recommended,
8+
{
9+
rules: {
10+
"@typescript-eslint/no-unused-vars": [
11+
"error",
12+
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
13+
],
14+
"@typescript-eslint/no-explicit-any": "off",
15+
"@typescript-eslint/consistent-type-imports": "error",
16+
},
17+
},
18+
);

0 commit comments

Comments
 (0)