stormcloud-video-player 0.3.53 → 0.3.55

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.
@@ -177,9 +177,17 @@ function _ts_generator(thisArg, body) {
177
177
  },
178
178
  trys: [],
179
179
  ops: []
180
- }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
181
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() {
182
- return this;
180
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
181
+ return d(g, "next", {
182
+ value: verb(0)
183
+ }), d(g, "throw", {
184
+ value: verb(1)
185
+ }), d(g, "return", {
186
+ value: verb(2)
187
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
188
+ value: function() {
189
+ return this;
190
+ }
183
191
  }), g;
184
192
  function verb(n) {
185
193
  return function(v) {
@@ -279,20 +287,20 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
279
287
  var __getOwnPropNames = Object.getOwnPropertyNames;
280
288
  var __getProtoOf = Object.getPrototypeOf;
281
289
  var __hasOwnProp = Object.prototype.hasOwnProperty;
282
- var __export = function(target, all) {
290
+ var __export = function __export(target, all) {
283
291
  for(var name in all)__defProp(target, name, {
284
292
  get: all[name],
285
293
  enumerable: true
286
294
  });
287
295
  };
288
- var __copyProps = function(to, from, except, desc) {
296
+ var __copyProps = function __copyProps(to, from, except, desc) {
289
297
  if (from && (typeof from === "undefined" ? "undefined" : _type_of(from)) === "object" || typeof from === "function") {
290
298
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
291
299
  try {
292
300
  var _loop = function() {
293
301
  var key = _step.value;
294
302
  if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
295
- get: function() {
303
+ get: function get() {
296
304
  return from[key];
297
305
  },
298
306
  enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
@@ -316,7 +324,7 @@ var __copyProps = function(to, from, except, desc) {
316
324
  }
317
325
  return to;
318
326
  };
319
- var __toESM = function(mod, isNodeMode, target) {
327
+ var __toESM = function __toESM(mod, isNodeMode, target) {
320
328
  return target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(// If the importer is in node compatibility mode or this is not an ESM
321
329
  // file that has been converted to a CommonJS file using a Babel-
322
330
  // compatible transform (i.e. "__esModule" has not been set), then set
@@ -326,7 +334,7 @@ var __toESM = function(mod, isNodeMode, target) {
326
334
  enumerable: true
327
335
  }) : target, mod);
328
336
  };
329
- var __toCommonJS = function(mod) {
337
+ var __toCommonJS = function __toCommonJS(mod) {
330
338
  return __copyProps(__defProp({}, "__esModule", {
331
339
  value: true
332
340
  }), mod);
@@ -334,7 +342,7 @@ var __toCommonJS = function(mod) {
334
342
  // src/player/StormcloudVideoPlayer.ts
335
343
  var StormcloudVideoPlayer_exports = {};
336
344
  __export(StormcloudVideoPlayer_exports, {
337
- StormcloudVideoPlayer: function() {
345
+ StormcloudVideoPlayer: function StormcloudVideoPlayer1() {
338
346
  return StormcloudVideoPlayer;
339
347
  }
340
348
  });
@@ -667,7 +675,7 @@ function createImaController(video, options) {
667
675
  var fn = _step.value;
668
676
  try {
669
677
  fn(payload);
670
- } catch (e) {}
678
+ } catch (unused) {}
671
679
  }
672
680
  } catch (err) {
673
681
  _didIteratorError = true;
@@ -705,7 +713,7 @@ function createImaController(video, options) {
705
713
  console.error("StormcloudVideoPlayer: The host page is inside a sandboxed iframe without 'allow-scripts'. Google IMA cannot run ads within sandboxed frames. Remove the sandbox attribute or include 'allow-scripts allow-same-origin'.");
706
714
  }
707
715
  }
708
- } catch (e) {}
716
+ } catch (unused) {}
709
717
  if (typeof window !== "undefined" && ((_window_google = window.google) === null || _window_google === void 0 ? void 0 : _window_google.ima)) return Promise.resolve();
710
718
  var existing = document.querySelector('script[data-ima="true"]');
711
719
  if (existing) {
@@ -747,9 +755,6 @@ function createImaController(video, options) {
747
755
  var adDisplayContainer;
748
756
  var adContainerEl;
749
757
  var lastAdTagUrl;
750
- var retryAttempts = 0;
751
- var maxRetries = 2;
752
- var backoffBaseMs = 500;
753
758
  var adsLoadedPromise;
754
759
  var adsLoadedResolve;
755
760
  var adsLoadedReject;
@@ -953,7 +958,7 @@ function createImaController(video, options) {
953
958
  if (adsManager) {
954
959
  try {
955
960
  adsManager.destroy();
956
- } catch (e) {}
961
+ } catch (unused) {}
957
962
  adsManager = void 0;
958
963
  }
959
964
  if (adVideoElement) {
@@ -964,7 +969,7 @@ function createImaController(video, options) {
964
969
  if (adsLoader) {
965
970
  try {
966
971
  adsLoader.destroy();
967
- } catch (e) {}
972
+ } catch (unused) {}
968
973
  adsLoader = void 0;
969
974
  }
970
975
  }
@@ -982,7 +987,7 @@ function createImaController(video, options) {
982
987
  try {
983
988
  var _adDisplayContainer_initialize;
984
989
  (_adDisplayContainer_initialize = adDisplayContainer.initialize) === null || _adDisplayContainer_initialize === void 0 ? void 0 : _adDisplayContainer_initialize.call(adDisplayContainer);
985
- } catch (e) {}
990
+ } catch (unused) {}
986
991
  }
987
992
  }).catch(function() {});
988
993
  },
@@ -1046,7 +1051,6 @@ function createImaController(video, options) {
1046
1051
  _state.sent();
1047
1052
  google = window.google;
1048
1053
  lastAdTagUrl = vastTagUrl;
1049
- retryAttempts = 0;
1050
1054
  if (!adDisplayContainer) {
1051
1055
  container = document.createElement("div");
1052
1056
  container.style.position = "absolute";
@@ -1130,32 +1134,23 @@ function createImaController(video, options) {
1130
1134
  }
1131
1135
  }, 300);
1132
1136
  }
1133
- hideContentVideo();
1137
+ showContentVideo();
1134
1138
  if (adsLoadedReject) {
1135
1139
  adsLoadedReject(new Error("Ad playback error"));
1136
1140
  adsLoadedReject = void 0;
1137
1141
  adsLoadedResolve = void 0;
1138
1142
  }
1139
- if (lastAdTagUrl && retryAttempts < maxRetries && !isNoFill) {
1140
- var delay = backoffBaseMs * Math.pow(2, retryAttempts++);
1141
- window.setTimeout(function() {
1142
- try {
1143
- makeAdsRequest(google, lastAdTagUrl);
1144
- } catch (e) {}
1145
- }, delay);
1146
- } else {
1147
- emit("ad_error", {
1148
- code: errorCode,
1149
- vastErrorCode: vastErrorCode,
1150
- message: errorMessage,
1151
- cause: innerError,
1152
- isNoFill: isNoFill
1153
- });
1154
- if (!(options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds)) {
1155
- if (video.paused) {
1156
- var _video_play;
1157
- (_video_play = video.play()) === null || _video_play === void 0 ? void 0 : _video_play.catch(function() {});
1158
- }
1143
+ emit("ad_error", {
1144
+ code: errorCode,
1145
+ vastErrorCode: vastErrorCode,
1146
+ message: errorMessage,
1147
+ cause: innerError,
1148
+ isNoFill: isNoFill
1149
+ });
1150
+ if (!(options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds)) {
1151
+ if (video.paused) {
1152
+ var _video_play;
1153
+ (_video_play = video.play()) === null || _video_play === void 0 ? void 0 : _video_play.catch(function() {});
1159
1154
  }
1160
1155
  }
1161
1156
  });
@@ -1173,7 +1168,7 @@ function createImaController(video, options) {
1173
1168
  if (adsManager) {
1174
1169
  try {
1175
1170
  adsManager.setVolume(adVolume);
1176
- } catch (e) {}
1171
+ } catch (unused) {}
1177
1172
  }
1178
1173
  emit("content_pause");
1179
1174
  });
@@ -1187,7 +1182,7 @@ function createImaController(video, options) {
1187
1182
  if (adsManager) {
1188
1183
  try {
1189
1184
  adsManager.setVolume(originalMutedState ? 0 : adVolume);
1190
- } catch (e) {}
1185
+ } catch (unused) {}
1191
1186
  }
1192
1187
  }
1193
1188
  if (adContainerEl) {
@@ -1201,7 +1196,7 @@ function createImaController(video, options) {
1201
1196
  adsManager.addEventListener(AdEvent.CONTENT_RESUME_REQUESTED, function() {
1202
1197
  adPlaying = false;
1203
1198
  setAdPlayingFlag(false);
1204
- hideContentVideo();
1199
+ showContentVideo();
1205
1200
  emit("content_resume");
1206
1201
  });
1207
1202
  adsManager.addEventListener(AdEvent.ALL_ADS_COMPLETED, function() {
@@ -1217,7 +1212,7 @@ function createImaController(video, options) {
1217
1212
  }
1218
1213
  }, 300);
1219
1214
  }
1220
- hideContentVideo();
1215
+ showContentVideo();
1221
1216
  emit("all_ads_completed");
1222
1217
  });
1223
1218
  if (adsLoadedResolve) {
@@ -1239,7 +1234,7 @@ function createImaController(video, options) {
1239
1234
  }
1240
1235
  }, 300);
1241
1236
  }
1242
- hideContentVideo();
1237
+ showContentVideo();
1243
1238
  if (adsLoadedReject) {
1244
1239
  adsLoadedReject(new Error("Failed to setup ads manager"));
1245
1240
  adsLoadedReject = void 0;
@@ -1282,7 +1277,7 @@ function createImaController(video, options) {
1282
1277
  }
1283
1278
  }, 300);
1284
1279
  }
1285
- hideContentVideo();
1280
+ showContentVideo();
1286
1281
  if (adsLoadedReject) {
1287
1282
  adsLoadedReject(new Error(isNoFill ? "No ads available" : "Ads loader error"));
1288
1283
  adsLoadedReject = void 0;
@@ -1348,7 +1343,7 @@ function createImaController(video, options) {
1348
1343
  }
1349
1344
  try {
1350
1345
  adsManager.setVolume(originalMutedState ? 0 : adVolume);
1351
- } catch (e) {}
1346
+ } catch (unused) {}
1352
1347
  adsManager.start();
1353
1348
  return [
1354
1349
  2,
@@ -1430,7 +1425,7 @@ function createImaController(video, options) {
1430
1425
  try {
1431
1426
  ;
1432
1427
  adsManager === null || adsManager === void 0 ? void 0 : (_adsManager_stop = adsManager.stop) === null || _adsManager_stop === void 0 ? void 0 : _adsManager_stop.call(adsManager);
1433
- } catch (e) {}
1428
+ } catch (unused) {}
1434
1429
  destroyAdsManager();
1435
1430
  return [
1436
1431
  2
@@ -1461,7 +1456,7 @@ function createImaController(video, options) {
1461
1456
  try {
1462
1457
  var _adsLoader_destroy;
1463
1458
  adsLoader === null || adsLoader === void 0 ? void 0 : (_adsLoader_destroy = adsLoader.destroy) === null || _adsLoader_destroy === void 0 ? void 0 : _adsLoader_destroy.call(adsLoader);
1464
- } catch (e) {}
1459
+ } catch (unused) {}
1465
1460
  adDisplayContainer = void 0;
1466
1461
  adsLoader = void 0;
1467
1462
  contentVideoHidden = false;
@@ -1510,7 +1505,7 @@ function createImaController(video, options) {
1510
1505
  if (adsManager && adPlaying) {
1511
1506
  try {
1512
1507
  adsManager.setVolume(clampedVolume);
1513
- } catch (e) {}
1508
+ } catch (unused) {}
1514
1509
  }
1515
1510
  },
1516
1511
  getAdVolume: function getAdVolume() {
@@ -2614,9 +2609,6 @@ function sendInitialTracking(licenseKey) {
2614
2609
  headers = {
2615
2610
  "Content-Type": "application/json"
2616
2611
  };
2617
- if (licenseKey) {
2618
- headers["Authorization"] = "Bearer ".concat(licenseKey);
2619
- }
2620
2612
  return [
2621
2613
  4,
2622
2614
  fetch("https://adstorm.co/api-adstorm-dev/adstorm/player-tracking/track", {
@@ -2722,6 +2714,234 @@ function sendHeartbeat(licenseKey) {
2722
2714
  });
2723
2715
  })();
2724
2716
  }
2717
+ var TRACK_API_URL = "https://adstorm.co/api-adstorm-dev/adstorm/player-tracking/track";
2718
+ function mapToAdTrackingSource(source, adPlayerType) {
2719
+ if (source === "prebid" || source === "ima" || source === "hls") {
2720
+ return source;
2721
+ }
2722
+ if (source === "preload" || source === "ssp") {
2723
+ return source === "ssp" ? "prebid" : "ima";
2724
+ }
2725
+ return adPlayerType === "hls" ? "hls" : "ima";
2726
+ }
2727
+ function postAdTracking(licenseKey, body) {
2728
+ return _async_to_generator(function() {
2729
+ var headers, response;
2730
+ return _ts_generator(this, function(_state) {
2731
+ switch(_state.label){
2732
+ case 0:
2733
+ headers = {
2734
+ "Content-Type": "application/json"
2735
+ };
2736
+ if (licenseKey) {
2737
+ headers["Authorization"] = "Bearer ".concat(licenseKey);
2738
+ }
2739
+ return [
2740
+ 4,
2741
+ fetch(TRACK_API_URL, {
2742
+ method: "POST",
2743
+ headers: headers,
2744
+ body: JSON.stringify(body)
2745
+ })
2746
+ ];
2747
+ case 1:
2748
+ response = _state.sent();
2749
+ if (!response.ok) {
2750
+ throw new Error("HTTP error! status: ".concat(response.status));
2751
+ }
2752
+ return [
2753
+ 4,
2754
+ response.json()
2755
+ ];
2756
+ case 2:
2757
+ _state.sent();
2758
+ return [
2759
+ 2
2760
+ ];
2761
+ }
2762
+ });
2763
+ })();
2764
+ }
2765
+ function sendAdDetectTracking(licenseKey, payload) {
2766
+ return _async_to_generator(function() {
2767
+ var _payload_source, _payload_timestamp, clientInfo, browserId, adDetectInfo, body, error;
2768
+ return _ts_generator(this, function(_state) {
2769
+ switch(_state.label){
2770
+ case 0:
2771
+ _state.trys.push([
2772
+ 0,
2773
+ 3,
2774
+ ,
2775
+ 4
2776
+ ]);
2777
+ clientInfo = getClientInfo();
2778
+ return [
2779
+ 4,
2780
+ getBrowserID(clientInfo)
2781
+ ];
2782
+ case 1:
2783
+ browserId = _state.sent();
2784
+ adDetectInfo = _object_spread({
2785
+ source: (_payload_source = payload.source) !== null && _payload_source !== void 0 ? _payload_source : "scte35",
2786
+ timestamp: (_payload_timestamp = payload.timestamp) !== null && _payload_timestamp !== void 0 ? _payload_timestamp : /* @__PURE__ */ new Date().toISOString()
2787
+ }, payload.durationSeconds != null && {
2788
+ durationSeconds: payload.durationSeconds
2789
+ }, payload.ptsSeconds != null && {
2790
+ ptsSeconds: payload.ptsSeconds
2791
+ }, payload.detectedAtFragmentSn != null && {
2792
+ detectedAtFragmentSn: payload.detectedAtFragmentSn
2793
+ });
2794
+ body = _object_spread_props(_object_spread({
2795
+ browserId: browserId
2796
+ }, clientInfo, licenseKey && {
2797
+ licenseKey: licenseKey
2798
+ }), {
2799
+ adDetectInfo: adDetectInfo
2800
+ });
2801
+ return [
2802
+ 4,
2803
+ postAdTracking(licenseKey, body)
2804
+ ];
2805
+ case 2:
2806
+ _state.sent();
2807
+ return [
2808
+ 3,
2809
+ 4
2810
+ ];
2811
+ case 3:
2812
+ error = _state.sent();
2813
+ console.error("[StormcloudVideoPlayer] Error sending ad-detect tracking:", error);
2814
+ return [
2815
+ 3,
2816
+ 4
2817
+ ];
2818
+ case 4:
2819
+ return [
2820
+ 2
2821
+ ];
2822
+ }
2823
+ });
2824
+ })();
2825
+ }
2826
+ function sendAdLoadedTracking(licenseKey, payload, adPlayerType) {
2827
+ return _async_to_generator(function() {
2828
+ var clientInfo, browserId, source, adLoadedInfo, body, error;
2829
+ return _ts_generator(this, function(_state) {
2830
+ switch(_state.label){
2831
+ case 0:
2832
+ _state.trys.push([
2833
+ 0,
2834
+ 3,
2835
+ ,
2836
+ 4
2837
+ ]);
2838
+ clientInfo = getClientInfo();
2839
+ return [
2840
+ 4,
2841
+ getBrowserID(clientInfo)
2842
+ ];
2843
+ case 1:
2844
+ browserId = _state.sent();
2845
+ source = mapToAdTrackingSource(payload.source, adPlayerType);
2846
+ adLoadedInfo = _object_spread({
2847
+ source: source,
2848
+ timestamp: /* @__PURE__ */ new Date().toISOString()
2849
+ }, payload.vastUrl != null && {
2850
+ vastUrl: payload.vastUrl
2851
+ }, payload.durationSeconds != null && {
2852
+ durationSeconds: payload.durationSeconds
2853
+ });
2854
+ body = _object_spread_props(_object_spread({
2855
+ browserId: browserId
2856
+ }, clientInfo, licenseKey && {
2857
+ licenseKey: licenseKey
2858
+ }), {
2859
+ adLoadedInfo: adLoadedInfo
2860
+ });
2861
+ return [
2862
+ 4,
2863
+ postAdTracking(licenseKey, body)
2864
+ ];
2865
+ case 2:
2866
+ _state.sent();
2867
+ return [
2868
+ 3,
2869
+ 4
2870
+ ];
2871
+ case 3:
2872
+ error = _state.sent();
2873
+ console.error("[StormcloudVideoPlayer] Error sending ad-loaded tracking:", error);
2874
+ return [
2875
+ 3,
2876
+ 4
2877
+ ];
2878
+ case 4:
2879
+ return [
2880
+ 2
2881
+ ];
2882
+ }
2883
+ });
2884
+ })();
2885
+ }
2886
+ function sendAdImpressionTracking(licenseKey, payload, adPlayerType) {
2887
+ return _async_to_generator(function() {
2888
+ var clientInfo, browserId, source, adImpressionInfo, body, error;
2889
+ return _ts_generator(this, function(_state) {
2890
+ switch(_state.label){
2891
+ case 0:
2892
+ _state.trys.push([
2893
+ 0,
2894
+ 3,
2895
+ ,
2896
+ 4
2897
+ ]);
2898
+ clientInfo = getClientInfo();
2899
+ return [
2900
+ 4,
2901
+ getBrowserID(clientInfo)
2902
+ ];
2903
+ case 1:
2904
+ browserId = _state.sent();
2905
+ source = mapToAdTrackingSource(payload.source, adPlayerType);
2906
+ adImpressionInfo = _object_spread({
2907
+ source: source,
2908
+ adIndex: payload.adIndex,
2909
+ timestamp: /* @__PURE__ */ new Date().toISOString()
2910
+ }, payload.durationSeconds != null && {
2911
+ durationSeconds: payload.durationSeconds
2912
+ });
2913
+ body = _object_spread_props(_object_spread({
2914
+ browserId: browserId
2915
+ }, clientInfo, licenseKey && {
2916
+ licenseKey: licenseKey
2917
+ }), {
2918
+ adImpressionInfo: adImpressionInfo
2919
+ });
2920
+ return [
2921
+ 4,
2922
+ postAdTracking(licenseKey, body)
2923
+ ];
2924
+ case 2:
2925
+ _state.sent();
2926
+ return [
2927
+ 3,
2928
+ 4
2929
+ ];
2930
+ case 3:
2931
+ error = _state.sent();
2932
+ console.error("[StormcloudVideoPlayer] Error sending ad-impression tracking:", error);
2933
+ return [
2934
+ 3,
2935
+ 4
2936
+ ];
2937
+ case 4:
2938
+ return [
2939
+ 2
2940
+ ];
2941
+ }
2942
+ });
2943
+ })();
2944
+ }
2725
2945
  // src/utils/polyfills.ts
2726
2946
  function polyfillURLSearchParams() {
2727
2947
  if (typeof URLSearchParams !== "undefined") {
@@ -3003,18 +3223,26 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3003
3223
  this.maxPlaceholderDurationMs = 5e3;
3004
3224
  this.isShowingPlaceholder = false;
3005
3225
  this.totalAdRequestsInBreak = 0;
3006
- this.maxTotalAdRequestsPerBreak = 20;
3226
+ this.maxTotalAdRequestsPerBreak = 10;
3007
3227
  this.pendingAdBreak = null;
3008
3228
  this.consecutiveFailures = 0;
3009
3229
  this.maxConsecutiveFailures = 5;
3010
3230
  this.lastAdRequestTime = 0;
3011
- this.minAdRequestIntervalMs = 2500;
3231
+ this.minAdRequestIntervalMs = 3e3;
3012
3232
  this.backoffBaseMs = 1e3;
3013
3233
  this.maxBackoffMs = 15e3;
3234
+ this.globalConsecutiveNoFills = 0;
3235
+ this.globalNoFillThreshold = 3;
3236
+ this.globalNoFillCooldownUntil = 0;
3237
+ this.globalNoFillBackoffBaseMs = 5e3;
3238
+ this.globalNoFillBackoffMaxMs = 6e4;
3239
+ this.globalLastGamRequestTime = 0;
3240
+ this.globalMinGamIntervalMs = 3e3;
3014
3241
  this.preloadPool = [];
3015
- this.maxPreloadPoolSize = 3;
3242
+ this.maxPreloadPoolSize = 2;
3016
3243
  this.preloadPoolActive = false;
3017
3244
  this.preloadPoolLoopRunning = false;
3245
+ this.adDetectSentForCurrentBreak = false;
3018
3246
  this.continuousFetchLoopRunning = false;
3019
3247
  initializePolyfills();
3020
3248
  var browserOverrides = getBrowserConfigOverrides();
@@ -3155,7 +3383,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3155
3383
  });
3156
3384
  this.hls.on(import_hls2.default.Events.MANIFEST_PARSED, function(_, data) {
3157
3385
  return _async_to_generator(function() {
3158
- var _this_hls_levels, _this_hls, _this_hls_levels_some, adBehavior, _this_config_minSegmentsBeforePlay, minSegments, _this_video_play;
3386
+ var _this_config_minSegmentsBeforePlay, _ref, _this_hls_levels, _this_hls, adBehavior, minSegments, _this_video_play;
3159
3387
  return _ts_generator(this, function(_state) {
3160
3388
  switch(_state.label){
3161
3389
  case 0:
@@ -3164,10 +3392,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3164
3392
  } else {
3165
3393
  ;
3166
3394
  ;
3167
- this.isLiveStream = (_this_hls_levels_some = (_this_hls = this.hls) === null || _this_hls === void 0 ? void 0 : (_this_hls_levels = _this_hls.levels) === null || _this_hls_levels === void 0 ? void 0 : _this_hls_levels.some(function(level) {
3395
+ this.isLiveStream = (_ref = (_this_hls = this.hls) === null || _this_hls === void 0 ? void 0 : (_this_hls_levels = _this_hls.levels) === null || _this_hls_levels === void 0 ? void 0 : _this_hls_levels.some(function(level) {
3168
3396
  var _level_details, _level_details1;
3169
3397
  return (level === null || level === void 0 ? void 0 : (_level_details = level.details) === null || _level_details === void 0 ? void 0 : _level_details.live) === true || (level === null || level === void 0 ? void 0 : (_level_details1 = level.details) === null || _level_details1 === void 0 ? void 0 : _level_details1.type) === "LIVE";
3170
- })) !== null && _this_hls_levels_some !== void 0 ? _this_hls_levels_some : false;
3398
+ })) !== null && _ref !== void 0 ? _ref : false;
3171
3399
  }
3172
3400
  if (this.config.debugAdTiming) {
3173
3401
  adBehavior = this.shouldContinueLiveStreamDuringAds() ? "live (main video continues muted during ads)" : "vod (main video pauses during ads)";
@@ -3231,9 +3459,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3231
3459
  var tag = "";
3232
3460
  var value = "";
3233
3461
  if (Array.isArray(entry)) {
3234
- var _entry_;
3462
+ var _entry_, _entry_1;
3235
3463
  tag = String((_entry_ = entry[0]) !== null && _entry_ !== void 0 ? _entry_ : "");
3236
- var _entry_1;
3237
3464
  value = String((_entry_1 = entry[1]) !== null && _entry_1 !== void 0 ? _entry_1 : "");
3238
3465
  } else if (typeof entry === "string") {
3239
3466
  var idx = entry.indexOf(":");
@@ -3356,9 +3583,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3356
3583
  var tag = "";
3357
3584
  var value = "";
3358
3585
  if (Array.isArray(entry)) {
3359
- var _entry_;
3586
+ var _entry_, _entry_1;
3360
3587
  tag = String((_entry_ = entry[0]) !== null && _entry_ !== void 0 ? _entry_ : "");
3361
- var _entry_1;
3362
3588
  value = String((_entry_1 = entry[1]) !== null && _entry_1 !== void 0 ? _entry_1 : "");
3363
3589
  } else if (typeof entry === "string") {
3364
3590
  var idx = entry.indexOf(":");
@@ -3408,10 +3634,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3408
3634
  }
3409
3635
  });
3410
3636
  } else if (tag.includes("EXT-X-DATERANGE")) {
3637
+ var _attrs_CLASS;
3411
3638
  var attrs = _this.parseAttributeList(value);
3412
3639
  var hasScteOut = "SCTE35-OUT" in attrs || attrs["SCTE35-OUT"] !== void 0;
3413
3640
  var hasScteIn = "SCTE35-IN" in attrs || attrs["SCTE35-IN"] !== void 0;
3414
- var _attrs_CLASS;
3415
3641
  var klass = String((_attrs_CLASS = attrs["CLASS"]) !== null && _attrs_CLASS !== void 0 ? _attrs_CLASS : "");
3416
3642
  var duration = _this.toNumber(attrs["DURATION"]);
3417
3643
  if (hasScteOut || /com\.apple\.hls\.cue/i.test(klass)) {
@@ -3486,6 +3712,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3486
3712
  value: function attachImaEventListeners() {
3487
3713
  var _this = this;
3488
3714
  this.ima.on("all_ads_completed", function() {
3715
+ sendAdImpressionTracking(_this.config.licenseKey, {
3716
+ adIndex: _this.currentAdIndex
3717
+ }, _this.config.adPlayerType).catch(function() {});
3489
3718
  var remaining = _this.getRemainingAdMs();
3490
3719
  _this.consecutiveFailures = 0;
3491
3720
  if (_this.config.debugAdTiming) {
@@ -3525,6 +3754,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3525
3754
  _this.clearAdRequestWatchdog();
3526
3755
  _this.activeAdRequestToken = null;
3527
3756
  _this.showAds = true;
3757
+ _this.resetGamNoFillCounter();
3528
3758
  if (_this.inAdBreak && _this.expectedAdBreakDurationMs != null) {
3529
3759
  if (_this.adStopTimerId == null) {
3530
3760
  _this.currentAdBreakStartWallClockMs = Date.now();
@@ -3547,6 +3777,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3547
3777
  }
3548
3778
  });
3549
3779
  this.ima.on("content_resume", function() {
3780
+ sendAdImpressionTracking(_this.config.licenseKey, {
3781
+ adIndex: _this.currentAdIndex
3782
+ }, _this.config.adPlayerType).catch(function() {});
3550
3783
  if (!_this.video.muted) {
3551
3784
  _this.video.muted = true;
3552
3785
  _this.video.volume = 0;
@@ -3813,11 +4046,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3813
4046
  }
3814
4047
  var daterangeMatch = text.match(/EXT-X-DATERANGE:([^\r\n]*)/i);
3815
4048
  if (daterangeMatch) {
3816
- var _daterangeMatch_;
4049
+ var _daterangeMatch_, _attrs_CLASS;
3817
4050
  var attrs = this.parseAttributeList((_daterangeMatch_ = daterangeMatch[1]) !== null && _daterangeMatch_ !== void 0 ? _daterangeMatch_ : "");
3818
4051
  var hasScteOut = "SCTE35-OUT" in attrs || attrs["SCTE35-OUT"] !== void 0;
3819
4052
  var hasScteIn = "SCTE35-IN" in attrs || attrs["SCTE35-IN"] !== void 0;
3820
- var _attrs_CLASS;
3821
4053
  var klass = String((_attrs_CLASS = attrs["CLASS"]) !== null && _attrs_CLASS !== void 0 ? _attrs_CLASS : "");
3822
4054
  var duration = this.toNumber(attrs["DURATION"]);
3823
4055
  if (hasScteOut || /com\.apple\.hls\.cue/i.test(klass)) {
@@ -3893,7 +4125,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3893
4125
  var out = "";
3894
4126
  for(var i = 0; i < value.length; i++)out += String.fromCharCode(value[i]);
3895
4127
  return out;
3896
- } catch (e) {
4128
+ } catch (unused) {
3897
4129
  return void 0;
3898
4130
  }
3899
4131
  }
@@ -3912,6 +4144,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3912
4144
  });
3913
4145
  }
3914
4146
  if (marker.type === "start") {
4147
+ var _this_config_immediateManifestAds;
3915
4148
  var _this_pendingAdBreak;
3916
4149
  if (!this.video.muted) {
3917
4150
  this.video.muted = true;
@@ -3930,13 +4163,19 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3930
4163
  }
3931
4164
  return;
3932
4165
  }
4166
+ if (!this.adDetectSentForCurrentBreak) {
4167
+ this.adDetectSentForCurrentBreak = true;
4168
+ var detectPayload = {};
4169
+ if (marker.durationSeconds != null) detectPayload.durationSeconds = marker.durationSeconds;
4170
+ if (marker.ptsSeconds != null) detectPayload.ptsSeconds = marker.ptsSeconds;
4171
+ sendAdDetectTracking(this.config.licenseKey, detectPayload).catch(function() {});
4172
+ }
3933
4173
  var hasPrefetchedAds = this.pendingAdBreak && this.pendingAdBreak.vastUrls.length > 0;
3934
4174
  this.inAdBreak = true;
3935
4175
  var durationMs = marker.durationSeconds != null ? marker.durationSeconds * 1e3 : ((_this_pendingAdBreak = this.pendingAdBreak) === null || _this_pendingAdBreak === void 0 ? void 0 : _this_pendingAdBreak.marker.durationSeconds) != null ? this.pendingAdBreak.marker.durationSeconds * 1e3 : void 0;
3936
4176
  this.expectedAdBreakDurationMs = durationMs;
3937
4177
  this.currentAdBreakStartWallClockMs = Date.now();
3938
4178
  var isManifestMarker = this.isManifestBasedMarker(marker);
3939
- var _this_config_immediateManifestAds;
3940
4179
  var forceImmediate = (_this_config_immediateManifestAds = this.config.immediateManifestAds) !== null && _this_config_immediateManifestAds !== void 0 ? _this_config_immediateManifestAds : true;
3941
4180
  if (this.config.debugAdTiming) {
3942
4181
  console.log("[StormcloudVideoPlayer] Ad start decision:", {
@@ -4091,9 +4330,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4091
4330
  var regex = /([A-Z0-9-]+)=(("[^"]*")|([^",]*))(?:,|$)/gi;
4092
4331
  var match;
4093
4332
  while((match = regex.exec(value)) !== null){
4094
- var _match_;
4333
+ var _match_, _ref, _match_1;
4095
4334
  var key = (_match_ = match[1]) !== null && _match_ !== void 0 ? _match_ : "";
4096
- var _match_1, _ref;
4097
4335
  var rawVal = (_ref = (_match_1 = match[3]) !== null && _match_1 !== void 0 ? _match_1 : match[4]) !== null && _ref !== void 0 ? _ref : "";
4098
4336
  if (rawVal.startsWith('"') && rawVal.endsWith('"')) {
4099
4337
  rawVal = rawVal.slice(1, -1);
@@ -4438,13 +4676,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4438
4676
  {
4439
4677
  key: "shouldShowNativeControls",
4440
4678
  value: function shouldShowNativeControls() {
4679
+ var _this_config_showCustomControls;
4441
4680
  var streamType = this.getStreamType();
4442
4681
  if (streamType === "other") {
4443
- var _this_config_showCustomControls;
4444
- return !((_this_config_showCustomControls = this.config.showCustomControls) !== null && _this_config_showCustomControls !== void 0 ? _this_config_showCustomControls : false);
4682
+ var _this_config_showCustomControls1;
4683
+ return !((_this_config_showCustomControls1 = this.config.showCustomControls) !== null && _this_config_showCustomControls1 !== void 0 ? _this_config_showCustomControls1 : false);
4445
4684
  }
4446
- var _this_config_showCustomControls1;
4447
- return !!(this.config.allowNativeHls && !((_this_config_showCustomControls1 = this.config.showCustomControls) !== null && _this_config_showCustomControls1 !== void 0 ? _this_config_showCustomControls1 : false));
4685
+ return !!(this.config.allowNativeHls && !((_this_config_showCustomControls = this.config.showCustomControls) !== null && _this_config_showCustomControls !== void 0 ? _this_config_showCustomControls : false));
4448
4686
  }
4449
4687
  },
4450
4688
  {
@@ -4489,6 +4727,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4489
4727
  isFetching: false,
4490
4728
  fetchStartTime: Date.now()
4491
4729
  });
4730
+ this.adDetectSentForCurrentBreak = true;
4731
+ var detectPayload = {};
4732
+ if (marker.durationSeconds != null) detectPayload.durationSeconds = marker.durationSeconds;
4733
+ if (marker.ptsSeconds != null) detectPayload.ptsSeconds = marker.ptsSeconds;
4734
+ if (fragmentSn !== void 0) detectPayload.detectedAtFragmentSn = fragmentSn;
4735
+ sendAdDetectTracking(this.config.licenseKey, detectPayload).catch(function() {});
4492
4736
  if (this.config.debugAdTiming) {
4493
4737
  console.log("[PREFETCH] \uD83D\uDD04 Starting ad prefetch for upcoming ad break");
4494
4738
  console.log("[PREFETCH] \uD83D\uDCCB Pre-generated ".concat(generatedUrls.length, " VAST URLs"));
@@ -4552,6 +4796,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4552
4796
  var _this, loadPromise;
4553
4797
  return _ts_generator(this, function(_state) {
4554
4798
  _this = this;
4799
+ if (this.isGamInCooldown()) {
4800
+ if (this.config.debugAdTiming) {
4801
+ console.log("[CIRCUIT-BREAKER] GAM in cooldown, skipping preload");
4802
+ }
4803
+ return [
4804
+ 2
4805
+ ];
4806
+ }
4555
4807
  if (this.preloadPool.some(function(entry) {
4556
4808
  return entry.vastUrl === vastUrl;
4557
4809
  }) || this.failedVastUrls.has(vastUrl) || this.isUrlInCooldown(vastUrl)) {
@@ -4581,26 +4833,32 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4581
4833
  case 1:
4582
4834
  _state.trys.push([
4583
4835
  1,
4584
- 4,
4836
+ 5,
4585
4837
  ,
4586
- 5
4838
+ 6
4587
4839
  ]);
4588
4840
  continueLiveStreamDuringAds = this.shouldContinueLiveStreamDuringAds();
4589
4841
  preloadIma = this.createAdPlayer(continueLiveStreamDuringAds);
4590
4842
  preloadIma.initialize();
4591
- errorListener = function(payload) {
4843
+ errorListener = function errorListener(payload) {
4592
4844
  hasAdError = true;
4593
4845
  adErrorPayload = payload;
4594
4846
  };
4595
4847
  preloadIma.on("ad_error", errorListener);
4596
- errorListenerCleanup = function() {
4848
+ errorListenerCleanup = function errorListenerCleanup() {
4597
4849
  return preloadIma.off("ad_error", errorListener);
4598
4850
  };
4599
4851
  return [
4600
4852
  4,
4601
- preloadIma.requestAds(vastUrl)
4853
+ this.enforceGlobalRateLimit()
4602
4854
  ];
4603
4855
  case 2:
4856
+ _state.sent();
4857
+ return [
4858
+ 4,
4859
+ preloadIma.requestAds(vastUrl)
4860
+ ];
4861
+ case 3:
4604
4862
  _state.sent();
4605
4863
  preloadIma.pause();
4606
4864
  return [
@@ -4609,7 +4867,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4609
4867
  return setTimeout(resolve, 1500);
4610
4868
  })
4611
4869
  ];
4612
- case 3:
4870
+ case 4:
4613
4871
  _state.sent();
4614
4872
  preloadIma.pause();
4615
4873
  if (hasAdError) {
@@ -4618,6 +4876,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4618
4876
  errorListenerCleanup();
4619
4877
  }
4620
4878
  preloadIma.destroy();
4879
+ this.recordGamNoFill();
4621
4880
  if (isNoFill) {
4622
4881
  if (this.config.debugAdTiming) {
4623
4882
  console.log("[PRELOAD-POOL] ⚠️ Ad preload returned no-fill: ".concat(vastUrl));
@@ -4644,7 +4903,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4644
4903
  isReady: true,
4645
4904
  loadPromise: Promise.resolve()
4646
4905
  };
4647
- lateErrorListener = function(payload) {
4906
+ lateErrorListener = function lateErrorListener(payload) {
4648
4907
  var index = _this.preloadPool.findIndex(function(entry) {
4649
4908
  return entry.vastUrl === vastUrl;
4650
4909
  });
@@ -4655,7 +4914,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4655
4914
  }
4656
4915
  try {
4657
4916
  preloadIma.destroy();
4658
- } catch (e) {}
4917
+ } catch (unused) {}
4659
4918
  }
4660
4919
  };
4661
4920
  preloadIma.on("ad_error", lateErrorListener);
@@ -4668,13 +4927,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4668
4927
  }
4669
4928
  return [
4670
4929
  3,
4671
- 5
4930
+ 6
4672
4931
  ];
4673
- case 4:
4932
+ case 5:
4674
4933
  error = _state.sent();
4675
4934
  if (errorListenerCleanup) {
4676
4935
  errorListenerCleanup();
4677
4936
  }
4937
+ this.recordGamNoFill();
4678
4938
  if (this.config.debugAdTiming) {
4679
4939
  console.warn("[PRELOAD-POOL] ⚠️ Failed to preload ad: ".concat(vastUrl), error);
4680
4940
  }
@@ -4685,9 +4945,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4685
4945
  }
4686
4946
  return [
4687
4947
  3,
4688
- 5
4948
+ 6
4689
4949
  ];
4690
- case 5:
4950
+ case 6:
4691
4951
  return [
4692
4952
  2
4693
4953
  ];
@@ -4726,6 +4986,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4726
4986
  3,
4727
4987
  10
4728
4988
  ];
4989
+ if (this.isGamInCooldown()) {
4990
+ if (this.config.debugAdTiming) {
4991
+ console.log("[CIRCUIT-BREAKER] GAM in cooldown, stopping preload pool loop");
4992
+ }
4993
+ return [
4994
+ 3,
4995
+ 10
4996
+ ];
4997
+ }
4729
4998
  if (!(!this.inAdBreak && this.preloadPool.length >= this.maxPreloadPoolSize)) return [
4730
4999
  3,
4731
5000
  3
@@ -4758,7 +5027,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4758
5027
  3,
4759
5028
  8
4760
5029
  ];
4761
- if (!this.preloadPoolActive) {
5030
+ if (!this.preloadPoolActive || this.isGamInCooldown()) {
4762
5031
  return [
4763
5032
  3,
4764
5033
  8
@@ -4939,6 +5208,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4939
5208
  firstAdUrl = preloaded.vastUrl;
4940
5209
  preloadedController = preloaded.imaController;
4941
5210
  usePreloadedAd = true;
5211
+ sendAdLoadedTracking(this.config.licenseKey, {
5212
+ source: "preload",
5213
+ vastUrl: firstAdUrl
5214
+ }, this.config.adPlayerType).catch(function() {});
4942
5215
  if (this.config.debugAdTiming) {
4943
5216
  console.log("[CONTINUOUS-FETCH] \uD83D\uDE80 Using preloaded ad from pool (preloaded in advance, ready immediately!)");
4944
5217
  console.log("[CONTINUOUS-FETCH] Pool still has ".concat(this.preloadPool.length, " preloaded ads ready"));
@@ -4974,9 +5247,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4974
5247
  case 1:
4975
5248
  _state.trys.push([
4976
5249
  1,
4977
- 7,
5250
+ 8,
4978
5251
  ,
4979
- 13
5252
+ 14
4980
5253
  ]);
4981
5254
  if (!(usePreloadedAd && preloadedController)) return [
4982
5255
  3,
@@ -5012,16 +5285,26 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5012
5285
  this.ima.setAdVolume(adVolume);
5013
5286
  return [
5014
5287
  3,
5015
- 6
5288
+ 7
5016
5289
  ];
5017
5290
  case 3:
5291
+ return [
5292
+ 4,
5293
+ this.enforceGlobalRateLimit()
5294
+ ];
5295
+ case 4:
5296
+ _state.sent();
5018
5297
  this.lastAdRequestTime = Date.now();
5019
5298
  return [
5020
5299
  4,
5021
5300
  this.ima.requestAds(firstAdUrl)
5022
5301
  ];
5023
- case 4:
5302
+ case 5:
5024
5303
  _state.sent();
5304
+ sendAdLoadedTracking(this.config.licenseKey, {
5305
+ source: "ssp",
5306
+ vastUrl: firstAdUrl
5307
+ }, this.config.adPlayerType).catch(function() {});
5025
5308
  if (this.config.debugAdTiming) {
5026
5309
  console.log("[CONTINUOUS-FETCH] \u2705 First ad request successful, starting playback");
5027
5310
  }
@@ -5035,7 +5318,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5035
5318
  4,
5036
5319
  this.ima.play()
5037
5320
  ];
5038
- case 5:
5321
+ case 6:
5039
5322
  _state.sent();
5040
5323
  if (this.expectedAdBreakDurationMs != null) {
5041
5324
  this.currentAdBreakStartWallClockMs = Date.now();
@@ -5043,36 +5326,36 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5043
5326
  }
5044
5327
  adVolume1 = currentMuted ? 0 : currentVolume;
5045
5328
  this.ima.setAdVolume(adVolume1);
5046
- _state.label = 6;
5047
- case 6:
5329
+ _state.label = 7;
5330
+ case 7:
5048
5331
  return [
5049
5332
  3,
5050
- 13
5333
+ 14
5051
5334
  ];
5052
- case 7:
5335
+ case 8:
5053
5336
  error = _state.sent();
5054
5337
  if (this.config.debugAdTiming) {
5055
5338
  console.warn("[CONTINUOUS-FETCH] \u26A0\uFE0F First ad request failed:", error);
5056
5339
  }
5057
5340
  if (!!usePreloadedAd) return [
5058
5341
  3,
5059
- 11
5342
+ 12
5060
5343
  ];
5061
5344
  fallbackPreloaded = this.getPreloadedAd();
5062
5345
  if (!fallbackPreloaded) return [
5063
5346
  3,
5064
- 11
5347
+ 12
5065
5348
  ];
5066
5349
  if (this.config.debugAdTiming) {
5067
5350
  console.log("[CONTINUOUS-FETCH] \uD83D\uDD04 First ad failed, using preloaded fallback");
5068
5351
  }
5069
- _state.label = 8;
5070
- case 8:
5352
+ _state.label = 9;
5353
+ case 9:
5071
5354
  _state.trys.push([
5072
- 8,
5073
- 10,
5355
+ 9,
5356
+ 11,
5074
5357
  ,
5075
- 11
5358
+ 12
5076
5359
  ]);
5077
5360
  this.ima.destroy();
5078
5361
  this.video.muted = true;
@@ -5091,7 +5374,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5091
5374
  4,
5092
5375
  this.ima.play()
5093
5376
  ];
5094
- case 9:
5377
+ case 10:
5095
5378
  _state.sent();
5096
5379
  if (this.expectedAdBreakDurationMs != null) {
5097
5380
  this.currentAdBreakStartWallClockMs = Date.now();
@@ -5102,16 +5385,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5102
5385
  return [
5103
5386
  2
5104
5387
  ];
5105
- case 10:
5388
+ case 11:
5106
5389
  fallbackError = _state.sent();
5107
5390
  if (this.config.debugAdTiming) {
5108
5391
  console.warn("[CONTINUOUS-FETCH] \u26A0\uFE0F Preloaded fallback also failed:", fallbackError);
5109
5392
  }
5110
5393
  return [
5111
5394
  3,
5112
- 11
5395
+ 12
5113
5396
  ];
5114
- case 11:
5397
+ case 12:
5115
5398
  if (this.isTemporaryAdError(error)) {
5116
5399
  this.temporaryFailureUrls.set(firstAdUrl, Date.now());
5117
5400
  if (this.config.debugAdTiming) {
@@ -5129,13 +5412,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5129
5412
  4,
5130
5413
  this.tryNextAvailableAdWithRateLimit()
5131
5414
  ];
5132
- case 12:
5415
+ case 13:
5133
5416
  _state.sent();
5134
5417
  return [
5135
5418
  3,
5136
- 13
5419
+ 14
5137
5420
  ];
5138
- case 13:
5421
+ case 14:
5139
5422
  return [
5140
5423
  2
5141
5424
  ];
@@ -5186,6 +5469,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5186
5469
  "break"
5187
5470
  ];
5188
5471
  }
5472
+ if (_this.isGamInCooldown()) {
5473
+ if (_this.config.debugAdTiming) {
5474
+ console.log("[CIRCUIT-BREAKER] GAM in cooldown, stopping URL generation");
5475
+ }
5476
+ return [
5477
+ 2,
5478
+ "break"
5479
+ ];
5480
+ }
5189
5481
  if (_this.consecutiveFailures >= _this.maxConsecutiveFailures) {
5190
5482
  if (_this.config.debugAdTiming) {
5191
5483
  console.log("[CONTINUOUS-FETCH] \uD83D\uDED1 Too many consecutive failures (".concat(_this.consecutiveFailures, "), stopping URL generation"));
@@ -5382,6 +5674,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5382
5674
  2
5383
5675
  ];
5384
5676
  }
5677
+ if (this.isGamInCooldown()) {
5678
+ if (this.config.debugAdTiming) {
5679
+ console.log("[CIRCUIT-BREAKER] GAM in cooldown, ending ad break gracefully");
5680
+ }
5681
+ this.handleAdPodComplete();
5682
+ return [
5683
+ 2
5684
+ ];
5685
+ }
5385
5686
  if (this.consecutiveFailures >= this.maxConsecutiveFailures) {
5386
5687
  if (this.config.debugAdTiming) {
5387
5688
  console.log("[CONTINUOUS-FETCH] \uD83D\uDED1 Too many consecutive failures (".concat(this.consecutiveFailures, "), ending ad break"));
@@ -5400,6 +5701,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5400
5701
  if (this.config.debugAdTiming) {
5401
5702
  console.log("[CONTINUOUS-FETCH] \uD83C\uDFAF Using preloaded ad from pool (".concat(this.preloadPool.length, " remaining in pool)"));
5402
5703
  }
5704
+ sendAdLoadedTracking(this.config.licenseKey, {
5705
+ source: "preload",
5706
+ vastUrl: preloaded.vastUrl
5707
+ }, this.config.adPlayerType).catch(function() {});
5403
5708
  _state.label = 1;
5404
5709
  case 1:
5405
5710
  _state.trys.push([
@@ -5578,6 +5883,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5578
5883
  case 0:
5579
5884
  remaining = this.getRemainingAdMs();
5580
5885
  waitTime = Math.min(this.maxPlaceholderDurationMs, remaining);
5886
+ if (this.isGamInCooldown()) {
5887
+ if (this.config.debugAdTiming) {
5888
+ console.log("[CIRCUIT-BREAKER] GAM in cooldown, skipping placeholder wait");
5889
+ }
5890
+ this.handleAdPodComplete();
5891
+ return [
5892
+ 2
5893
+ ];
5894
+ }
5581
5895
  if (this.consecutiveFailures >= this.maxConsecutiveFailures) {
5582
5896
  if (this.config.debugAdTiming) {
5583
5897
  console.log("[CONTINUOUS-FETCH] \uD83D\uDED1 Skipping placeholder - too many consecutive failures");
@@ -5841,11 +6155,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5841
6155
  {
5842
6156
  key: "ensureAdStoppedByTimer",
5843
6157
  value: function ensureAdStoppedByTimer() {
6158
+ var _this_config_adBreakCheckIntervalMs, _this_expectedAdBreakDurationMs;
5844
6159
  if (!this.inAdBreak) return;
5845
6160
  this.adStopTimerId = void 0;
5846
6161
  var adPlaying = this.ima.isAdPlaying();
5847
6162
  var pendingAds = this.adPodQueue.length > 0;
5848
- var _this_config_adBreakCheckIntervalMs;
5849
6163
  var checkIntervalMs = Math.max(250, Math.floor((_this_config_adBreakCheckIntervalMs = this.config.adBreakCheckIntervalMs) !== null && _this_config_adBreakCheckIntervalMs !== void 0 ? _this_config_adBreakCheckIntervalMs : 1e3));
5850
6164
  var maxExtensionMsConfig = this.config.maxAdBreakExtensionMs;
5851
6165
  var maxExtensionMs = typeof maxExtensionMsConfig === "number" && maxExtensionMsConfig > 0 ? maxExtensionMsConfig : 6e4;
@@ -5853,7 +6167,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5853
6167
  if (this.currentAdBreakStartWallClockMs != null) {
5854
6168
  elapsedSinceStartMs = Date.now() - this.currentAdBreakStartWallClockMs;
5855
6169
  }
5856
- var _this_expectedAdBreakDurationMs;
5857
6170
  var expectedDurationMs = (_this_expectedAdBreakDurationMs = this.expectedAdBreakDurationMs) !== null && _this_expectedAdBreakDurationMs !== void 0 ? _this_expectedAdBreakDurationMs : 0;
5858
6171
  var overrunMs = Math.max(0, elapsedSinceStartMs - expectedDurationMs);
5859
6172
  var shouldExtendAdBreak = (adPlaying || pendingAds || this.showAds) && overrunMs < maxExtensionMs;
@@ -5967,6 +6280,73 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5967
6280
  }
5968
6281
  }
5969
6282
  },
6283
+ {
6284
+ key: "isGamInCooldown",
6285
+ value: function isGamInCooldown() {
6286
+ return Date.now() < this.globalNoFillCooldownUntil;
6287
+ }
6288
+ },
6289
+ {
6290
+ key: "recordGamNoFill",
6291
+ value: function recordGamNoFill() {
6292
+ this.globalConsecutiveNoFills++;
6293
+ if (this.globalConsecutiveNoFills >= this.globalNoFillThreshold) {
6294
+ var exponent = this.globalConsecutiveNoFills - this.globalNoFillThreshold;
6295
+ var backoff = Math.min(this.globalNoFillBackoffBaseMs * Math.pow(2, exponent), this.globalNoFillBackoffMaxMs);
6296
+ this.globalNoFillCooldownUntil = Date.now() + backoff;
6297
+ if (this.config.debugAdTiming) {
6298
+ console.log("[CIRCUIT-BREAKER] GAM cooldown activated: ".concat(backoff, "ms (").concat(this.globalConsecutiveNoFills, " consecutive no-fills)"));
6299
+ }
6300
+ }
6301
+ }
6302
+ },
6303
+ {
6304
+ key: "resetGamNoFillCounter",
6305
+ value: function resetGamNoFillCounter() {
6306
+ if (this.globalConsecutiveNoFills > 0 && this.config.debugAdTiming) {
6307
+ console.log("[CIRCUIT-BREAKER] Resetting no-fill counter (was ".concat(this.globalConsecutiveNoFills, ")"));
6308
+ }
6309
+ this.globalConsecutiveNoFills = 0;
6310
+ this.globalNoFillCooldownUntil = 0;
6311
+ }
6312
+ },
6313
+ {
6314
+ key: "enforceGlobalRateLimit",
6315
+ value: function enforceGlobalRateLimit() {
6316
+ return _async_to_generator(function() {
6317
+ var now, elapsed, waitMs;
6318
+ return _ts_generator(this, function(_state) {
6319
+ switch(_state.label){
6320
+ case 0:
6321
+ now = Date.now();
6322
+ elapsed = now - this.globalLastGamRequestTime;
6323
+ if (!(elapsed < this.globalMinGamIntervalMs)) return [
6324
+ 3,
6325
+ 2
6326
+ ];
6327
+ waitMs = this.globalMinGamIntervalMs - elapsed;
6328
+ if (this.config.debugAdTiming) {
6329
+ console.log("[RATE-LIMIT] Waiting ".concat(waitMs, "ms before next GAM request"));
6330
+ }
6331
+ return [
6332
+ 4,
6333
+ new Promise(function(resolve) {
6334
+ return setTimeout(resolve, waitMs);
6335
+ })
6336
+ ];
6337
+ case 1:
6338
+ _state.sent();
6339
+ _state.label = 2;
6340
+ case 2:
6341
+ this.globalLastGamRequestTime = Date.now();
6342
+ return [
6343
+ 2
6344
+ ];
6345
+ }
6346
+ });
6347
+ }).call(this);
6348
+ }
6349
+ },
5970
6350
  {
5971
6351
  key: "playSingleAd",
5972
6352
  value: function playSingleAd(vastTagUrl) {
@@ -5998,6 +6378,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5998
6378
  }
5999
6379
  throw new Error("Too many consecutive failures");
6000
6380
  }
6381
+ if (this.isGamInCooldown()) {
6382
+ if (this.config.debugAdTiming) {
6383
+ console.warn("[CIRCUIT-BREAKER] GAM in cooldown, skipping ad request");
6384
+ }
6385
+ throw new Error("GAM in cooldown");
6386
+ }
6001
6387
  this.recreateImaController();
6002
6388
  requestToken = ++this.adRequestTokenCounter;
6003
6389
  this.activeAdRequestToken = requestToken;
@@ -6006,37 +6392,47 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6006
6392
  case 1:
6007
6393
  _state.trys.push([
6008
6394
  1,
6009
- 11,
6395
+ 12,
6010
6396
  ,
6011
- 16
6397
+ 17
6012
6398
  ]);
6399
+ return [
6400
+ 4,
6401
+ this.enforceGlobalRateLimit()
6402
+ ];
6403
+ case 2:
6404
+ _state.sent();
6013
6405
  this.lastAdRequestTime = Date.now();
6014
6406
  return [
6015
6407
  4,
6016
6408
  this.ima.requestAds(vastTagUrl)
6017
6409
  ];
6018
- case 2:
6410
+ case 3:
6019
6411
  _state.sent();
6412
+ sendAdLoadedTracking(this.config.licenseKey, {
6413
+ source: "ssp",
6414
+ vastUrl: vastTagUrl
6415
+ }, this.config.adPlayerType).catch(function() {});
6020
6416
  this.clearAdRequestWatchdog();
6021
6417
  if (this.activeAdRequestToken !== requestToken) {
6022
6418
  return [
6023
6419
  2
6024
6420
  ];
6025
6421
  }
6026
- _state.label = 3;
6027
- case 3:
6422
+ _state.label = 4;
6423
+ case 4:
6028
6424
  _state.trys.push([
6029
- 3,
6030
- 5,
6425
+ 4,
6426
+ 6,
6031
6427
  ,
6032
- 10
6428
+ 11
6033
6429
  ]);
6034
6430
  this.startAdFailsafeTimer(requestToken);
6035
6431
  return [
6036
6432
  4,
6037
6433
  this.ima.play()
6038
6434
  ];
6039
- case 4:
6435
+ case 5:
6040
6436
  _state.sent();
6041
6437
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6042
6438
  this.currentAdBreakStartWallClockMs = Date.now();
@@ -6050,9 +6446,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6050
6446
  this.temporaryFailureUrls.delete(vastTagUrl);
6051
6447
  return [
6052
6448
  3,
6053
- 10
6449
+ 11
6054
6450
  ];
6055
- case 5:
6451
+ case 6:
6056
6452
  playError = _state.sent();
6057
6453
  if (this.config.debugAdTiming) {
6058
6454
  console.error("[AD-ERROR] Failed to play ad:", playError);
@@ -6060,18 +6456,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6060
6456
  preloadedFallback = this.getPreloadedAd();
6061
6457
  if (!preloadedFallback) return [
6062
6458
  3,
6063
- 9
6459
+ 10
6064
6460
  ];
6065
6461
  if (this.config.debugAdTiming) {
6066
6462
  console.log("[AD-ERROR] Play failed, trying preloaded fallback ad");
6067
6463
  }
6068
- _state.label = 6;
6069
- case 6:
6464
+ _state.label = 7;
6465
+ case 7:
6070
6466
  _state.trys.push([
6071
- 6,
6072
- 8,
6467
+ 7,
6468
+ 9,
6073
6469
  ,
6074
- 9
6470
+ 10
6075
6471
  ]);
6076
6472
  this.clearAdFailsafeTimer();
6077
6473
  this.ima.destroy();
@@ -6087,7 +6483,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6087
6483
  4,
6088
6484
  this.ima.play()
6089
6485
  ];
6090
- case 7:
6486
+ case 8:
6091
6487
  _state.sent();
6092
6488
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6093
6489
  this.currentAdBreakStartWallClockMs = Date.now();
@@ -6100,16 +6496,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6100
6496
  return [
6101
6497
  2
6102
6498
  ];
6103
- case 8:
6499
+ case 9:
6104
6500
  fallbackError = _state.sent();
6105
6501
  if (this.config.debugAdTiming) {
6106
6502
  console.warn("[AD-ERROR] Preloaded fallback also failed:", fallbackError);
6107
6503
  }
6108
6504
  return [
6109
6505
  3,
6110
- 9
6506
+ 10
6111
6507
  ];
6112
- case 9:
6508
+ case 10:
6113
6509
  if (this.isTemporaryAdError(playError)) {
6114
6510
  this.temporaryFailureUrls.set(vastTagUrl, Date.now());
6115
6511
  if (this.config.debugAdTiming) {
@@ -6126,12 +6522,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6126
6522
  this.activeAdRequestToken = null;
6127
6523
  }
6128
6524
  throw playError;
6129
- case 10:
6525
+ case 11:
6130
6526
  return [
6131
6527
  3,
6132
- 16
6528
+ 17
6133
6529
  ];
6134
- case 11:
6530
+ case 12:
6135
6531
  error = _state.sent();
6136
6532
  errorMessage = (error === null || error === void 0 ? void 0 : error.message) || "";
6137
6533
  if (this.config.debugAdTiming) {
@@ -6140,18 +6536,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6140
6536
  preloadedFallback1 = this.getPreloadedAd();
6141
6537
  if (!preloadedFallback1) return [
6142
6538
  3,
6143
- 15
6539
+ 16
6144
6540
  ];
6145
6541
  if (this.config.debugAdTiming) {
6146
6542
  console.log("[AD-ERROR] Request failed, trying preloaded fallback ad");
6147
6543
  }
6148
- _state.label = 12;
6149
- case 12:
6544
+ _state.label = 13;
6545
+ case 13:
6150
6546
  _state.trys.push([
6151
- 12,
6152
- 14,
6547
+ 13,
6548
+ 15,
6153
6549
  ,
6154
- 15
6550
+ 16
6155
6551
  ]);
6156
6552
  this.clearAdRequestWatchdog();
6157
6553
  this.clearAdFailsafeTimer();
@@ -6168,7 +6564,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6168
6564
  4,
6169
6565
  this.ima.play()
6170
6566
  ];
6171
- case 13:
6567
+ case 14:
6172
6568
  _state.sent();
6173
6569
  currentMuted2 = this.video.muted;
6174
6570
  currentVolume2 = this.video.volume;
@@ -6177,16 +6573,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6177
6573
  return [
6178
6574
  2
6179
6575
  ];
6180
- case 14:
6576
+ case 15:
6181
6577
  fallbackError1 = _state.sent();
6182
6578
  if (this.config.debugAdTiming) {
6183
6579
  console.warn("[AD-ERROR] Preloaded fallback also failed:", fallbackError1);
6184
6580
  }
6185
6581
  return [
6186
6582
  3,
6187
- 15
6583
+ 16
6188
6584
  ];
6189
- case 15:
6585
+ case 16:
6190
6586
  if (this.isTemporaryAdError(error)) {
6191
6587
  this.temporaryFailureUrls.set(vastTagUrl, Date.now());
6192
6588
  if (this.config.debugAdTiming) {
@@ -6204,7 +6600,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6204
6600
  this.activeAdRequestToken = null;
6205
6601
  }
6206
6602
  throw error;
6207
- case 16:
6603
+ case 17:
6208
6604
  return [
6209
6605
  2
6210
6606
  ];
@@ -6231,6 +6627,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6231
6627
  }
6232
6628
  this.adRequestQueue = [];
6233
6629
  this.inAdBreak = false;
6630
+ this.adDetectSentForCurrentBreak = false;
6234
6631
  this.expectedAdBreakDurationMs = void 0;
6235
6632
  this.currentAdBreakStartWallClockMs = void 0;
6236
6633
  this.clearAdStartTimer();
@@ -6240,6 +6637,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6240
6637
  this.currentAdIndex = 0;
6241
6638
  this.totalAdsInBreak = 0;
6242
6639
  this.consecutiveFailures = 0;
6640
+ this.globalConsecutiveNoFills = 0;
6243
6641
  this.ima.stop().catch(function() {});
6244
6642
  var restoredMuted = this.ima.getOriginalMutedState();
6245
6643
  var restoredVolume = this.ima.getOriginalVolume();
@@ -6271,6 +6669,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6271
6669
  key: "handleAdFailure",
6272
6670
  value: function handleAdFailure() {
6273
6671
  this.consecutiveFailures++;
6672
+ this.recordGamNoFill();
6274
6673
  var remaining = this.getRemainingAdMs();
6275
6674
  if (this.config.debugAdTiming) {
6276
6675
  console.log("[CONTINUOUS-FETCH] Ad failure: remaining=".concat(remaining, "ms, queued ads=").concat(this.adRequestQueue.length, ", consecutiveFailures=").concat(this.consecutiveFailures), this.adRequestQueue.length > 0 ? {
@@ -6298,8 +6697,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6298
6697
  key: "startAdRequestWatchdog",
6299
6698
  value: function startAdRequestWatchdog(token) {
6300
6699
  var _this = this;
6301
- this.clearAdRequestWatchdog();
6302
6700
  var _this_config_adFailsafeTimeoutMs;
6701
+ this.clearAdRequestWatchdog();
6303
6702
  var timeoutMs = (_this_config_adFailsafeTimeoutMs = this.config.adFailsafeTimeoutMs) !== null && _this_config_adFailsafeTimeoutMs !== void 0 ? _this_config_adFailsafeTimeoutMs : 1e4;
6304
6703
  this.adRequestWatchdogToken = token;
6305
6704
  this.adRequestWatchdogId = window.setTimeout(function() {
@@ -6342,8 +6741,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6342
6741
  key: "startAdFailsafeTimer",
6343
6742
  value: function startAdFailsafeTimer(token) {
6344
6743
  var _this = this;
6345
- this.clearAdFailsafeTimer();
6346
6744
  var _this_config_adFailsafeTimeoutMs;
6745
+ this.clearAdFailsafeTimer();
6347
6746
  var failsafeMs = (_this_config_adFailsafeTimeoutMs = this.config.adFailsafeTimeoutMs) !== null && _this_config_adFailsafeTimeoutMs !== void 0 ? _this_config_adFailsafeTimeoutMs : 1e4;
6348
6747
  this.adFailsafeToken = token;
6349
6748
  this.adFailsafeTimerId = window.setTimeout(function() {