npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@osiris-smarttv/beacon

v1.2.1

Published

Remote observability SDK for Smart TV web apps — PS5, Tizen, WebOS

Readme

@osiris-smarttv/beacon

Remote observability SDK for Smart TV web apps — PS5 browser, Tizen, webOS, and desktop lab builds.

Ship structured logs, network traces, performance gauges, Shaka/SSAI playback telemetry, and dual-stack Player Filmstrip observability to your telemetry gateway (POST /ingest), then visualize in Grafana (Loki · Tempo · Prometheus).

What's new in 1.2.0Shaka v4 + v5 dual support: pass shakaVersion: 'v4' | 'v5' (default 'v4') so one SDK works with Shaka ≥4.14 and ≥5.0; telemetry unchanged. See Shaka version.

What's new in 1.1.0Player Filmstrip: monitorShaka now fuses Shaka events + <video> events into a multi-lane per-playback_id session timeline (startup waterfall, stall classification, adaptation divergence, session-analytics rollup) with zero app instrumentation. Enabled by default. See Player Filmstrip.

npm package: published as @osiris-smarttv/beacon — ships compiled dist/ only (no TypeScript source).
Integration playbook for humans & AI: see RULE.md bundled in the package (node_modules/@osiris-smarttv/beacon/RULE.md).

Your app (browser / PS5 webview)
  logger.* / capture() / plugins
        │
        ▼
  FetchTransport → POST {endpoint}/ingest
        │
        ▼
  Your telemetry gateway → Loki / Tempo / Prometheus → Grafana

Install

npm install @osiris-smarttv/beacon

Install optional peers only for features you use:

# Shaka QoE + SSAI
npm install shaka-player

# Session replay
npm install rrweb

# Faro bridge (legacy)
npm install @grafana/faro-web-sdk

| Peer | Import subpath | Purpose | |------|----------------|---------| | shaka-player | @osiris-smarttv/beacon/plugins/shaka | QoE, session milestones, SSAI | | rrweb | @osiris-smarttv/beacon/plugins/rrweb | Session replay chunks | | @grafana/faro-web-sdk | @osiris-smarttv/beacon/plugins/faro | Faro bridge |


Quick start

import { init, destroy, logger } from '@osiris-smarttv/beacon'
import {
  monitorNetwork,
  monitorConsole,
  monitorPerformance,
} from '@osiris-smarttv/beacon'

const ENDPOINT = 'https://telemetry.example.com'   // your gateway base URL
const API_KEY  = 'your-api-key'                    // sent as X-App-Key header

init({
  endpoint: ENDPOINT,
  apiKey: API_KEY,
  app: {
    name:    'my-streaming-app',   // → Loki app_id label on gateway
    version: '1.2.0',
    build:   'ci-4821',
    env:     'uat',
  },
  plugins: [
    monitorNetwork({
      urlDenyList: [ENDPOINT, '/ingest', '/health'],
    }),
    monitorConsole(),
    monitorPerformance({ reportIntervalMs: 10_000 }),
  ],
})

logger.info('app.startup', 'Application ready', { route: '/home' })

// SPA unmount / teardown
await logger.flush()
destroy()

Environment variables (typical Vite / bundler setup)

| Variable | Purpose | |----------|---------| | VITE_BEACON_ENDPOINT | Gateway base URL | | VITE_BEACON_API_KEY | API key registered on gateway | | VITE_BEACON_APP_NAME | App id label | | VITE_BEACON_DEVICE_ID | Stable device identifier | | VITE_BEACON_APP_VERSION | App version label | | VITE_BEACON_APP_BUILD | Build / CI id label |

Gateway auth: every ingest request sends X-App-Key: <apiKey>. Your gateway operator maps keys to app_id (e.g. APP_KEYS=app_id:api_key).

CORS: the gateway must respond to browser preflight with Access-Control-Allow-Origin: * (or your app origin). The SDK uses standard fetch — no credentials mode.


What's in the npm package

| Path | Description | |------|-------------| | dist/index.{js,cjs,d.ts} | Core SDK | | dist/plugins/shaka.* | Shaka / SSAI plugin | | dist/plugins/rrweb.* | rrweb replay plugin | | dist/plugins/faro.* | Faro bridge | | README.md | This file | | RULE.md | Integration conventions + debug-case / Grafana playbook |

TypeScript types are included. Source maps are not published.


Three ways to emit telemetry

| API | Pipeline | Dedup / sample | Best for | |-----|----------|----------------|----------| | logger.* | Main | Yes | App logs, business events | | logger.track() | Breadcrumbs only | — | Context on next flush | | capture() | Monitor lane | No | Dense traces, plugin internals |

Logger

import { logger } from '@osiris-smarttv/beacon'

logger.setContext({ feature: 'checkout', contentId: 'movie-42' })

logger.debug('ui.click', 'Button pressed', { id: 'play' })
logger.info ('playback.user_action', 'User pressed play')
logger.warn ('network.slow', 'Manifest > 2s', { latencyMs: 2400 })
logger.error('player.error', 'Load failed', { code: 1001 })

const flow = logger.child({ component: 'ad-break', podIndex: 2 })
flow.info('ads.pod_start', 'Pod starting')
flow.end()

await logger.flush()

Capture (inside custom plugins)

client.capture({
  event:   'debug.my-case.step_3',
  message: 'Before seek',
  level:   'info',
  monitor: { kind: 'media' },
  context: { targetSec: 120, playhead: 45.2 },
})

Built-in plugins

| Plugin | Import | Emits | |--------|--------|-------| | monitorNetwork | @osiris-smarttv/beacon | monitor.network + traces | | monitorConsole | main | monitor.console | | monitorStorage | main | monitor.storage | | monitorPerformance | main | monitor.perf + device metrics | | monitorShaka | @osiris-smarttv/beacon/plugins/shaka | media.*, media.ssai.*, media.filmstrip.* |


Configuration reference

See TypeScript types in BeaconConfig (dist/index.d.ts). Highlights:

  • endpoint, apiKey, app — required
  • sampleRate (0–1), dedupWindowMs — set dedupWindowMs: 0 when debugging
  • batch — transport batching (batchSize, flushIntervalMs, monitorRealtime)
  • beforeSend, piiScrubbing, blockedFields — privacy hooks
  • plugins[] — monitor + custom plugins

Shaka Player plugin

import { monitorShaka, getSsaiTracker } from '@osiris-smarttv/beacon/plugins/shaka'

monitorShaka({
  player,
  videoElement: video,
  content: {
    id: 'asset-123',
    playbackId: crypto.randomUUID(),
    streamType: 'vod',
  },
  heartbeatMs: 10_000,
  session: { enabled: true },
  ads: { mode: 'custom' },
})

const ssai = getSsaiTracker(player)
ssai?.podStart({ podIndex: 0, availId: 'avail-1' })
ssai?.adStart({ adId: 'ad-1', creativeId: 'cr-1', durationMs: 15_000 })
ssai?.adComplete({ adId: 'ad-1' })
ssai?.podEnd({ podIndex: 0 })

Requires shaka-player peer dependency (>=4.14.0 for v4, >=5.0.0 for v5).

Shaka version (v1.2.0)

Set shakaVersion explicitly to match the Shaka build your app ships — there is no auto-detect. Default is 'v4' (existing integrations unchanged).

monitorShaka({
  shakaVersion: 'v5', // or 'v4' (default)
  player,
  videoElement: video,
})

| Version | Min Shaka | Notes | |---------|-----------|-------| | 'v4' (default) | 4.14.0 | Uses setTextTrackVisibility, texttrackvisibility event | | 'v5' | 5.0.0 | Uses selectAudioTrack / selectTextTrack; no setTextTrackVisibility |

configSchema validates the player API fingerprint at init — mismatches throw before listeners attach (e.g. declaring 'v5' on a v4 player).

Content context (v1.0.2+, optional)

Pass human-readable metadata on contentall fields optional except what you already use (id, playbackId). Old apps without these fields behave exactly as before; Grafana falls back to content_id.

import { monitorShaka, updateActiveProgram } from '@osiris-smarttv/beacon/plugins/shaka'

// VOD
monitorShaka({
  player, videoElement,
  content: {
    id: 'bb-s01e03',
    playbackId: crypto.randomUUID(),
    streamType: 'vod',
    title: 'Full Measure',
    series: { title: 'Breaking Bad', season: 1, episode: 3 },
  },
})

// Live + EPG refresh (same playbackId)
monitorShaka({
  player, videoElement,
  content: {
    id: 'vtv1-hd',
    playbackId: crypto.randomUUID(),
    streamType: 'live',
    channel: { id: 'vtv1-hd', name: 'VTV1' },
    program: { title: 'Thời sự 19h' },
  },
})
updateActiveProgram({ title: 'Phim tài liệu' }) // → media.content.update

Gateway promotes low-cardinality labels: stream_type, channel_id, content_kind. Titles stay in log body (displayName, program name).

Player Filmstrip (v1.1.0)

Reconstruct the full playback story for one playback_id — playback, buffering, quality, ABR, audio/subtitle, DRM, ads, config — with zero app-side instrumentation. monitorShaka attaches two synchronized listener grids (Shaka events + HTMLMediaElement events), fuses them, and reconciles state on each heartbeat. The app only passes player + videoElement (+ optional content.playbackId).

Enabled by default — no config needed. Tune or disable via filmstrip:

monitorShaka({
  player, videoElement,
  content: { id: 'asset-123', playbackId: crypto.randomUUID() },
  filmstrip: {
    enabled: true,        // default true — set false to opt out entirely
    dedupeMs: 100,        // cross-stack (Shaka↔video) dedupe window
    reconcileMs: 2000,    // heartbeat snapshot-diff quiet window
    proxyFallback: false, // wrap player.configure/track setters for Shaka
                          // builds that don't emit configurationchanged
  },
})

What it emits (all additive — existing media.* events unchanged):

| Signal | Where | Notes | |--------|-------|-------| | Normalized lane changes | Loki | media.filmstrip.*, extended media.quality / media.track.* / media.config.changed, media.video.* — carry lane, source (shaka_event | html_media | fused | reconcile | proxy) | | media.filmstrip.startup_waterfall | Loki | ms per milestone (loadstart → canplay → playing → shaka.loaded) | | media.filmstrip.stall_classified | Loki | type: initial_buffer | rebuffer | seek_buffer | decoder_stall | network_stall | | media.filmstrip.divergence | Loki | Shaka vs <video> mismatch (e.g. adaptation up but frame static) | | media.session.analytics | Loki | end-of-session rollup: time-in-grade, rebuffer score, ABR efficiency, engagement, stall breakdown, completion, divergence count | | Session-scoped gauges | Prometheus | beacon_media_playback_state, shaka_buffering, video_ready_state, video_network_state, abr_enabled, text_visible, drm_state, config_hash, playback_rate_x100, … labelled by playback_id |

High-frequency Shaka events (segmentappended, …) are metrics-only; whitelisted config keys only (never license URLs / tokens).

Gateway requirement: the filmstrip lanes are scoped by playback_id, so the gateway must stamp playback_id on media metric data points (already handled by the Osiris gateway toOtlpMetrics).

Grafana: the Player Filmstrip board (/d/osiris-player-filmstrip, Admin / Official only) renders these as synchronized state-timeline lanes + enterprise KPI row + causality log.

Manifest audits (v1.0.1+)

Opt-in HLS playlist audits run on every MANIFEST response 200 and emit media.manifest_audit (warn on violation, info on clean playlists with discontinuities, skipped on pure content playlists). Results are deduplicated per audit kind by manifest hash — a live playlist refreshed every ~4 s with identical content emits at most once.

monitorShaka({
  player, videoElement,
  manifest: {
    // Built-in rules — see below.
    audits: ['ssai-xmap-missing'],
    // Optional app-specific rule invoked alongside built-ins.
    onAudit: (uri, text) => { /* custom check */ },
  },
})

Built-in audits:

| Name | Rule | Fires when | |------|------|------------| | ssai-xmap-missing | Every #EXT-X-DISCONTINUITY must be followed by an #EXT-X-MAP within 6 non-empty lines | SSAI stitcher (MediaTailor / CDN splicer) forgets to restate the init segment after an ad-in/ad-out boundary — fMP4 playback stalls |

Event payload (under monitor.* — unwrap body first in LogQL):

{
  "auditKind": "ssai-xmap-missing",
  "uri": "https://cdn/live.m3u8",
  "hash": "a1b2c3d4",
  "bytes": 84210,
  "mediaSequence": 1200,
  "discontinuityCount": 28,
  "extXMapCount": 27,
  "violationCount": 1,
  "ok": false,
  "violations": [{ "discontinuityLine": 142, "windowLines": 6, "windowPreview": "…", "mediaSequenceHint": 1201 }]
}

The pure audit function is also exported for standalone use (e.g. gateway analyzer over media.manifest_raw):

import { auditHlsDiscontinuityMap } from '@osiris-smarttv/beacon/plugins/shaka'

const report = auditHlsDiscontinuityMap(playlistText)
if (!report.ok) console.warn('missing X-MAP', report.violations)

Custom plugins

import { createPlugin } from '@osiris-smarttv/beacon'

export const traceMyFeature = createPlugin<{ thresholdMs: number }>({
  name: 'my-app:feature-x',
  version: '1.0.0',
  setup(client, config) {
    // … hooks using client.capture() or logger via setup context …
    return () => { /* restore patches */ }
  },
})

Register in init({ plugins: [traceMyFeature({ thresholdMs: 500 })] }).


React / SPA lifecycle

import { init, destroy } from '@osiris-smarttv/beacon'

useEffect(() => {
  init({ /* config */ })
  return () => { void destroy() }
}, [])

init() resets any prior instance — safe for HMR / Strict Mode.


Event naming

| Prefix | Use | Affects shared SLO dashboards? | |--------|-----|--------------------------------| | app.* | Stable product events | Only if dashboards query them | | debug.<caseId>.* | Temporary investigation | No — safe sandbox | | media.* | Shaka playback QoE | Yes | | media.filmstrip.* | Filmstrip lane / stall / divergence / waterfall | Yes (Filmstrip board) | | media.session.analytics | End-of-session enterprise rollup | Yes (Filmstrip board) | | media.ssai.* | Ad lifecycle | Yes | | monitor.* | Auto-instrumentation | Monitor dashboards |

For obscure bugs, use debug.<caseId>.* + dedicated device_id. Details in RULE.md.


Investigation workflow (summary)

  1. Namespace: debug.<case-id>.<step>, device ps5-debug-<case-id>, app.env = 'lab-debug'
  2. Instrument with logger.* or capture()
  3. Query Grafana Explore (LogQL body unwrap: | json | line_format "{{.body}}" | json)
  4. Import a Scratch dashboard JSON (template in RULE.md §5)
  5. Promote stable events to app.* when done

Gateway contract

| Endpoint | Method | Auth | |----------|--------|------| | {endpoint}/ingest | POST JSON | X-App-Key | | {endpoint}/health | GET | — | | {endpoint}/replay-viewer.html | GET | — (if rrweb enabled) |

Request body:

{
  "sdk": { "name": "@osiris-smarttv/beacon", "version": "1.1.0" },
  "sent_at": "2026-07-02T12:00:00.000Z",
  "events": [{ "level": "info", "event": "app.startup", "message": "…", "timestamp": "…", "session": { … }, "app": { … }, "context": { } }]
}

Typical Loki labels (gateway-dependent): app_id, device_id, level, event, session_id, content_id, playback_id, stream_type, channel_id, content_kind, app_version, build, deploy_env.


Package exports

| Import | Symbols | |--------|---------| | @osiris-smarttv/beacon | init, destroy, logger, withScope, getInternals, monitors, ContentContext, setActiveContent, updateActiveProgram, types | | @osiris-smarttv/beacon/plugins/shaka | monitorShaka, getSsaiTracker, setActiveContent, updateActiveProgram, mapFromMediaTailorAvails, auditHlsDiscontinuityMap, MANIFEST_AUDIT_EVENT, SSAI + audit types | | @osiris-smarttv/beacon/plugins/rrweb | rrwebPlugin | | @osiris-smarttv/beacon/plugins/faro | faroPlugin |


AI assistants

If you use Cursor or other coding agents, copy RULE.md into your project docs or point the agent at:

node_modules/@osiris-smarttv/beacon/RULE.md

It defines debug namespaces, anti-patterns, and Grafana Scratch dashboard JSON templates.


License

MIT