Skip to content

feat(core): add native hls error handling#1190

Merged
luwes merged 7 commits intomainfrom
native-error
Apr 3, 2026
Merged

feat(core): add native hls error handling#1190
luwes merged 7 commits intomainfrom
native-error

Conversation

@luwes
Copy link
Copy Markdown
Collaborator

@luwes luwes commented Apr 1, 2026

fix #982


Note

Medium Risk
Touches core media event forwarding (ProxyMixin, DelegateMixin, CustomMediaMixin) and error propagation for both hls.js and native playback, which could subtly change how consumers receive/stop events. Coverage is improved with new unit tests, but the behavioral shift is cross-cutting.

Overview
Adds native HLS error enrichment by introducing NativeHlsMediaErrorsMixin, which intercepts native <video> error events, stops their propagation, and re-dispatches an enriched ErrorEvent carrying a MediaError (cleared on emptied/detach/destroy).

Refactors event bridging/proxying: extracts bridgeEvents into core/utils, updates DelegateMixin attach ordering, reworks ProxyMixin to forward target events onto the proxy’s own EventTarget listeners, and changes CustomMediaMixin to defer forwarding captured non-bubbling media events so consumer stopPropagation semantics still work.

Renames HLS mixins to HlsJs* variants and adjusts hls.js fatal error message handling (data.error?.message), adds extensive new tests for ProxyMixin, delegate/proxy attach ordering, and native HLS error behavior, and adds new sandbox templates to demo native-hls-video in both HTML and React.

Written by Cursor Bugbot for commit bb37e45. This will update automatically on new commits. Configure here.

@luwes luwes self-assigned this Apr 1, 2026
@netlify
Copy link
Copy Markdown

netlify bot commented Apr 1, 2026

Deploy Preview for vjs10-site ready!

Name Link
🔨 Latest commit bb37e45
🔍 Latest deploy log https://app.netlify.com/projects/vjs10-site/deploys/69cf0ba82bd01000089c37f4
😎 Deploy Preview https://deploy-preview-1190--vjs10-site.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
v10-sandbox Ready Ready Preview, Comment Apr 3, 2026 0:37am

Request Review

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

📦 Bundle Size Report

🎨 @videojs/html

Path Base PR Diff %
/media/native-hls-video 3.03 kB 3.54 kB +525 B +16.9% 🔴
Presets (7)
Entry Size
/video (default) 24.92 kB
/video (default + hls) 156.64 kB
/video (minimal) 24.82 kB
/video (minimal + hls) 156.73 kB
/audio (default) 23.00 kB
/audio (minimal) 23.01 kB
/background 6.89 kB
Media (7)
Entry Size
/media/background-video 1.04 kB
/media/container 1.59 kB
/media/dash-video 236.35 kB
/media/hls-video 133.34 kB
/media/mux-video 156.05 kB
/media/native-hls-video 3.54 kB
/media/simple-hls-video 14.96 kB
Players (3)
Entry Size
/video/player 6.62 kB
/audio/player 6.61 kB
/background/player 6.60 kB
Skins (17)
Entry Type Size
/video/minimal-skin.css css 3.42 kB
/video/skin.css css 3.44 kB
/video/minimal-skin js 24.83 kB
/video/minimal-skin.tailwind js 25.13 kB
/video/skin js 24.87 kB
/video/skin.tailwind js 25.25 kB
/audio/minimal-skin.css css 2.48 kB
/audio/skin.css css 2.45 kB
/audio/minimal-skin js 23.01 kB
/audio/minimal-skin.tailwind js 23.22 kB
/audio/skin js 23.00 kB
/audio/skin.tailwind js 23.29 kB
/background/skin.css css 117 B
/background/skin js 1.15 kB
/base.css css 157 B
/shared.css css 88 B
/skin-element js 1.34 kB
UI Components (22)
Entry Size
/ui/alert-dialog 1.93 kB
/ui/alert-dialog-close 1.70 kB
/ui/alert-dialog-description 1.68 kB
/ui/alert-dialog-title 1.62 kB
/ui/buffering-indicator 1.67 kB
/ui/captions-button 2.00 kB
/ui/controls 1.66 kB
/ui/error-dialog 2.16 kB
/ui/fullscreen-button 1.98 kB
/ui/mute-button 2.02 kB
/ui/pip-button 2.01 kB
/ui/play-button 2.05 kB
/ui/playback-rate-button 1.78 kB
/ui/popover 1.77 kB
/ui/poster 1.59 kB
/ui/seek-button 2.01 kB
/ui/slider 1.70 kB
/ui/thumbnail 1.98 kB
/ui/time 1.75 kB
/ui/time-slider 2.18 kB
/ui/tooltip 2.30 kB
/ui/volume-slider 2.33 kB

Sizes are marginal over the root entry point.

⚛️ @videojs/react

Path Base PR Diff %
/media/native-hls-video 2.96 kB 3.50 kB +554 B +18.3% 🔴
Presets (7)
Entry Size
/video (default) 19.83 kB
/video (default + hls) 151.71 kB
/video (minimal) 19.89 kB
/video (minimal + hls) 151.76 kB
/audio (default) 16.65 kB
/audio (minimal) 16.70 kB
/background 3.13 kB
Media (6)
Entry Size
/media/background-video 476 B
/media/dash-video 236.39 kB
/media/hls-video 133.25 kB
/media/mux-video 155.98 kB
/media/native-hls-video 3.50 kB
/media/simple-hls-video 15.03 kB
Skins (14)
Entry Type Size
/video/minimal-skin.css css 3.35 kB
/video/skin.css css 3.37 kB
/video/minimal-skin js 19.81 kB
/video/minimal-skin.tailwind js 23.28 kB
/video/skin js 19.77 kB
/video/skin.tailwind js 23.36 kB
/audio/minimal-skin.css css 2.38 kB
/audio/skin.css css 2.34 kB
/audio/minimal-skin js 16.63 kB
/audio/minimal-skin.tailwind js 19.12 kB
/audio/skin js 16.58 kB
/audio/skin.tailwind js 19.10 kB
/background/skin.css css 90 B
/background/skin js 272 B
UI Components (19)
Entry Size
/ui/alert-dialog 1.52 kB
/ui/buffering-indicator 1.22 kB
/ui/captions-button 1.83 kB
/ui/controls 1.18 kB
/ui/error-dialog 1.64 kB
/ui/fullscreen-button 1.82 kB
/ui/mute-button 1.83 kB
/ui/pip-button 1.84 kB
/ui/play-button 1.86 kB
/ui/playback-rate-button 1.31 kB
/ui/popover 2.94 kB
/ui/poster 1.12 kB
/ui/seek-button 1.83 kB
/ui/slider 2.32 kB
/ui/thumbnail 1.41 kB
/ui/time 1.95 kB
/ui/time-slider 2.69 kB
/ui/tooltip 2.14 kB
/ui/volume-slider 2.82 kB

Sizes are marginal over the root entry point.

🧩 @videojs/core

Path Base PR Diff %
/dom/media/native-hls 2.38 kB 2.90 kB +533 B +21.9% 🔴
Entries (8)
Entry Size
. 5.27 kB
/dom 8.89 kB
/dom/media/custom-media-element 1.82 kB
/dom/media/dash 235.73 kB
/dom/media/hls 132.79 kB
/dom/media/mux 155.45 kB
/dom/media/native-hls 2.90 kB
/dom/media/simple-hls 14.43 kB
🏷️ @videojs/element — no changes
Entries (2)
Entry Size
. 999 B
/context 943 B
📦 @videojs/store — no changes
Entries (3)
Entry Size
. 1.39 kB
/html 696 B
/react 360 B
🔧 @videojs/utils — no changes
Entries (10)
Entry Size
/array 104 B
/dom 1.53 kB
/events 319 B
/function 261 B
/object 247 B
/predicate 265 B
/string 148 B
/style 190 B
/time 478 B
/number 158 B
📦 @videojs/spf — no changes
Entries (3)
Entry Size
. 40 B
/dom 12.45 kB
/playback-engine 12.41 kB

ℹ️ How to interpret

All sizes are standalone totals (minified + brotli).

Icon Meaning
No change
🔺 Increased ≤ 10%
🔴 Increased > 10%
🔽 Decreased
🆕 New (no baseline)

Run pnpm size locally to check current sizes.

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Stale error state after source change in native path
    • Added 'emptied' event listener to clear #error field on source changes, matching browser behavior and hls.js pattern.

Create PR

Or push these changes by commenting:

@cursor push 3077e33124
Preview (3077e33124)
diff --git a/packages/core/src/dom/media/native-hls/errors.ts b/packages/core/src/dom/media/native-hls/errors.ts
--- a/packages/core/src/dom/media/native-hls/errors.ts
+++ b/packages/core/src/dom/media/native-hls/errors.ts
@@ -54,6 +54,15 @@
         },
         { signal: this.#disconnect.signal }
       );
+
+      listen(
+        target,
+        'emptied',
+        () => {
+          this.#error = null;
+        },
+        { signal: this.#disconnect.signal }
+      );
     }
 
     #destroy(): void {

diff --git a/packages/core/src/dom/media/native-hls/tests/errors.test.ts b/packages/core/src/dom/media/native-hls/tests/errors.test.ts
--- a/packages/core/src/dom/media/native-hls/tests/errors.test.ts
+++ b/packages/core/src/dom/media/native-hls/tests/errors.test.ts
@@ -181,4 +181,17 @@
     const event = handler.mock.calls[0]![0] as ErrorEvent;
     expect(event.error.code).toBe(MediaError.MEDIA_ERR_NETWORK);
   });
+
+  it('clears error on emptied event (source change)', () => {
+    const { host, video } = setup();
+
+    fireNativeError(video, MediaError.MEDIA_ERR_NETWORK, 'network failure');
+
+    expect(host.error).not.toBeNull();
+    expect(host.error!.code).toBe(MediaError.MEDIA_ERR_NETWORK);
+
+    video.dispatchEvent(new Event('emptied'));
+
+    expect(host.error).toBeNull();
+  });
 });

This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

Comment thread packages/core/src/dom/media/native-hls/errors.ts
Comment thread packages/core/src/dom/media/native-hls/errors.ts
Comment thread packages/core/src/core/media/proxy.ts
Comment thread packages/core/src/core/utils/bridge-events.ts
Comment thread packages/core/src/dom/media/hls/errors.ts Outdated
Comment thread packages/core/src/dom/media/native-hls/errors.ts
Comment thread packages/core/src/core/media/proxy.ts
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Comment thread packages/core/src/core/media/proxy.ts
@luwes luwes merged commit 5239b9b into main Apr 3, 2026
21 checks passed
@luwes luwes deleted the native-error branch April 3, 2026 03:25
@luwes luwes mentioned this pull request Apr 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hls.js Error Handling

1 participant