- Defensive null check on video.play() return value (jsdom returns undefined) - Fix test mock: win.Hls (not win.HLS) to match viewer.js window.Hls reference - All 39/39 tests now pass
- viewer.js: dynamic hls.js loading, HLS-aware panel creation, error handling - schema.json: hlsManifest and mediaType fields (optional, backward compatible) - types.ts: VideoEntry interface with MediaType type - isHls() null guard fix - tests: 39 tests (schema, viewer units, data flow, integration) - CI: GitHub/Gitea Actions workflow (npm test on push/PR) - deps: ajv, ajv-formats, jsdom for testing