@syra.fm/sdk
v0.7.0
Published
Syra SDK — headless, isomorphic catalog client (Node/React-free, public reads + 30s previews) that also ships the Syra live-rooms engine (audio rooms over LiveKit) on React Native and web.
Maintainers
Readme
@syra.fm/sdk
Isomorphic client for the public Syra API. The package resolves per platform via export conditions:
- Node / bundlers (
require/import) get the headless catalog client — runs on Node 18+ and browsers, no React, React Native, or DOM dependencies; the only runtime dependency iszod. Public reads only (no authentication in this version). - React Native (Metro) and Expo web (
browser) additionally get the live-rooms engine (audio rooms over LiveKit) and theSyraIconbrand mark. Its React Native / LiveKit / Expo dependencies are declared as optional peer dependencies, so headless Node consumers never install them.
Everyone imports from the same @syra.fm/sdk root — the condition picks the
right surface.
Install
bun add @syra.fm/sdkUsage
import { createSyraClient } from '@syra.fm/sdk';
const syra = createSyraClient(); // defaults to https://api.syra.fm
// Search the catalog — returns one page; only tracks with a public preview are
// in `items`. Paginate for infinite scroll by advancing `offset` by `limit`.
const page = await syra.searchTracks('lofi beats', { limit: 10, offset: 0 });
if (page.hasMore) {
const next = await syra.searchTracks('lofi beats', { limit: 10, offset: 10 });
}
// Fetch a single track
const track = await syra.getTrack(page.items[0].id);
// Build a public 30s preview URL (directly playable MP3)
const url = syra.previewUrl(track.id); // .../api/preview/<id>.mp3?start=0
const hook = syra.previewUrl(track.id, 45); // start 45s in
// Resolve artwork to an absolute URL
const cover = syra.artworkUrl(track, 'large');Options
createSyraClient({
baseURL: 'https://api.syra.fm', // override the API origin
fetch, // inject a fetch implementation (e.g. node-fetch)
});fetch defaults to the global fetch. It is the seam through which an
authenticated transport can be layered in a future version.
API
| Method | Description |
| --- | --- |
| searchTracks(query, { limit, offset }) | A SearchPage<TrackSummary> of preview-available tracks ({ items, hasMore, limit, offset }). |
| getTrack(id) | A single TrackSummary, schema-validated. |
| previewUrl(id, startSec = 0) | Public 30s preview URL. |
| artworkUrl(trackOrCoverArt, size?) | Absolute artwork URL, or undefined. |
| searchPodcasts(query, { limit, offset }) | A SearchPage<PodcastSummary> of podcast shows. |
| getPodcast(id) | A single PodcastSummary, schema-validated. |
| podcastUrl(id) | Syra web deep link (/podcasts/:id). |
| podcastArtworkUrl(show, size?) | Absolute show-artwork URL, or undefined. |
hasMore reflects the backend's pagination over the full result set, so it is
not affected by the client-side preview filter on searchTracks — paginate by
advancing offset by limit, never by items.length.
Responses are validated at runtime with the package's own self-contained Zod
schemas (trackSummarySchema), so there are no shared internal dependencies.
SyraApiError (with a status) is thrown on non-2xx responses.
Live rooms (React Native)
On React Native and Expo web, the same root export also carries the live-rooms engine — providers, hooks, components, and icons:
import {
LiveRoomProvider,
useRoomAudio,
RoomCard,
createRoomsService,
SyraIcon, // Syra brand mark
} from '@syra.fm/sdk';These require the optional peer dependencies (react-native, livekit-client,
@livekit/react-native, expo-audio, react-native-svg, …) — present in any
Expo/React Native app, absent from headless Node consumers.
