@jackmorgan/phaser-catalog
v0.2.0
Published
Typed REST client for the Phaser catalog API — tracks, artists, albums, genres, search, and playlists.
Downloads
271
Maintainers
Readme
@jackmorgan/phaser-catalog
Typed REST client for the Phaser catalog API. Covers tracks, artists, albums, genres, search, and playlists — zero dependencies, works in Node 20+ and every modern browser.
Install
npm install @jackmorgan/phaser-catalogQuick start
import { CatalogClient } from "@jackmorgan/phaser-catalog";
const catalog = new CatalogClient();
const page = await catalog.tracks({ q: "neon", sort: "newest", limit: 25 });
console.log(page.data); // Track[]
console.log(page.next_cursor); // string | null
const genres = await catalog.genres();
const result = await catalog.search("daft punk");The catalog API is open — no auth required for reads. For listener-scoped endpoints (/v1/me/*) you'll use the player package's auth flow separately.
Constructor
new CatalogClient({
apiUrl?: string; // default: "https://phaser-api.jackmorgan.xyz"
fetch?: typeof fetch; // default: global fetch
})Uses the global fetch in Node 20+ and browsers. Pass fetch to inject a custom transport (e.g. for tests or undici with custom agents).
Methods
Every method accepts an optional AbortSignal for cancellation.
catalog.tracks({ q?, genre?, artistId?, sort?, cursor?, limit?, signal? }): Promise<Paginated<Track>>
catalog.track(id, { signal? }): Promise<Track>
catalog.artists({ q?, cursor?, limit?, signal? }): Promise<Paginated<Artist>>
catalog.artist(id, { signal? }): Promise<Artist>
catalog.artistTracks(id, { cursor?, limit?, signal? }): Promise<Paginated<Track>>
catalog.album(id, { signal? }): Promise<Album>
catalog.genres({ signal? }): Promise<Genre[]>
catalog.search(q, { limit?, signal? }): Promise<SearchResult>
catalog.playlist(id, { signal? }): Promise<Playlist>sort accepts "newest" | "popular". All paginated responses have the shape { data: T[]; next_cursor: string | null; has_more: boolean }.
Cancellation
const ac = new AbortController();
const promise = catalog.tracks({ q: "neon", signal: ac.signal });
ac.abort();Errors
Non-2xx responses throw a typed CatalogError. Subclasses narrow common cases:
import {
CatalogError,
CatalogAuthError,
CatalogNotFoundError,
CatalogRateLimitError,
} from "@jackmorgan/phaser-catalog";
try {
await catalog.track("trk_missing");
} catch (err) {
if (err instanceof CatalogNotFoundError) {
// 404
} else if (err instanceof CatalogAuthError) {
// 401 / 403
} else if (err instanceof CatalogRateLimitError) {
console.log("retry after", err.retryAfter);
} else if (err instanceof CatalogError) {
console.log(err.status, err.code, err.message);
}
}Every error carries { status, code, message, url?, body? }. Network failures (DNS, connection reset) propagate as the underlying TypeError / AbortError from fetch.
Types
import type {
Track, Artist, Album, Genre, Playlist,
SearchResult, Paginated, TrackSort,
} from "@jackmorgan/phaser-catalog";Types mirror the catalog API payloads documented at https://phaser-docs.jackmorgan.xyz.
Pairing with @jackmorgan/phaser-player
import { CatalogClient } from "@jackmorgan/phaser-catalog";
import { Player } from "@jackmorgan/phaser-player";
const catalog = new CatalogClient();
const player = new Player();
const page = await catalog.tracks({ sort: "newest" });
await player.load(page.data[0].id);
await player.play();License
MIT
