Recipes
Copy-paste, single-capability snippets. Each assumes a constructed client:
import { Crate } from '@hosaka-fm/crate';const crate = new Crate({ apiKey: process.env.CRATE_API_KEY });Resolve an identity
Section titled “Resolve an identity”const id = await crate.resolve('Four Tet'); // name → identityconst byUrl = await crate.resolve('https://x.bandcamp.com'); // URL → identityconst byLoc = await crate.resolve({ discogs: 1234 }); // explicit locatorconsole.log(id.cluster_id, id.resolved_via, id.locators.bandcamp);Fetch an artist dossier
Section titled “Fetch an artist dossier”const a = await crate.artist('Four Tet'); // throws if a locator resolves to nothingconst maybe = await crate.artistOrNull('discogs:1'); // → ArtistDossierContract | nulla.discography; // pointer index of masters: { discogs_master_id, representative_name, _links.master }a.bandcamp_emergence; // bandcamp is a dimension of the dossier, not a separate resourceFetch a label dossier
Section titled “Fetch a label dossier”const label = await crate.label('warp-records'); // → LabelDossierContractTrim a dossier with ?fields=
Section titled “Trim a dossier with ?fields=”// Default-rich: one call returns the full dossier. Pass `fields` only to TRIM.const lean = await crate.artist('Four Tet', { fields: ['discography', 'bandcamp_emergence'] });// An unknown field name → CrateAPIError(code: 'invalid_fields').Search, breakouts, tastemakers
Section titled “Search, breakouts, tastemakers”const hits = await crate.search({ genre: ['idm', 'ambient'], year_from: 2000, limit: 20 });const breaking = await crate.breakouts();const board = await crate.tastemakers();const watch = await crate.tastemakers.onesToWatch();Handle a 429 with the SDK’s own retry metadata
Section titled “Handle a 429 with the SDK’s own retry metadata”import { isRateLimited } from '@hosaka-fm/crate';try { await crate.search({ q: 'jungle' });} catch (err) { if (isRateLimited(err)) { // The SDK already backed off; this is the server-directed ceiling. console.log('limit', err.rateLimit, 'retry after', err.retryAfter, 's'); } else throw err;}Cancel an in-flight call
Section titled “Cancel an in-flight call”const ac = new AbortController();const p = crate.search({ q: 'ambient' }, { signal: ac.signal });ac.abort(); // p rejects with CrateAbortError (never retried)More runnable examples in examples/.