Track
Track is the queue item shape shared across adapter and consumer boundaries.
Use this page as the canonical source for track payload semantics used by queue operations, snapshot projections, and event payloads.
TrackType
Section titled “TrackType”TrackType is derived from TRACK_TYPES:
const TRACK_TYPES = ['file', 'progressive', 'hls', 'dash'] as const;type TrackType = (typeof TRACK_TYPES)[number];HeaderGroup
Section titled “HeaderGroup”HeaderGroup defines setup-scoped shared HTTP headers that tracks can reference through headerGroupId.
interface HeaderGroup { id: string; headers: Record<string, string>;}| Field | Type | Required | Notes |
|---|---|---|---|
id | string | Yes | Stable identifier referenced by Track.headerGroupId. |
headers | Record<string, string> | Yes | Static headers reused by tracks that reference this group. |
Track fields
Section titled “Track fields”| Field | Type | Required | Notes |
|---|---|---|---|
id | string | Yes | Stable track identifier for remove/skip operations. |
url | string | Yes | Playback URL consumed by native transport. |
title | string | No | Optional display metadata. |
artist | string | No | Optional display metadata. |
album | string | No | Optional display metadata. |
artwork | string | No | Optional artwork URL for lockscreen/notification surfaces. |
duration | number | No | Optional duration in seconds when known. |
type | TrackType | No | Declared media semantics used by native capability projectors. |
headerGroupId | string | No | Optional reference to a setup-scoped HeaderGroup. Unknown IDs fail fast at add() time. |
headers | Record<string, string> | No | Static per-track HTTP headers used by native playback transport. |
Header resolution precedence
Section titled “Header resolution precedence”When headerGroupId and headers are both present, resolution happens at queue admission time:
- group only → effective headers = group headers
- track only → effective headers = track headers
- both → effective headers =
{ ...group, ...track }(track wins per key) - neither → no auth headers
Important boundary: merged effective headers are runtime-internal. Consumers should treat snapshots/events as public projections and avoid relying on internal merged-request state.
What type means (and does NOT mean)
Section titled “What type means (and does NOT mean)”typeexpresses media-kind intent (file,progressive,hls,dash) used by runtime capability projection.typedoes NOT guarantee that a specific operation (for example seek) is always available.- Runtime decisions should combine track declaration with runtime projections and snapshot signals (for example nullable duration semantics).
headers scope and guarantees
Section titled “headers scope and guarantees”Based on the contract comments, v1 support scope is intentionally narrow:
- Applied by Android/iOS runtime media requests for that specific track.
- Isolated per track, not shared across queue transitions.
Shared groups do not replace per-track support. headers remains fully supported and is the per-track override path when both are present.
v1 non-goals explicitly documented in the contract:
- DRM or license-request authentication flows.
- Token refresh or dynamic auth callbacks.
- Cookie/session renewal orchestration.
What this means in practice:
headersis useful for static per-track request headers.headersis not an auth lifecycle engine and should not be treated as one.
Progressive examples
Section titled “Progressive examples”1) Minimal track
Section titled “1) Minimal track”import type { Track } from '@ddgutierrezc/legato-contract';
const track: Track = { id: 'song-42', url: 'https://cdn.example.com/song-42.mp3',};2) Metadata-rich track
Section titled “2) Metadata-rich track”const track: Track = { id: 'podcast-ep-12', url: 'https://cdn.example.com/podcast/ep-12.mp3', title: 'Episode 12', artist: 'Legato Studio', album: 'Season 2', artwork: 'https://cdn.example.com/podcast/ep-12.jpg', duration: 1620,};3) Typed track
Section titled “3) Typed track”const track: Track = { id: 'live-hour', url: 'https://stream.example.com/live.m3u8', type: 'hls',};4) Protected track with headers
Section titled “4) Protected track with headers”import type { Track } from '@ddgutierrezc/legato-contract';
const track: Track = { id: 'song-42', url: 'https://cdn.example.com/song-42.mp3', type: 'progressive', headers: { Authorization: 'Bearer demo-token', 'X-Client': 'mobile-app', },};5) Shared header group reference
Section titled “5) Shared header group reference”const track: Track = { id: 'song-43', url: 'https://cdn.example.com/song-43.mp3', type: 'progressive', headerGroupId: 'premium-us',};6) Group + per-track override
Section titled “6) Group + per-track override”const track: Track = { id: 'song-44', url: 'https://cdn.example.com/song-44.mp3', type: 'progressive', headerGroupId: 'premium-us', headers: { Authorization: 'Bearer one-off-override', },};Anti-patterns
Section titled “Anti-patterns”- Setting
type: 'hls'ortype: 'dash'and assuming seek is always available. Seek remains runtime-capability-dependent. - Omitting stable
idvalues (for example randomizing per render). Queue operations (remove,skip) depend on stable identifiers and indexes. - Treating
headersas shared global auth state across all queue items. Header scope is per track. - Assuming
headerGroupIdreplaces per-trackheaders. It does not; both can coexist, with per-track keys taking precedence. - Expecting unknown
headerGroupIdvalues to be ignored. Admission fails fast atadd()time. - Expecting
headersto solve token refresh, cookie renewal, or DRM license workflows. Those are out of contract v1 scope.