Data models
Data models
Canonical type definitions. All types are defined as TypeScript interfaces (authoritative for the API spec). Rust serde structs must match exactly — the TypeScript types are the source of truth.
The core does not transform types between plugin↔core and core↔frontend boundaries. The one exception: core adds id (UUID) and added_at on library save — those fields don’t exist in plugin-originated data.
Track
interface Track {
id: string; // core UUID (assigned on library save)
plugin_id: string; // which plugin provided this
content_id: string; // plugin-scoped foreign ID
title: string;
duration_ms: number | null;
artist: ArtistStub; // required
album: AlbumStub | null;
cover_art_url: string | null;
explicit: boolean;
added_at: string | null; // ISO 8601, set on library save
}
Album
interface Album {
id: string; // core UUID
plugin_id: string;
content_id: string; // plugin-scoped foreign ID
title: string;
artist: ArtistStub;
cover_art_url: string | null;
track_count: number | null;
release_year: number | null;
tracks: TrackStub[]; // stubs only — full tracks via get_track
}
Artist
interface Artist {
id: string; // core UUID
plugin_id: string;
content_id: string;
name: string;
bio: string | null;
image_url: string | null;
}
Playlist
interface Playlist {
id: string; // core UUID
name: string;
description: string | null;
created_at: string; // ISO 8601
tracks: TrackStub[];
}
Stub types
interface TrackStub {
plugin_id: string;
content_id: string;
title: string;
duration_ms: number | null;
artist_name: string;
}
interface ArtistStub {
id: string | null; // null if not addressable
name: string;
}
interface AlbumStub {
id: string | null; // null if not addressable
title: string;
cover_art_url: string | null;
}
id: null on stubs is valid — not every plugin models artists/albums as addressable entities.
SearchResult
interface SearchResult {
plugin_id: string; // which plugin returned this
content_id: string; // plugin-scoped foreign ID
title: string;
duration_ms: number | null;
artist: ArtistStub; // required minimum
album: AlbumStub | null;
cover_art_url: string | null;
explicit: boolean;
}
StreamInfo
interface StreamInfo {
url: string;
content_type: string; // "audio/mpeg", "audio/flac", "audio/ogg", etc.
duration_ms: number | null; // plugin may not know
file_size_bytes: number | null;
expires_at: string | null; // ISO 8601 — for signed URLs that expire
}
Field requirements
Required fields are those with non-nullable types above.
cover_art_urlis always optional — plugins frequently don’t have it.duration_msis optional — some streaming sources don’t expose it until the stream is opened.- No thumbnail vs full-size distinction in v1. One URL; plugins return whatever they have.
References
- ADR-003 (UUIDv4 content IDs)
- FR-MUSIC-1 (browse by album/artist)