@scarlett-player/hls 1.1.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -34,9 +34,19 @@ __export(index_exports, {
34
34
  default: () => index_default
35
35
  });
36
36
  module.exports = __toCommonJS(index_exports);
37
- var import_core = require("@scarlett-player/core");
38
37
 
39
38
  // src/hls-loader.ts
39
+ var hls_loader_exports = {};
40
+ __export(hls_loader_exports, {
41
+ createHlsInstance: () => createHlsInstance,
42
+ getHlsConstructor: () => getHlsConstructor,
43
+ isHLSSupported: () => isHLSSupported,
44
+ isHlsJsSupported: () => isHlsJsSupported,
45
+ loadHlsJs: () => loadHlsJs,
46
+ resetLoader: () => resetLoader,
47
+ shouldPreferNativeHLS: () => shouldPreferNativeHLS,
48
+ supportsNativeHLS: () => supportsNativeHLS
49
+ });
40
50
  var hlsConstructor = null;
41
51
  var loadingPromise = null;
42
52
  function supportsNativeHLS() {
@@ -44,6 +54,13 @@ function supportsNativeHLS() {
44
54
  const video = document.createElement("video");
45
55
  return video.canPlayType("application/vnd.apple.mpegurl") !== "";
46
56
  }
57
+ function shouldPreferNativeHLS() {
58
+ if (!supportsNativeHLS()) return false;
59
+ if (typeof navigator === "undefined") return false;
60
+ const ua = navigator.userAgent;
61
+ const isSafari = /Safari/.test(ua) && !/Chrome/.test(ua) && !/CriOS/.test(ua);
62
+ return isSafari;
63
+ }
47
64
  function isHlsJsSupported() {
48
65
  if (hlsConstructor) {
49
66
  return hlsConstructor.isSupported();
@@ -87,6 +104,13 @@ function createHlsInstance(config) {
87
104
  function getHlsConstructor() {
88
105
  return hlsConstructor;
89
106
  }
107
+ function resetLoader() {
108
+ hlsConstructor = null;
109
+ loadingPromise = null;
110
+ }
111
+
112
+ // src/create-hls-plugin.ts
113
+ var import_core = require("@scarlett-player/core");
90
114
 
91
115
  // src/quality.ts
92
116
  function formatLevel(level) {
@@ -418,7 +442,51 @@ function setupVideoEventHandlers(video, api) {
418
442
  };
419
443
  }
420
444
 
421
- // src/index.ts
445
+ // src/playlist-validation.ts
446
+ var PLAYLIST_INVALID_TEXT = "Invalid playlist document";
447
+ var MEDIA_PLAYLIST_CONTEXTS = ["level", "audioTrack", "subtitleTrack"];
448
+ function isValidPlaylistDocument(data, contextType) {
449
+ if (typeof data !== "string" || data.length === 0) return false;
450
+ const text = data.trimStart();
451
+ if (!text.startsWith("#EXTM3U")) return false;
452
+ if (contextType && MEDIA_PLAYLIST_CONTEXTS.includes(contextType)) {
453
+ return /^#EXT(?:INF|-X-TARGETDURATION):/m.test(text);
454
+ }
455
+ return true;
456
+ }
457
+ function createValidatingPlaylistLoader(Hls) {
458
+ const BaseLoader = Hls.DefaultConfig.loader;
459
+ return class ValidatingPlaylistLoader extends BaseLoader {
460
+ /**
461
+ * Load a playlist, validating the response document before it reaches
462
+ * the M3U8 parser.
463
+ *
464
+ * @param context - hls.js loader context
465
+ * @param config - hls.js loader config
466
+ * @param callbacks - hls.js loader callbacks
467
+ */
468
+ load(context, config, callbacks) {
469
+ const wrapped = {
470
+ ...callbacks,
471
+ onSuccess: (response, stats, ctx, networkDetails) => {
472
+ if (!isValidPlaylistDocument(response?.data, ctx?.type)) {
473
+ callbacks.onError(
474
+ { code: 0, text: PLAYLIST_INVALID_TEXT },
475
+ ctx,
476
+ networkDetails,
477
+ stats
478
+ );
479
+ return;
480
+ }
481
+ callbacks.onSuccess(response, stats, ctx, networkDetails);
482
+ }
483
+ };
484
+ super.load(context, config, wrapped);
485
+ }
486
+ };
487
+ }
488
+
489
+ // src/create-hls-plugin.ts
422
490
  var DEFAULT_CONFIG = {
423
491
  debug: false,
424
492
  autoStartLoad: true,
@@ -440,14 +508,16 @@ var DEFAULT_CONFIG = {
440
508
  autoReconnect: true,
441
509
  reconnectBaseDelayMs: 2e3,
442
510
  reconnectMaxDelayMs: 3e4,
443
- reconnectWindowMs: 3e5
511
+ reconnectWindowMs: 3e5,
512
+ // Never index a malformed live playlist refresh blindly
513
+ validatePlaylists: true
444
514
  };
445
515
  var MANIFEST_PHASE_ERRORS = [
446
516
  "manifestLoadError",
447
517
  "manifestLoadTimeOut",
448
518
  "manifestParsingError"
449
519
  ];
450
- function createHLSPlugin(config) {
520
+ function createHLSPluginWith(loader, variant, config) {
451
521
  const mergedConfig = { ...DEFAULT_CONFIG, ...config };
452
522
  let api = null;
453
523
  let hls = null;
@@ -457,6 +527,8 @@ function createHLSPlugin(config) {
457
527
  let cleanupHlsEvents = null;
458
528
  let cleanupVideoEvents = null;
459
529
  let isAutoQuality = true;
530
+ let loadSession = 0;
531
+ let abortPendingLoad = null;
460
532
  let networkRetryCount = 0;
461
533
  let mediaRetryCount = 0;
462
534
  let retryTimeout = null;
@@ -489,7 +561,9 @@ function createHLSPlugin(config) {
489
561
  api?.container.appendChild(video);
490
562
  return video;
491
563
  };
492
- const cleanup = () => {
564
+ const teardownPipeline = (reason) => {
565
+ abortPendingLoad?.(reason ?? new Error("HLS load cancelled"));
566
+ abortPendingLoad = null;
493
567
  cleanupHlsEvents?.();
494
568
  cleanupHlsEvents = null;
495
569
  cleanupVideoEvents?.();
@@ -502,6 +576,9 @@ function createHLSPlugin(config) {
502
576
  hls.destroy();
503
577
  hls = null;
504
578
  }
579
+ };
580
+ const cleanup = (reason) => {
581
+ teardownPipeline(reason);
505
582
  currentSrc = null;
506
583
  isNative = false;
507
584
  isAutoQuality = true;
@@ -510,7 +587,17 @@ function createHLSPlugin(config) {
510
587
  errorCount = 0;
511
588
  errorWindowStart = 0;
512
589
  };
513
- const buildHlsConfig = () => ({
590
+ const buildHlsConfig = () => {
591
+ const config2 = buildBaseHlsConfig();
592
+ if (mergedConfig.validatePlaylists !== false) {
593
+ const Hls = loader.getHlsConstructor();
594
+ if (Hls && Hls.DefaultConfig?.loader) {
595
+ config2.pLoader = createValidatingPlaylistLoader(Hls);
596
+ }
597
+ }
598
+ return config2;
599
+ };
600
+ const buildBaseHlsConfig = () => ({
514
601
  debug: mergedConfig.debug,
515
602
  autoStartLoad: mergedConfig.autoStartLoad,
516
603
  startPosition: mergedConfig.startPosition,
@@ -538,7 +625,21 @@ function createHLSPlugin(config) {
538
625
  const jitter = delay * (0.7 + Math.random() * 0.3);
539
626
  return jitter;
540
627
  };
628
+ const APPEND_ERROR_DETAILS = [
629
+ "bufferAppendError",
630
+ "bufferAppendingError",
631
+ "bufferAddCodecError"
632
+ ];
541
633
  const mapFatalErrorCode = (error) => {
634
+ if (error.response?.text === PLAYLIST_INVALID_TEXT) {
635
+ return import_core.ErrorCode.PLAYLIST_INVALID;
636
+ }
637
+ if (error.details === "bufferFullError") {
638
+ return import_core.ErrorCode.MEDIA_BUFFER_FULL;
639
+ }
640
+ if (APPEND_ERROR_DETAILS.includes(error.details)) {
641
+ return import_core.ErrorCode.MEDIA_APPEND_ERROR;
642
+ }
542
643
  switch (error.type) {
543
644
  case "network":
544
645
  return import_core.ErrorCode.MEDIA_NETWORK_ERROR;
@@ -563,7 +664,7 @@ function createHLSPlugin(config) {
563
664
  maybeScheduleReconnect(error);
564
665
  };
565
666
  const handleHlsError = (error) => {
566
- const Hls = getHlsConstructor();
667
+ const Hls = loader.getHlsConstructor();
567
668
  if (!Hls || !hls) return false;
568
669
  const now = Date.now();
569
670
  if (now - errorWindowStart > ERROR_WINDOW_MS) {
@@ -575,10 +676,7 @@ function createHLSPlugin(config) {
575
676
  if (errorCount >= MAX_ERRORS_IN_WINDOW) {
576
677
  api?.logger.error(`Too many errors (${errorCount} in ${ERROR_WINDOW_MS}ms), giving up`);
577
678
  emitFatalError(error, true);
578
- cleanupHlsEvents?.();
579
- cleanupHlsEvents = null;
580
- hls.destroy();
581
- hls = null;
679
+ teardownPipeline(new Error(error.details));
582
680
  return true;
583
681
  }
584
682
  if (error.fatal) {
@@ -599,8 +697,9 @@ function createHLSPlugin(config) {
599
697
  clearTimeout(retryTimeout);
600
698
  }
601
699
  const isManifestPhase = MANIFEST_PHASE_ERRORS.includes(error.details);
700
+ const retry_session = loadSession;
602
701
  retryTimeout = setTimeout(() => {
603
- if (!hls) return;
702
+ if (retry_session !== loadSession || !hls) return;
604
703
  if (isManifestPhase && currentSrc) {
605
704
  hls.loadSource(currentSrc);
606
705
  } else {
@@ -623,10 +722,10 @@ function createHLSPlugin(config) {
623
722
  if (retryTimeout) {
624
723
  clearTimeout(retryTimeout);
625
724
  }
725
+ const retry_session = loadSession;
626
726
  retryTimeout = setTimeout(() => {
627
- if (hls) {
628
- hls.recoverMediaError();
629
- }
727
+ if (retry_session !== loadSession || !hls) return;
728
+ hls.recoverMediaError();
630
729
  }, delay);
631
730
  break;
632
731
  }
@@ -638,6 +737,7 @@ function createHLSPlugin(config) {
638
737
  return false;
639
738
  };
640
739
  const loadNative = async (src) => {
740
+ const session = loadSession;
641
741
  const videoEl = getOrCreateVideo();
642
742
  isNative = true;
643
743
  if (api) {
@@ -645,7 +745,12 @@ function createHLSPlugin(config) {
645
745
  }
646
746
  return new Promise((resolve, reject) => {
647
747
  let watchdog = null;
748
+ let settled = false;
648
749
  const settle = () => {
750
+ settled = true;
751
+ if (abortPendingLoad === abort) {
752
+ abortPendingLoad = null;
753
+ }
649
754
  videoEl.removeEventListener("loadedmetadata", onLoaded);
650
755
  videoEl.removeEventListener("error", onError);
651
756
  if (watchdog !== null) {
@@ -653,7 +758,19 @@ function createHLSPlugin(config) {
653
758
  watchdog = null;
654
759
  }
655
760
  };
761
+ const abort = (reason) => {
762
+ if (settled) return;
763
+ settle();
764
+ reject(reason);
765
+ };
766
+ abortPendingLoad = abort;
656
767
  const onLoaded = () => {
768
+ if (settled) return;
769
+ if (session !== loadSession) {
770
+ settle();
771
+ reject(new Error("HLS load cancelled"));
772
+ return;
773
+ }
657
774
  settle();
658
775
  hasPlayedContent = true;
659
776
  const onFatalVideoError = () => {
@@ -677,6 +794,7 @@ function createHLSPlugin(config) {
677
794
  resolve();
678
795
  };
679
796
  const onError = () => {
797
+ if (settled) return;
680
798
  settle();
681
799
  const error = videoEl.error;
682
800
  reject(new Error(error?.message || "Failed to load HLS source"));
@@ -684,6 +802,7 @@ function createHLSPlugin(config) {
684
802
  const timeout_ms = mergedConfig.loadTimeoutMs ?? 3e4;
685
803
  if (timeout_ms > 0) {
686
804
  watchdog = setTimeout(() => {
805
+ if (settled || session !== loadSession) return;
687
806
  settle();
688
807
  reject(new Error("Video took too long to load (network timeout)"));
689
808
  }, timeout_ms);
@@ -695,10 +814,14 @@ function createHLSPlugin(config) {
695
814
  });
696
815
  };
697
816
  const loadWithHlsJs = async (src) => {
698
- await loadHlsJs();
817
+ const session = loadSession;
818
+ await loader.loadHlsJs();
819
+ if (session !== loadSession) {
820
+ throw new Error("HLS load cancelled");
821
+ }
699
822
  const videoEl = getOrCreateVideo();
700
823
  isNative = false;
701
- hls = createHlsInstance(buildHlsConfig());
824
+ hls = loader.createHlsInstance(buildHlsConfig());
702
825
  if (api) {
703
826
  cleanupVideoEvents = setupVideoEventHandlers(videoEl, api);
704
827
  }
@@ -715,10 +838,24 @@ function createHLSPlugin(config) {
715
838
  watchdog = null;
716
839
  }
717
840
  };
841
+ const abort = (reason) => {
842
+ if (resolved) return;
843
+ resolved = true;
844
+ clearWatchdog();
845
+ reject(reason);
846
+ };
847
+ abortPendingLoad = abort;
848
+ const releaseAbort = () => {
849
+ if (abortPendingLoad === abort) {
850
+ abortPendingLoad = null;
851
+ }
852
+ };
718
853
  cleanupHlsEvents = setupHlsEventHandlers(hls, api, {
719
854
  onManifestParsed: () => {
855
+ if (session !== loadSession) return;
720
856
  if (!resolved) {
721
857
  resolved = true;
858
+ releaseAbort();
722
859
  clearWatchdog();
723
860
  hasPlayedContent = true;
724
861
  api?.setState("source", { src, type: "application/x-mpegURL" });
@@ -729,14 +866,17 @@ function createHLSPlugin(config) {
729
866
  onLevelSwitched: () => {
730
867
  },
731
868
  onError: (error) => {
869
+ if (session !== loadSession) return;
732
870
  const terminal = handleHlsError(error);
733
871
  if (terminal && !resolved) {
734
872
  resolved = true;
873
+ releaseAbort();
735
874
  clearWatchdog();
736
875
  reject(new Error(error.details));
737
876
  }
738
877
  },
739
878
  onFragLoaded: () => {
879
+ if (session !== loadSession) return;
740
880
  if (networkRetryCount > 0 || mediaRetryCount > 0) {
741
881
  api?.logger.debug("Playback recovered, resetting retry budgets");
742
882
  networkRetryCount = 0;
@@ -748,17 +888,11 @@ function createHLSPlugin(config) {
748
888
  const timeout_ms = mergedConfig.loadTimeoutMs ?? 3e4;
749
889
  if (timeout_ms > 0) {
750
890
  watchdog = setTimeout(() => {
751
- if (resolved) return;
891
+ if (resolved || session !== loadSession) return;
752
892
  resolved = true;
893
+ releaseAbort();
753
894
  api?.logger.error(`HLS load timed out after ${timeout_ms}ms`, { src });
754
- if (retryTimeout) {
755
- clearTimeout(retryTimeout);
756
- retryTimeout = null;
757
- }
758
- cleanupHlsEvents?.();
759
- cleanupHlsEvents = null;
760
- hls?.destroy();
761
- hls = null;
895
+ teardownPipeline();
762
896
  reject(new Error("Video took too long to load (network timeout)"));
763
897
  }, timeout_ms);
764
898
  }
@@ -805,6 +939,7 @@ function createHLSPlugin(config) {
805
939
  };
806
940
  const attemptReconnect = async () => {
807
941
  if (!api || !currentSrc) return;
942
+ const session = ++loadSession;
808
943
  reconnectAttempts++;
809
944
  const saved_src = currentSrc;
810
945
  const was_live = api.getState("live");
@@ -812,27 +947,19 @@ function createHLSPlugin(config) {
812
947
  const resume_position = reconnectResumePosition;
813
948
  api.logger.info(`Auto-reconnect attempt ${reconnectAttempts}`, { src: saved_src });
814
949
  try {
815
- cleanupHlsEvents?.();
816
- cleanupHlsEvents = null;
817
- cleanupVideoEvents?.();
818
- cleanupVideoEvents = null;
819
- if (retryTimeout) {
820
- clearTimeout(retryTimeout);
821
- retryTimeout = null;
822
- }
823
- hls?.destroy();
824
- hls = null;
950
+ teardownPipeline(new Error("HLS load cancelled: reconnecting"));
825
951
  networkRetryCount = 0;
826
952
  mediaRetryCount = 0;
827
953
  errorCount = 0;
828
954
  errorWindowStart = 0;
829
955
  currentSrc = saved_src;
830
956
  api.setState("playbackState", "loading");
831
- if (was_native && supportsNativeHLS()) {
957
+ if (was_native && loader.supportsNativeHLS()) {
832
958
  await loadNative(saved_src);
833
959
  } else {
834
960
  await loadWithHlsJs(saved_src);
835
961
  }
962
+ if (session !== loadSession) return;
836
963
  if (!was_live && video && resume_position > 0) {
837
964
  video.currentTime = resume_position;
838
965
  }
@@ -846,18 +973,19 @@ function createHLSPlugin(config) {
846
973
  } catch {
847
974
  }
848
975
  } catch {
976
+ if (session !== loadSession) return;
849
977
  api?.logger.warn(`Auto-reconnect attempt ${reconnectAttempts} failed`);
850
978
  scheduleReconnectAttempt();
851
979
  }
852
980
  };
853
981
  const plugin = {
854
982
  id: "hls-provider",
855
- name: "HLS Provider",
983
+ name: variant.name,
856
984
  version: "1.0.0",
857
985
  type: "provider",
858
- description: "HLS playback provider using hls.js",
986
+ description: variant.description,
859
987
  canPlay(src) {
860
- if (!isHLSSupported()) return false;
988
+ if (!loader.isHLSSupported()) return false;
861
989
  const url = src.toLowerCase();
862
990
  const urlWithoutQuery = url.split("?")[0].split("#")[0];
863
991
  if (urlWithoutQuery.endsWith(".m3u8")) return true;
@@ -867,7 +995,7 @@ function createHLSPlugin(config) {
867
995
  },
868
996
  async init(pluginApi) {
869
997
  api = pluginApi;
870
- api.logger.info("HLS plugin initialized");
998
+ api.logger.info(`HLS plugin${variant.logSuffix} initialized`);
871
999
  const unsubPlay = api.on("playback:play", async () => {
872
1000
  if (!video) return;
873
1001
  try {
@@ -955,13 +1083,14 @@ function createHLSPlugin(config) {
955
1083
  });
956
1084
  },
957
1085
  async destroy() {
958
- api?.logger.info("HLS plugin destroying");
1086
+ api?.logger.info(`HLS plugin${variant.logSuffix} destroying`);
1087
+ loadSession++;
959
1088
  cancelReconnect();
960
1089
  if (onlineListener && typeof window !== "undefined") {
961
1090
  window.removeEventListener("online", onlineListener);
962
1091
  onlineListener = null;
963
1092
  }
964
- cleanup();
1093
+ cleanup(new Error("HLS load cancelled: player destroyed"));
965
1094
  if (video?.parentNode) {
966
1095
  video.parentNode.removeChild(video);
967
1096
  }
@@ -970,25 +1099,27 @@ function createHLSPlugin(config) {
970
1099
  },
971
1100
  async loadSource(src) {
972
1101
  if (!api) throw new Error("Plugin not initialized");
973
- api.logger.info("Loading HLS source", { src });
1102
+ api.logger.info(`Loading HLS source${variant.logSuffix}`, { src });
1103
+ const session = ++loadSession;
974
1104
  cancelReconnect();
975
1105
  hasPlayedContent = false;
976
- cleanup();
1106
+ cleanup(new Error("HLS load cancelled: superseded by a new load"));
977
1107
  currentSrc = src;
978
1108
  api.setState("playbackState", "loading");
979
1109
  api.setState("buffering", true);
980
- if (api.getState("airplayActive") && supportsNativeHLS()) {
1110
+ if (api.getState("airplayActive") && loader.supportsNativeHLS()) {
981
1111
  api.logger.info("Using native HLS (AirPlay active)");
982
1112
  await loadNative(src);
983
- } else if (isHlsJsSupported()) {
984
- api.logger.info("Using hls.js for HLS playback");
1113
+ } else if (loader.isHlsJsSupported()) {
1114
+ api.logger.info(`Using ${variant.engineLabel} for HLS playback`);
985
1115
  await loadWithHlsJs(src);
986
- } else if (supportsNativeHLS()) {
1116
+ } else if (loader.supportsNativeHLS()) {
987
1117
  api.logger.info("Using native HLS playback (hls.js not supported)");
988
1118
  await loadNative(src);
989
1119
  } else {
990
1120
  throw new Error("HLS playback not supported in this browser");
991
1121
  }
1122
+ if (session !== loadSession) return;
992
1123
  if (video) {
993
1124
  const muted = api.getState("muted");
994
1125
  const volume = api.getState("volume");
@@ -1040,7 +1171,7 @@ function createHLSPlugin(config) {
1040
1171
  api?.logger.debug("Already using native HLS");
1041
1172
  return;
1042
1173
  }
1043
- if (!supportsNativeHLS()) {
1174
+ if (!loader.supportsNativeHLS()) {
1044
1175
  api?.logger.warn("Native HLS not supported in this browser");
1045
1176
  return;
1046
1177
  }
@@ -1052,8 +1183,10 @@ function createHLSPlugin(config) {
1052
1183
  const wasPlaying = api?.getState("playing") || false;
1053
1184
  const currentTime = video?.currentTime || 0;
1054
1185
  const savedSrc = currentSrc;
1055
- cleanup();
1186
+ const session = ++loadSession;
1187
+ cleanup(new Error("HLS load cancelled: switching to native HLS"));
1056
1188
  await loadNative(savedSrc);
1189
+ if (session !== loadSession) return;
1057
1190
  if (video && currentTime > 0) {
1058
1191
  video.currentTime = currentTime;
1059
1192
  }
@@ -1075,7 +1208,7 @@ function createHLSPlugin(config) {
1075
1208
  api?.logger.debug("Already using hls.js");
1076
1209
  return;
1077
1210
  }
1078
- if (!isHlsJsSupported()) {
1211
+ if (!loader.isHlsJsSupported()) {
1079
1212
  api?.logger.warn("hls.js not supported in this browser");
1080
1213
  return;
1081
1214
  }
@@ -1087,8 +1220,10 @@ function createHLSPlugin(config) {
1087
1220
  const wasPlaying = api?.getState("playing") || false;
1088
1221
  const currentTime = video?.currentTime || 0;
1089
1222
  const savedSrc = currentSrc;
1090
- cleanup();
1223
+ const session = ++loadSession;
1224
+ cleanup(new Error("HLS load cancelled: switching to hls.js"));
1091
1225
  await loadWithHlsJs(savedSrc);
1226
+ if (session !== loadSession) return;
1092
1227
  if (video && currentTime > 0) {
1093
1228
  video.currentTime = currentTime;
1094
1229
  }
@@ -1104,6 +1239,20 @@ function createHLSPlugin(config) {
1104
1239
  };
1105
1240
  return plugin;
1106
1241
  }
1242
+
1243
+ // src/index.ts
1244
+ function createHLSPlugin(config) {
1245
+ return createHLSPluginWith(
1246
+ hls_loader_exports,
1247
+ {
1248
+ name: "HLS Provider",
1249
+ description: "HLS playback provider using hls.js",
1250
+ logSuffix: "",
1251
+ engineLabel: "hls.js"
1252
+ },
1253
+ config
1254
+ );
1255
+ }
1107
1256
  var index_default = createHLSPlugin;
1108
1257
  // Annotate the CommonJS export names for ESM import in node:
1109
1258
  0 && (module.exports = {
package/dist/index.d.cts CHANGED
@@ -1,17 +1,15 @@
1
- import { H as HLSPluginConfig, I as IHLSPlugin } from './types-DOzoPHQe.cjs';
2
- export { b as HLSError, c as HLSLiveInfo, a as HLSQualityLevel } from './types-DOzoPHQe.cjs';
1
+ import { H as HLSPluginConfig, I as IHLSPlugin } from './types-D-HW4lmM.cjs';
2
+ export { b as HLSError, c as HLSLiveInfo, a as HLSQualityLevel } from './types-D-HW4lmM.cjs';
3
3
  import '@scarlett-player/core';
4
4
 
5
5
  /**
6
6
  * HLS Provider Plugin for Scarlett Player
7
7
  *
8
8
  * Provides HLS playback using hls.js or native HLS (Safari).
9
- * Features:
10
- * - Lazy loading of hls.js
11
- * - Native HLS fallback for Safari
12
- * - Quality level management
13
- * - Error recovery
14
- * - Live stream support
9
+ * Thin wrapper around the shared factory in `create-hls-plugin.ts`; the
10
+ * light entry (`light.ts`) wraps the same factory with the hls.js/light
11
+ * loader, so both builds always carry identical error handling, retry,
12
+ * reconnect, and playlist-validation machinery.
15
13
  */
16
14
 
17
15
  /**
package/dist/index.d.ts CHANGED
@@ -1,17 +1,15 @@
1
- import { H as HLSPluginConfig, I as IHLSPlugin } from './types-DOzoPHQe.js';
2
- export { b as HLSError, c as HLSLiveInfo, a as HLSQualityLevel } from './types-DOzoPHQe.js';
1
+ import { H as HLSPluginConfig, I as IHLSPlugin } from './types-D-HW4lmM.js';
2
+ export { b as HLSError, c as HLSLiveInfo, a as HLSQualityLevel } from './types-D-HW4lmM.js';
3
3
  import '@scarlett-player/core';
4
4
 
5
5
  /**
6
6
  * HLS Provider Plugin for Scarlett Player
7
7
  *
8
8
  * Provides HLS playback using hls.js or native HLS (Safari).
9
- * Features:
10
- * - Lazy loading of hls.js
11
- * - Native HLS fallback for Safari
12
- * - Quality level management
13
- * - Error recovery
14
- * - Live stream support
9
+ * Thin wrapper around the shared factory in `create-hls-plugin.ts`; the
10
+ * light entry (`light.ts`) wraps the same factory with the hls.js/light
11
+ * loader, so both builds always carry identical error handling, retry,
12
+ * reconnect, and playlist-validation machinery.
15
13
  */
16
14
 
17
15
  /**