@hexdn/playback
v0.1.3
Published
HexDN browser playback runtime and protected HLS integration.
Readme
@hexdn/playback
Framework-neutral playback for a real HTMLVideoElement. The controller owns
lazy HLS loading, protected requests, credential renewal, bounded recovery,
captions, volume, and observable playback state. It has no React or analytics
dependency. For ready-made controls, use @hexdn/react/player.
import { createPlaybackController } from "@hexdn/playback";
const playback = createPlaybackController(video, {
source: { sourceUrl: "https://cdn.example/video/master.m3u8" },
});
const unsubscribe = playback.subscribe(() => {
renderControls(playback.getSnapshot());
});
await playback.play();
playback.seek(42); // seconds
playback.pause();
unsubscribe();
playback.destroy();A ready source attaches without a backend handshake. State exposes position,
duration, buffering/readiness, errors, captions and volume. Progress
observations use milliseconds and remain available without analytics. Add an
optional onProgress callback to persist resume state using your own product
rules. getSnapshot() returns the same object until state changes; subscribe
does not emit an initial event.
For protected video, keep authorization on your server. Supply a tenant endpoint
that returns the SDK source descriptor produced by @hexdn/sdk:
import {
createPlaybackController,
createPlaybackSourceEndpoint,
} from "@hexdn/playback";
const playback = createPlaybackController(video, {
getSource: createPlaybackSourceEndpoint({
endpoint: "/api/videos/123/playback",
}),
autoPlay: true,
});The endpoint uses POST by default and same-origin credentials. It must recheck
viewer access on renewal. A custom getSource({ reason, signal }) supports
other tenant transports; honor its abort signal. Browser packages never receive
server API credentials.
For signed playback, the endpoint can return
hexdn.playback.createSignedSource(). Its descriptor includes expiresAt; the
controller renews through the same endpoint before expiry, without proof
headers. Updating only the expiry adjusts the renewal schedule without reloading
the video.
refresh() coalesces concurrent renewal and preserves position and play/pause
intent and playback speed. setSource(next) also preserves those for the same
logical video, reuses a compatible HLS engine, and avoids reloading equivalent
descriptors. Source descriptors use playbackId as their default identity;
external sources without an ID use their URL. An explicit identity overrides
that default. A different identity resets position and intent; optionally supply
initialPositionMs. retry() starts a fresh recovery budget after a terminal
playback failure. Destroy the controller when leaving the playback surface.
createPlaybackPreparation() provides bounded metadata/key preloading and
explicit-play engine preparation. Pass its integration to the controller or
React player so the mounted player adopts the prepared engine. preload(source)
warms metadata; warm(source) prepares media after play intent;
discardPrepared() retires an abandoned engine while retaining metadata;
clear() invalidates all prepared resources. Preparation itself does not count
as a viewing attempt. Applications with principal changes should supply
isInvalidated and clear preparation when access changes.
createPlaybackPreferences({ captionsKey, volumeKey }) preserves an
application's existing preference keys. The default controller uses scoped HexDN
keys and continues playing when local storage is unavailable.
Request helpers are advanced integration points for applications with an
existing request boundary. Proof-bearing fetches reject redirects and omit
referrers. @hexdn/playback/internal is unsupported and reserved for the
matching HexDN React release and package tests; tenants should use the top-level
API.
