stormcloud-video-player 0.8.55 → 0.8.57

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.
Files changed (69) hide show
  1. package/README.md +2 -2
  2. package/dist/stormcloud-vp.min.js +1 -3
  3. package/lib/index.cjs +377 -359
  4. package/lib/index.cjs.map +1 -1
  5. package/lib/index.d.cts +12 -30
  6. package/lib/index.d.ts +12 -30
  7. package/lib/index.js +357 -303
  8. package/lib/index.js.map +1 -1
  9. package/lib/player/AdBreakOrchestrator.cjs +140 -212
  10. package/lib/player/AdBreakOrchestrator.cjs.map +1 -1
  11. package/lib/player/AdBreakOrchestrator.d.cts +1 -1
  12. package/lib/player/AdConfigManager.cjs +103 -211
  13. package/lib/player/AdConfigManager.cjs.map +1 -1
  14. package/lib/player/AdConfigManager.d.cts +1 -2
  15. package/lib/player/AdTimingService.cjs.map +1 -1
  16. package/lib/player/AdTimingService.d.cts +1 -1
  17. package/lib/player/HlsEngine.cjs.map +1 -1
  18. package/lib/player/HlsEngine.d.cts +1 -1
  19. package/lib/player/PlaceholderLayer.cjs.map +1 -1
  20. package/lib/player/PlayerControls.cjs.map +1 -1
  21. package/lib/player/PlayerControls.d.cts +1 -1
  22. package/lib/player/Scte35CueManager.cjs.map +1 -1
  23. package/lib/player/Scte35CueManager.d.cts +1 -1
  24. package/lib/player/Scte35Parser.cjs.map +1 -1
  25. package/lib/player/Scte35Parser.d.cts +1 -1
  26. package/lib/player/StormcloudVideoPlayer.cjs +350 -281
  27. package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
  28. package/lib/player/StormcloudVideoPlayer.d.cts +1 -1
  29. package/lib/player/playerTypes.cjs.map +1 -1
  30. package/lib/player/playerTypes.d.cts +1 -1
  31. package/lib/players/FilePlayer.cjs.map +1 -1
  32. package/lib/players/HlsPlayer.cjs +350 -281
  33. package/lib/players/HlsPlayer.cjs.map +1 -1
  34. package/lib/players/HlsPlayer.d.cts +1 -1
  35. package/lib/players/index.cjs +350 -281
  36. package/lib/players/index.cjs.map +1 -1
  37. package/lib/sdk/hlsAdPlayer.cjs +194 -52
  38. package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
  39. package/lib/sdk/hlsAdPlayer.d.cts +1 -1
  40. package/lib/sdk/pal.cjs.map +1 -1
  41. package/lib/{types-DpbgEvSH.d.cts → types-cTqIKw_D.d.cts} +0 -1
  42. package/lib/ui/StormcloudVideoPlayer.cjs +350 -281
  43. package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
  44. package/lib/ui/StormcloudVideoPlayer.d.cts +1 -1
  45. package/lib/utils/browserCompat.cjs.map +1 -1
  46. package/lib/utils/ctvVastSignals.cjs.map +1 -1
  47. package/lib/utils/devUrl.cjs.map +1 -1
  48. package/lib/utils/polyfills.cjs.map +1 -1
  49. package/lib/utils/tracking.cjs +135 -212
  50. package/lib/utils/tracking.cjs.map +1 -1
  51. package/lib/utils/tracking.d.cts +1 -1
  52. package/lib/utils/trackingIngest.cjs +322 -0
  53. package/lib/utils/trackingIngest.cjs.map +1 -0
  54. package/lib/utils/trackingIngest.d.cts +14 -0
  55. package/lib/utils/vastEnvironmentSignals.cjs +0 -4
  56. package/lib/utils/vastEnvironmentSignals.cjs.map +1 -1
  57. package/lib/utils/vastEnvironmentSignals.d.cts +1 -2
  58. package/lib/utils/vastMacros.cjs.map +1 -1
  59. package/lib/utils/vastTrackingMacros.cjs +185 -0
  60. package/lib/utils/vastTrackingMacros.cjs.map +1 -0
  61. package/lib/utils/vastTrackingMacros.d.cts +19 -0
  62. package/package.json +1 -3
  63. package/lib/utils/mqttClient.cjs +0 -305
  64. package/lib/utils/mqttClient.cjs.map +0 -1
  65. package/lib/utils/mqttClient.d.cts +0 -13
  66. package/lib/utils/mqttConfig.cjs +0 -139
  67. package/lib/utils/mqttConfig.cjs.map +0 -1
  68. package/lib/utils/mqttConfig.d.cts +0 -20
  69. package/src/certs/emqxsl-ca.crt +0 -22
package/lib/index.cjs CHANGED
@@ -423,8 +423,8 @@ var __toCommonJS = function __toCommonJS(mod) {
423
423
  // src/index.ts
424
424
  var index_exports = {};
425
425
  __export(index_exports, {
426
- DEFAULT_MQTT_CONFIG: function DEFAULT_MQTT_CONFIG1() {
427
- return DEFAULT_MQTT_CONFIG;
426
+ DEFAULT_TRACKING_INGEST_CONFIG: function DEFAULT_TRACKING_INGEST_CONFIG1() {
427
+ return DEFAULT_TRACKING_INGEST_CONFIG;
428
428
  },
429
429
  IS_BROWSER: function IS_BROWSER1() {
430
430
  return IS_BROWSER;
@@ -438,9 +438,6 @@ __export(index_exports, {
438
438
  IS_SAFARI: function IS_SAFARI1() {
439
439
  return IS_SAFARI;
440
440
  },
441
- MQTT_CA_CERT_FILE: function MQTT_CA_CERT_FILE1() {
442
- return MQTT_CA_CERT_FILE;
443
- },
444
441
  SUPPORTS_DASH: function SUPPORTS_DASH1() {
445
442
  return SUPPORTS_DASH;
446
443
  },
@@ -456,23 +453,17 @@ __export(index_exports, {
456
453
  StormcloudVideoPlayerComponent: function StormcloudVideoPlayerComponent1() {
457
454
  return StormcloudVideoPlayerComponent;
458
455
  },
459
- applyMQTTConfig: function applyMQTTConfig1() {
460
- return applyMQTTConfig;
456
+ applyTrackingIngestConfig: function applyTrackingIngestConfig1() {
457
+ return applyTrackingIngestConfig;
461
458
  },
462
459
  buildAnalyticsContext: function buildAnalyticsContext1() {
463
460
  return buildAnalyticsContext;
464
461
  },
465
- buildMQTTBrokerUrl: function buildMQTTBrokerUrl1() {
466
- return buildMQTTBrokerUrl;
467
- },
468
- buildPlayerTopic: function buildPlayerTopic1() {
469
- return buildPlayerTopic;
470
- },
471
462
  canPlay: function canPlay1() {
472
463
  return canPlay;
473
464
  },
474
- configureMQTT: function configureMQTT1() {
475
- return configureMQTT;
465
+ configureTrackingIngest: function configureTrackingIngest1() {
466
+ return configureTrackingIngest;
476
467
  },
477
468
  createHlsAdPlayer: function createHlsAdPlayer1() {
478
469
  return createHlsAdPlayer;
@@ -489,12 +480,6 @@ __export(index_exports, {
489
480
  detectBrowser: function detectBrowser1() {
490
481
  return detectBrowser;
491
482
  },
492
- disconnectMQTT: function disconnectMQTT1() {
493
- return disconnectMQTT;
494
- },
495
- ensureMQTTClient: function ensureMQTTClient1() {
496
- return ensureMQTTClient;
497
- },
498
483
  getBrowserConfigOverrides: function getBrowserConfigOverrides1() {
499
484
  return getBrowserConfigOverrides;
500
485
  },
@@ -504,27 +489,18 @@ __export(index_exports, {
504
489
  getClientInfo: function getClientInfo1() {
505
490
  return getClientInfo;
506
491
  },
507
- getMQTTStatus: function getMQTTStatus1() {
508
- return getMQTTStatus;
509
- },
510
- initMQTTClient: function initMQTTClient1() {
511
- return initMQTTClient;
492
+ ingestPlayerTracking: function ingestPlayerTracking1() {
493
+ return ingestPlayerTracking;
512
494
  },
513
495
  initializePolyfills: function initializePolyfills1() {
514
496
  return initializePolyfills;
515
497
  },
516
- isMQTTConfigured: function isMQTTConfigured1() {
517
- return isMQTTConfigured;
518
- },
519
- isMQTTConnected: function isMQTTConnected1() {
520
- return isMQTTConnected;
521
- },
522
- isMQTTEnabled: function isMQTTEnabled1() {
523
- return isMQTTEnabled;
524
- },
525
498
  isMediaStream: function isMediaStream1() {
526
499
  return isMediaStream;
527
500
  },
501
+ isTrackingIngestEnabled: function isTrackingIngestEnabled1() {
502
+ return isTrackingIngestEnabled;
503
+ },
528
504
  lazy: function lazy1() {
529
505
  return lazy;
530
506
  },
@@ -534,9 +510,6 @@ __export(index_exports, {
534
510
  merge: function merge1() {
535
511
  return merge;
536
512
  },
537
- mqttConfig: function mqttConfig1() {
538
- return mqttConfig;
539
- },
540
513
  omit: function omit1() {
541
514
  return omit;
542
515
  },
@@ -546,9 +519,6 @@ __export(index_exports, {
546
519
  players: function players() {
547
520
  return players_default;
548
521
  },
549
- publishMQTT: function publishMQTT1() {
550
- return publishMQTT;
551
- },
552
522
  randomString: function randomString1() {
553
523
  return randomString;
554
524
  },
@@ -578,6 +548,9 @@ __export(index_exports, {
578
548
  },
579
549
  supportsWebKitPresentationMode: function supportsWebKitPresentationMode1() {
580
550
  return supportsWebKitPresentationMode;
551
+ },
552
+ trackingIngestConfig: function trackingIngestConfig1() {
553
+ return trackingIngestConfig;
581
554
  }
582
555
  });
583
556
  module.exports = __toCommonJS(index_exports);
@@ -780,15 +753,147 @@ function supportsFeature(feature) {
780
753
  return false;
781
754
  }
782
755
  }
756
+ // src/utils/vastTrackingMacros.ts
757
+ var VAST_MACRO_PATTERN = /\[([A-Z][A-Z0-9_]*)\]/g;
758
+ var CACHEBUSTING_ALIASES = /\[CACHEBUSTER\]|\[cachebuster\]|\[timestamp\]|\[random\]|\[INSERT_RANDOM_NUMBER\]|%%CACHEBUSTER%%|%%CACHEBUST%%|\$\{CACHEBUSTER\}|\$\{CACHEBUSTING\}|\{cachebuster\}|\{random\}/g;
759
+ var KNOWN_VAST_MACROS = /* @__PURE__ */ new Set([
760
+ "ADCATEGORIES",
761
+ "ADCOUNT",
762
+ "ADPLAYHEAD",
763
+ "ADSERVINGID",
764
+ "ADTYPE",
765
+ "APIFRAMEWORKS",
766
+ "APPBUNDLE",
767
+ "ASSETURI",
768
+ "BLOCKEDADCATEGORIES",
769
+ "BREAKMAXADLENGTH",
770
+ "BREAKMAXADS",
771
+ "BREAKMAXDURATION",
772
+ "BREAKMINADLENGTH",
773
+ "BREAKPOSITION",
774
+ "CACHEBUSTING",
775
+ "CLICKPOS",
776
+ "CLICKTYPE",
777
+ "CLIENTUA",
778
+ "CONTENTID",
779
+ "CONTENTPLAYHEAD",
780
+ "CONTENTURI",
781
+ "DEVICEIP",
782
+ "DEVICEUA",
783
+ "DOMAIN",
784
+ "ERRORCODE",
785
+ "EXTENSIONS",
786
+ "GDPRCONSENT",
787
+ "IFA",
788
+ "IFATYPE",
789
+ "INVENTORYSTATE",
790
+ "LATLONG",
791
+ "LIMITADTRACKING",
792
+ "MEDIAMIME",
793
+ "MEDIAPLAYHEAD",
794
+ "OMIDPARTNER",
795
+ "PAGEURL",
796
+ "PLACEMENTTYPE",
797
+ "PLAYERCAPABILITIES",
798
+ "PLAYERSIZE",
799
+ "PLAYERSTATE",
800
+ "PODSEQUENCE",
801
+ "REGULATIONS",
802
+ "SERVERSIDE",
803
+ "SERVERUA",
804
+ "TIMESTAMP",
805
+ "TRANSACTIONID",
806
+ "UNIVERSALADID",
807
+ "VASTVERSIONS",
808
+ "VERIFICATIONVENDORS"
809
+ ]);
810
+ function generateCachebuster() {
811
+ return String(Math.floor(Math.random() * 9e7) + 1e7);
812
+ }
813
+ function formatPlayhead(seconds) {
814
+ if (seconds == null || !Number.isFinite(seconds) || seconds < 0) {
815
+ return void 0;
816
+ }
817
+ var total = Math.floor(seconds);
818
+ var hh = String(Math.floor(total / 3600)).padStart(2, "0");
819
+ var mm = String(Math.floor(total % 3600 / 60)).padStart(2, "0");
820
+ var ss = String(total % 60).padStart(2, "0");
821
+ var ms = String(Math.floor((seconds - total) * 1e3)).padStart(3, "0");
822
+ return "".concat(hh, ":").concat(mm, ":").concat(ss, ".").concat(ms);
823
+ }
824
+ function resolveMacroValues(ctx) {
825
+ var values = /* @__PURE__ */ new Map();
826
+ var set = function set(key, value) {
827
+ if (value != null && value !== "") values.set(key, value);
828
+ };
829
+ var adPlayhead = formatPlayhead(ctx.adPlayheadSeconds);
830
+ set("ADPLAYHEAD", adPlayhead);
831
+ set("MEDIAPLAYHEAD", adPlayhead);
832
+ set("CONTENTPLAYHEAD", formatPlayhead(ctx.contentPlayheadSeconds));
833
+ set("ASSETURI", ctx.assetUri);
834
+ set("MEDIAMIME", ctx.mediaMime);
835
+ set("TIMESTAMP", (/* @__PURE__ */ new Date()).toISOString());
836
+ set("SERVERSIDE", "0");
837
+ if (ctx.errorCode != null && ctx.errorCode !== "") {
838
+ set("ERRORCODE", String(ctx.errorCode));
839
+ }
840
+ if (ctx.playerWidth != null && ctx.playerHeight != null) {
841
+ set("PLAYERSIZE", "".concat(Math.round(ctx.playerWidth), ",").concat(Math.round(ctx.playerHeight)));
842
+ }
843
+ set("IFA", ctx.deviceId);
844
+ set("IFATYPE", ctx.deviceIdType);
845
+ if (ctx.limitAdTracking != null) {
846
+ set("LIMITADTRACKING", ctx.limitAdTracking ? "1" : "0");
847
+ }
848
+ set("PAGEURL", ctx.pageUrl);
849
+ if (ctx.pageUrl) {
850
+ try {
851
+ set("DOMAIN", new URL(ctx.pageUrl).hostname);
852
+ } catch (unused) {}
853
+ }
854
+ set("CLIENTUA", ctx.clientUa);
855
+ set("DEVICEUA", ctx.clientUa);
856
+ if (ctx.podSequence != null) {
857
+ set("PODSEQUENCE", String(ctx.podSequence));
858
+ }
859
+ return values;
860
+ }
861
+ function substituteVastTrackingMacros(url) {
862
+ var ctx = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
863
+ if (!url) return url;
864
+ var values = resolveMacroValues(ctx);
865
+ return url.replace(CACHEBUSTING_ALIASES, function() {
866
+ return generateCachebuster();
867
+ }).replace(VAST_MACRO_PATTERN, function(match, name) {
868
+ if (name === "CACHEBUSTING") return generateCachebuster();
869
+ var value = values.get(name);
870
+ if (value != null) return encodeURIComponent(value);
871
+ return KNOWN_VAST_MACROS.has(name) ? "" : match;
872
+ });
873
+ }
783
874
  // src/sdk/hlsAdPlayer.ts
784
875
  var MAX_VAST_WRAPPER_DEPTH = 5;
876
+ var BEACON_TIMEOUT_MS = 3e4;
877
+ var inFlightBeacons = /* @__PURE__ */ new Set();
878
+ var VAST_ERROR_MEDIA_DISPLAY = 405;
879
+ function toVastMediaErrorCode(error) {
880
+ switch(error === null || error === void 0 ? void 0 : error.code){
881
+ case 1:
882
+ return 400;
883
+ case 2:
884
+ return 401;
885
+ case 4:
886
+ return 403;
887
+ default:
888
+ return VAST_ERROR_MEDIA_DISPLAY;
889
+ }
890
+ }
785
891
  function createHlsAdPlayer(contentVideo, options) {
786
892
  var _contentVideo_AD_VIDEO_PROP, _contentVideo_AD_CONTAINER_PROP;
787
893
  var adPlaying = false;
788
894
  var originalMutedState = false;
789
895
  var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
790
896
  var listeners = /* @__PURE__ */ new Map();
791
- var licenseKey = options === null || options === void 0 ? void 0 : options.licenseKey;
792
897
  var mainHlsInstance = options === null || options === void 0 ? void 0 : options.mainHlsInstance;
793
898
  var AD_CONTAINER_PROP = "__stormcloudAdContainer";
794
899
  var AD_VIDEO_PROP = "__stormcloudAdVideo";
@@ -799,10 +904,9 @@ function createHlsAdPlayer(contentVideo, options) {
799
904
  var adContainerEl = (_contentVideo_AD_CONTAINER_PROP = contentVideo[AD_CONTAINER_PROP]) !== null && _contentVideo_AD_CONTAINER_PROP !== void 0 ? _contentVideo_AD_CONTAINER_PROP : void 0;
800
905
  var adEventHandlers = [];
801
906
  var currentAd;
802
- var currentAdMediaUrl;
907
+ var currentAdMediaFile;
803
908
  var podAds = [];
804
909
  var podIndex = 0;
805
- var sessionId;
806
910
  var preloadedAds = /* @__PURE__ */ new Map();
807
911
  var preloadingAds = /* @__PURE__ */ new Map();
808
912
  var destroyed = false;
@@ -852,21 +956,47 @@ function createHlsAdPlayer(contentVideo, options) {
852
956
  }
853
957
  }
854
958
  }
855
- function generateSessionId() {
856
- return "session-".concat(Date.now(), "-").concat(Math.random().toString(36).substr(2, 9));
959
+ function buildTrackingMacroContext(errorCode) {
960
+ var context = {
961
+ adPlayheadSeconds: adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.currentTime,
962
+ contentPlayheadSeconds: contentVideo.currentTime,
963
+ assetUri: currentAdMediaFile === null || currentAdMediaFile === void 0 ? void 0 : currentAdMediaFile.url,
964
+ mediaMime: currentAdMediaFile === null || currentAdMediaFile === void 0 ? void 0 : currentAdMediaFile.type,
965
+ playerWidth: (adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.clientWidth) || (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.clientWidth),
966
+ playerHeight: (adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.clientHeight) || (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.clientHeight)
967
+ };
968
+ if (errorCode != null) {
969
+ context.errorCode = errorCode;
970
+ }
971
+ if (typeof navigator !== "undefined" && navigator.userAgent) {
972
+ context.clientUa = navigator.userAgent;
973
+ }
974
+ if (typeof location !== "undefined" && location.href) {
975
+ context.pageUrl = location.href;
976
+ }
977
+ if (podAds.length > 0) {
978
+ context.podSequence = podIndex + 1;
979
+ }
980
+ return context;
857
981
  }
858
- function fireTrackingPixels(urls) {
982
+ function fireTrackingPixels(urls, options2) {
859
983
  if (!urls || urls.length === 0) return;
984
+ var macroContext = buildTrackingMacroContext(options2 === null || options2 === void 0 ? void 0 : options2.errorCode);
860
985
  urls.forEach(function(url) {
861
986
  try {
862
- var trackingUrl = url;
863
- if (sessionId) {
864
- trackingUrl = "".concat(trackingUrl).concat(trackingUrl.includes("?") ? "&" : "?", "session_id=").concat(sessionId);
865
- }
866
- if (licenseKey) {
867
- trackingUrl = "".concat(trackingUrl).concat(trackingUrl.includes("?") ? "&" : "?", "license_key=").concat(licenseKey);
868
- }
987
+ var trackingUrl = substituteVastTrackingMacros(url, macroContext);
869
988
  var img = new Image(1, 1);
989
+ inFlightBeacons.add(img);
990
+ var timeoutId;
991
+ var release = function release() {
992
+ if (timeoutId !== void 0) clearTimeout(timeoutId);
993
+ img.onload = null;
994
+ img.onerror = null;
995
+ inFlightBeacons.delete(img);
996
+ };
997
+ img.onload = release;
998
+ img.onerror = release;
999
+ timeoutId = setTimeout(release, BEACON_TIMEOUT_MS);
870
1000
  img.src = trackingUrl;
871
1001
  console.log("[HlsAdPlayer] Fired tracking pixel: ".concat(trackingUrl));
872
1002
  } catch (error) {
@@ -1505,7 +1635,9 @@ function createHlsAdPlayer(contentVideo, options) {
1505
1635
  if (!adPlaying) return;
1506
1636
  console.error("[HlsAdPlayer] Ad video error:", e);
1507
1637
  if (currentAd) {
1508
- fireTrackingPixels(currentAd.trackingUrls.error);
1638
+ fireTrackingPixels(currentAd.trackingUrls.error, {
1639
+ errorCode: toVastMediaErrorCode(adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.error)
1640
+ });
1509
1641
  }
1510
1642
  if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1511
1643
  return;
@@ -1617,9 +1749,9 @@ function createHlsAdPlayer(contentVideo, options) {
1617
1749
  delete contentVideo.dataset.stormcloudAdPlaying;
1618
1750
  }
1619
1751
  }
1620
- function resetQuartileTracking() {
1752
+ function resetQuartileTracking(preserveImpression) {
1621
1753
  trackingFired = {
1622
- impression: false,
1754
+ impression: preserveImpression ? trackingFired.impression : false,
1623
1755
  start: false,
1624
1756
  firstQuartile: false,
1625
1757
  midpoint: false,
@@ -1627,27 +1759,6 @@ function createHlsAdPlayer(contentVideo, options) {
1627
1759
  complete: false
1628
1760
  };
1629
1761
  }
1630
- function markCreativeRendered(reason) {
1631
- if (!currentAd || trackingFired.impression) return;
1632
- trackingFired.impression = true;
1633
- fireTrackingPixels(currentAd.trackingUrls.impression);
1634
- console.log("[HlsAdPlayer] Impression (pod ".concat(podIndex + 1, "/").concat(podAds.length || 1, ", reason: ").concat(reason, "): ").concat(currentAd.title));
1635
- emit("ad_impression", {
1636
- adId: currentAd.id,
1637
- title: currentAd.title,
1638
- durationSeconds: currentAd.duration,
1639
- mediaUrl: currentAdMediaUrl,
1640
- podIndex: podIndex,
1641
- podSize: podAds.length || 1,
1642
- reason: reason
1643
- });
1644
- }
1645
- function canDetectBlackFrames() {
1646
- if (!adVideoElement) return false;
1647
- if (requiresMediaPipelineResetAfterAds()) return false;
1648
- if (isRvfcSupported(adVideoElement)) return true;
1649
- return getDecodedVideoFrameCount(adVideoElement) !== void 0;
1650
- }
1651
1762
  function isRvfcSupported(video) {
1652
1763
  return typeof video.requestVideoFrameCallback === "function";
1653
1764
  }
@@ -1710,7 +1821,7 @@ function createHlsAdPlayer(contentVideo, options) {
1710
1821
  if (!mediaFile) {
1711
1822
  throw new Error("No media file available for ad");
1712
1823
  }
1713
- currentAdMediaUrl = mediaFile.url;
1824
+ currentAdMediaFile = mediaFile;
1714
1825
  var isHlsAd = isHlsMediaFile(mediaFile);
1715
1826
  console.log("[HlsAdPlayer] Loading ".concat(isHlsAd ? "HLS" : "progressive", " ad (pod ").concat(podIndex + 1, "/").concat(podAds.length || 1, ") from: ").concat(mediaFile.url));
1716
1827
  if (isHlsAd && import_hls.default.isSupported()) {
@@ -1754,9 +1865,11 @@ function createHlsAdPlayer(contentVideo, options) {
1754
1865
  }
1755
1866
  podIndex++;
1756
1867
  currentAd = podAds[podIndex];
1757
- currentAdMediaUrl = void 0;
1758
- resetQuartileTracking();
1868
+ currentAdMediaFile = void 0;
1869
+ resetQuartileTracking(false);
1759
1870
  if (currentAd) {
1871
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1872
+ trackingFired.impression = true;
1760
1873
  console.log("[HlsAdPlayer] Advancing to next pod ad (".concat(podIndex + 1, "/").concat(podAds.length, "): ").concat(currentAd.title, ", duration: ").concat(currentAd.duration, "s"));
1761
1874
  }
1762
1875
  clearStallWatchdog();
@@ -1795,7 +1908,9 @@ function createHlsAdPlayer(contentVideo, options) {
1795
1908
  console.warn("[HlsAdPlayer] Ad playback stalled (no progress) - recovering to avoid a blank frame");
1796
1909
  clearStallWatchdog();
1797
1910
  if (currentAd) {
1798
- fireTrackingPixels(currentAd.trackingUrls.error);
1911
+ fireTrackingPixels(currentAd.trackingUrls.error, {
1912
+ errorCode: VAST_ERROR_MEDIA_DISPLAY
1913
+ });
1799
1914
  }
1800
1915
  if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1801
1916
  return;
@@ -1851,7 +1966,6 @@ function createHlsAdPlayer(contentVideo, options) {
1851
1966
  if (!adPlaying) return;
1852
1967
  sawDecodedVideoFrame = true;
1853
1968
  markRvfcReliable();
1854
- markCreativeRendered("first_presented_frame");
1855
1969
  };
1856
1970
  try {
1857
1971
  videoFrameCallbackHandle = rvfc.call(adVideoElement, onPresentedFrame);
@@ -1864,7 +1978,9 @@ function createHlsAdPlayer(contentVideo, options) {
1864
1978
  console.warn("[HlsAdPlayer] Ad audio is advancing but no video frames decoded (black screen) - skipping this creative");
1865
1979
  clearStallWatchdog();
1866
1980
  if (currentAd) {
1867
- fireTrackingPixels(currentAd.trackingUrls.error);
1981
+ fireTrackingPixels(currentAd.trackingUrls.error, {
1982
+ errorCode: VAST_ERROR_MEDIA_DISPLAY
1983
+ });
1868
1984
  }
1869
1985
  if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1870
1986
  return;
@@ -1886,7 +2002,6 @@ function createHlsAdPlayer(contentVideo, options) {
1886
2002
  if (decodedFrames !== void 0 && decodedFrames > 0) {
1887
2003
  sawDecodedVideoFrame = true;
1888
2004
  markFrameCounterReliable();
1889
- markCreativeRendered("decoded_frames");
1890
2005
  } else if (adVideoElement.currentTime >= BLACKFRAME_MIN_PLAYBACK_S) {
1891
2006
  var timeAdvancing = adVideoElement.currentTime > lastAdProgressPosition + 0.05;
1892
2007
  if (isRvfcSupported(adVideoElement) && timeAdvancing && isRvfcReliable()) {
@@ -1899,9 +2014,6 @@ function createHlsAdPlayer(contentVideo, options) {
1899
2014
  }
1900
2015
  }
1901
2016
  }
1902
- if (!trackingFired.impression && !adVideoElement.paused && adVideoElement.currentTime >= BLACKFRAME_MIN_PLAYBACK_S && (sawDecodedVideoFrame || !canDetectBlackFrames())) {
1903
- markCreativeRendered(sawDecodedVideoFrame ? "decoded_frames" : "sustained_playback");
1904
- }
1905
2017
  if (adVideoElement.currentTime > lastAdProgressPosition + 0.05) {
1906
2018
  noteAdProgress();
1907
2019
  return;
@@ -2002,7 +2114,6 @@ function createHlsAdPlayer(contentVideo, options) {
2002
2114
  ,
2003
2115
  6
2004
2116
  ]);
2005
- sessionId = generateSessionId();
2006
2117
  ads = [];
2007
2118
  if (!preloadedAds.has(vastTagUrl)) return [
2008
2119
  3,
@@ -2040,9 +2151,12 @@ function createHlsAdPlayer(contentVideo, options) {
2040
2151
  podAds = ads;
2041
2152
  podIndex = 0;
2042
2153
  currentAd = ads[0];
2043
- currentAdMediaUrl = void 0;
2044
- resetQuartileTracking();
2154
+ currentAdMediaFile = void 0;
2045
2155
  console.log("[HlsAdPlayer] Pod parsed: ".concat(ads.length, ' ad(s), first="').concat(currentAd === null || currentAd === void 0 ? void 0 : currentAd.title, '", duration=').concat(currentAd === null || currentAd === void 0 ? void 0 : currentAd.duration, "s"));
2156
+ if (currentAd) {
2157
+ fireTrackingPixels(currentAd.trackingUrls.impression);
2158
+ trackingFired.impression = true;
2159
+ }
2046
2160
  return [
2047
2161
  2,
2048
2162
  Promise.resolve()
@@ -2082,7 +2196,7 @@ function createHlsAdPlayer(contentVideo, options) {
2082
2196
  contentVideo[AD_VIDEO_PROP] = adVideoElement;
2083
2197
  }
2084
2198
  setupAdEventListeners();
2085
- resetQuartileTracking();
2199
+ resetQuartileTracking(true);
2086
2200
  contentVolume = contentVideo.volume;
2087
2201
  originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
2088
2202
  if (!(options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds)) {
@@ -2172,7 +2286,7 @@ function createHlsAdPlayer(contentVideo, options) {
2172
2286
  }
2173
2287
  }
2174
2288
  currentAd = void 0;
2175
- currentAdMediaUrl = void 0;
2289
+ currentAdMediaFile = void 0;
2176
2290
  podAds = [];
2177
2291
  podIndex = 0;
2178
2292
  return [
@@ -2213,6 +2327,7 @@ function createHlsAdPlayer(contentVideo, options) {
2213
2327
  teardownAdEventListeners();
2214
2328
  releaseAdDecoder();
2215
2329
  currentAd = void 0;
2330
+ currentAdMediaFile = void 0;
2216
2331
  podAds = [];
2217
2332
  podIndex = 0;
2218
2333
  listeners.clear();
@@ -2536,184 +2651,89 @@ function createPalNonceManager() {
2536
2651
  }
2537
2652
  };
2538
2653
  }
2539
- // src/utils/mqttConfig.ts
2540
- var MQTT_CA_CERT_FILE = "src/certs/emqxsl-ca.crt";
2541
- var DEFAULT_MQTT_CONFIG = {
2654
+ // src/utils/trackingIngest.ts
2655
+ var DEFAULT_TRACKING_INGEST_CONFIG = {
2542
2656
  enabled: true,
2543
- brokerAddress: "vecbae77.ala.us-east-1.emqxsl.com",
2544
- brokerPort: 8883,
2545
- wsPort: 8084,
2546
- username: "for-sonifi",
2547
- password: "sonifi-mqtt",
2548
- topicPrefix: "adstorm/players",
2549
- qos: 1
2657
+ baseUrl: "https://player-analytics-ingest-api-760490581852.us-central1.run.app/api/adstorm/player-tracking"
2550
2658
  };
2551
- var mqttConfig = _object_spread({}, DEFAULT_MQTT_CONFIG);
2552
- function applyMQTTConfig(overrides) {
2553
- Object.assign(mqttConfig, overrides);
2554
- }
2555
- function isMQTTEnabled() {
2556
- return mqttConfig.enabled;
2557
- }
2558
- function buildMQTTBrokerUrl() {
2559
- if (mqttConfig.brokerUrl) return mqttConfig.brokerUrl;
2560
- return "wss://".concat(mqttConfig.brokerAddress, ":").concat(mqttConfig.wsPort, "/mqtt");
2561
- }
2562
- function buildPlayerTopic(licenseKey, channel) {
2563
- return "".concat(mqttConfig.topicPrefix, "/").concat(licenseKey, "/").concat(channel);
2564
- }
2565
- // src/utils/mqttClient.ts
2566
- var import_mqtt = __toESM(require("mqtt"), 1);
2567
- var LOG = "[StormcloudVideoPlayer][MQTT]";
2568
- var KEEPALIVE_SECONDS = 30;
2569
- var CONNECT_TIMEOUT_MS = 1e4;
2570
- var RECONNECT_BASE_MS = 5e3;
2571
- var RECONNECT_MAX_MS = 6e4;
2572
- var MAX_RECONNECT_ATTEMPTS = 8;
2573
- var COOLDOWN_MS = 10 * 6e4;
2574
- var client = null;
2575
- var status = "disconnected";
2576
- var reconnectAttempts = 0;
2577
- var reconnectTimer = null;
2578
- var stopped = false;
2579
- function getMQTTStatus() {
2580
- return status;
2581
- }
2582
- function isMQTTConnected() {
2583
- return status === "connected" && client !== null && client.connected;
2584
- }
2585
- function isMQTTConfigured() {
2586
- return isMQTTEnabled();
2587
- }
2588
- function configureMQTT(overrides) {
2589
- applyMQTTConfig(overrides);
2590
- disconnectMQTT();
2591
- }
2592
- function clearReconnectTimer() {
2593
- if (reconnectTimer) {
2594
- clearTimeout(reconnectTimer);
2595
- reconnectTimer = null;
2596
- }
2597
- }
2598
- function teardownClient() {
2599
- if (client) {
2600
- try {
2601
- client.removeAllListeners();
2602
- client.end(true);
2603
- } catch (unused) {}
2604
- client = null;
2605
- }
2606
- }
2607
- function scheduleReconnect() {
2608
- if (stopped || !isMQTTEnabled() || reconnectTimer) return;
2609
- if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
2610
- console.warn("".concat(LOG, " giving up after ").concat(reconnectAttempts, " attempts; cooling down for ").concat(COOLDOWN_MS / 6e4, "m"));
2611
- teardownClient();
2612
- status = "disconnected";
2613
- reconnectTimer = setTimeout(function() {
2614
- reconnectTimer = null;
2615
- reconnectAttempts = 0;
2616
- openConnection();
2617
- }, COOLDOWN_MS);
2618
- return;
2619
- }
2620
- var delay = Math.min(RECONNECT_MAX_MS, RECONNECT_BASE_MS * Math.pow(2, reconnectAttempts));
2621
- var jitter = Math.floor(Math.random() * 1e3);
2622
- reconnectAttempts += 1;
2623
- reconnectTimer = setTimeout(function() {
2624
- reconnectTimer = null;
2625
- openConnection();
2626
- }, delay + jitter);
2627
- }
2628
- function openConnection() {
2629
- if (stopped || !isMQTTEnabled()) return;
2630
- teardownClient();
2631
- var url = buildMQTTBrokerUrl();
2632
- status = "connecting";
2633
- var clientId = "stormcloud-vp-".concat(Math.random().toString(36).slice(2, 9));
2634
- try {
2635
- client = import_mqtt.default.connect(url, {
2636
- clientId: clientId,
2637
- username: mqttConfig.username,
2638
- password: mqttConfig.password,
2639
- keepalive: KEEPALIVE_SECONDS,
2640
- clean: true,
2641
- // Disable MQTT.js internal reconnect; we manage reconnection ourselves.
2642
- reconnectPeriod: 0,
2643
- connectTimeout: CONNECT_TIMEOUT_MS,
2644
- queueQoSZero: false,
2645
- reschedulePings: true,
2646
- // Root-cause fix for the Tizen 4.0 "Keepalive timeout" loop: MQTT.js's
2647
- // default timerVariant "auto" runs the keepalive interval inside a
2648
- // Blob-URL Web Worker (via worker-timers). On Samsung Tizen 4.0 (old
2649
- // WebKit) served from a file:// origin that worker can't tick reliably,
2650
- // so the keepalive counter trips onKeepaliveTimeout almost immediately
2651
- // after connect. Force the native setInterval timer instead; the main
2652
- // thread is free because video is decoded by the native AVPlay pipeline.
2653
- timerVariant: "native"
2654
- });
2655
- } catch (err) {
2656
- status = "error";
2657
- console.warn("".concat(LOG, " connect() threw:"), err);
2658
- scheduleReconnect();
2659
- return;
2660
- }
2661
- client.on("connect", function() {
2662
- status = "connected";
2663
- reconnectAttempts = 0;
2664
- clearReconnectTimer();
2665
- console.info("".concat(LOG, " connected to ").concat(url));
2666
- });
2667
- client.on("offline", function() {
2668
- if (status === "connected") status = "disconnected";
2669
- console.warn("".concat(LOG, " offline"));
2670
- scheduleReconnect();
2671
- });
2672
- client.on("error", function(err) {
2673
- status = "error";
2674
- console.warn("".concat(LOG, " error:"), err.message);
2675
- scheduleReconnect();
2676
- });
2677
- client.on("close", function() {
2678
- if (status === "connected") status = "disconnected";
2679
- scheduleReconnect();
2680
- });
2659
+ var trackingIngestConfig = _object_spread({}, DEFAULT_TRACKING_INGEST_CONFIG);
2660
+ function applyTrackingIngestConfig(overrides) {
2661
+ Object.assign(trackingIngestConfig, overrides);
2681
2662
  }
2682
- function initMQTTClient() {
2683
- if (client || !isMQTTEnabled()) return;
2684
- stopped = false;
2685
- reconnectAttempts = 0;
2686
- openConnection();
2663
+ function configureTrackingIngest(overrides) {
2664
+ applyTrackingIngestConfig(overrides);
2687
2665
  }
2688
- function ensureMQTTClient() {
2689
- if (isMQTTEnabled() && !client && !reconnectTimer) {
2690
- initMQTTClient();
2691
- }
2666
+ function isTrackingIngestEnabled() {
2667
+ return trackingIngestConfig.enabled === true;
2692
2668
  }
2693
- function publishMQTT(topic, payload) {
2694
- if (!isMQTTEnabled()) {
2695
- return false;
2696
- }
2697
- ensureMQTTClient();
2698
- if (!client || !client.connected) {
2699
- return false;
2700
- }
2701
- try {
2702
- client.publish(topic, JSON.stringify(payload), {
2703
- qos: mqttConfig.qos
2704
- });
2705
- return true;
2706
- } catch (err) {
2707
- console.warn("".concat(LOG, " publish failed on ").concat(topic, ":"), err);
2708
- return false;
2669
+ function normalizeIngestBaseUrl(baseUrl) {
2670
+ return baseUrl.replace(/\/+$/, "");
2671
+ }
2672
+ function buildTrackingIngestUrl(channel) {
2673
+ var base = normalizeIngestBaseUrl(trackingIngestConfig.baseUrl);
2674
+ if (channel === "impressions") {
2675
+ return "".concat(base, "/impressions/ingest");
2709
2676
  }
2677
+ return "".concat(base, "/metrics/ingest");
2710
2678
  }
2711
- function disconnectMQTT() {
2712
- stopped = true;
2713
- clearReconnectTimer();
2714
- teardownClient();
2715
- reconnectAttempts = 0;
2716
- status = "disconnected";
2679
+ function ingestPlayerTracking(licenseKey, channel, body) {
2680
+ return _async_to_generator(function() {
2681
+ var response, error;
2682
+ return _ts_generator(this, function(_state) {
2683
+ switch(_state.label){
2684
+ case 0:
2685
+ if (!isTrackingIngestEnabled() || !licenseKey) {
2686
+ return [
2687
+ 2,
2688
+ false
2689
+ ];
2690
+ }
2691
+ _state.label = 1;
2692
+ case 1:
2693
+ _state.trys.push([
2694
+ 1,
2695
+ 3,
2696
+ ,
2697
+ 4
2698
+ ]);
2699
+ return [
2700
+ 4,
2701
+ fetch(buildTrackingIngestUrl(channel), {
2702
+ method: "POST",
2703
+ headers: {
2704
+ "Content-Type": "application/json",
2705
+ Authorization: "License-Key ".concat(licenseKey)
2706
+ },
2707
+ body: JSON.stringify(body)
2708
+ })
2709
+ ];
2710
+ case 2:
2711
+ response = _state.sent();
2712
+ if (!response.ok) {
2713
+ console.warn("[StormcloudVideoPlayer] Tracking ingest failed (".concat(response.status, ") for ").concat(channel));
2714
+ return [
2715
+ 2,
2716
+ false
2717
+ ];
2718
+ }
2719
+ return [
2720
+ 2,
2721
+ true
2722
+ ];
2723
+ case 3:
2724
+ error = _state.sent();
2725
+ console.warn("[StormcloudVideoPlayer] Tracking ingest error for ".concat(channel, ":"), error);
2726
+ return [
2727
+ 2,
2728
+ false
2729
+ ];
2730
+ case 4:
2731
+ return [
2732
+ 2
2733
+ ];
2734
+ }
2735
+ });
2736
+ })();
2717
2737
  }
2718
2738
  // src/utils/vastEnvironmentSignals.ts
2719
2739
  var AIRY_ANDROID_APP_ID = "com.freeairytv.android";
@@ -3484,7 +3504,7 @@ function getBrowserID(clientInfo) {
3484
3504
  })();
3485
3505
  }
3486
3506
  function canPublish(licenseKey) {
3487
- return Boolean(isMQTTEnabled() && licenseKey);
3507
+ return Boolean(isTrackingIngestEnabled() && licenseKey);
3488
3508
  }
3489
3509
  function buildPlayerMetricEvent() {
3490
3510
  return _async_to_generator(function() {
@@ -3526,21 +3546,6 @@ function buildPlayerMetricEvent() {
3526
3546
  });
3527
3547
  }).apply(this, arguments);
3528
3548
  }
3529
- function publishTracking(licenseKey, channel, body) {
3530
- var debug = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : false;
3531
- ensureMQTTClient();
3532
- var topic = buildPlayerTopic(licenseKey, channel);
3533
- var published = publishMQTT(topic, body);
3534
- if (debug) {
3535
- console.log("[StormcloudVideoPlayer] publishTracking:", JSON.stringify({
3536
- licenseKey: licenseKey,
3537
- channel: channel,
3538
- topic: topic,
3539
- body: body,
3540
- published: published
3541
- }, null, 2));
3542
- }
3543
- }
3544
3549
  function sendInitialTracking(_0) {
3545
3550
  return _async_to_generator(function(licenseKey) {
3546
3551
  var context, metricEvent, error;
@@ -3556,9 +3561,9 @@ function sendInitialTracking(_0) {
3556
3561
  case 1:
3557
3562
  _state.trys.push([
3558
3563
  1,
3559
- 3,
3564
+ 4,
3560
3565
  ,
3561
- 4
3566
+ 5
3562
3567
  ]);
3563
3568
  return [
3564
3569
  4,
@@ -3569,23 +3574,28 @@ function sendInitialTracking(_0) {
3569
3574
  ];
3570
3575
  case 2:
3571
3576
  metricEvent = _state.sent();
3572
- publishTracking(licenseKey, "metrics", {
3573
- events: [
3574
- metricEvent
3575
- ]
3576
- }, !!context.debugAdTiming);
3577
3577
  return [
3578
- 3,
3579
- 4
3578
+ 4,
3579
+ ingestPlayerTracking(licenseKey, "metrics", {
3580
+ events: [
3581
+ metricEvent
3582
+ ]
3583
+ })
3580
3584
  ];
3581
3585
  case 3:
3586
+ _state.sent();
3587
+ return [
3588
+ 3,
3589
+ 5
3590
+ ];
3591
+ case 4:
3582
3592
  error = _state.sent();
3583
3593
  console.error("[StormcloudVideoPlayer] Error sending initial tracking data:", error);
3584
3594
  return [
3585
3595
  3,
3586
- 4
3596
+ 5
3587
3597
  ];
3588
- case 4:
3598
+ case 5:
3589
3599
  return [
3590
3600
  2
3591
3601
  ];
@@ -3683,7 +3693,7 @@ function sendAdLoadedTracking(_0, _1) {
3683
3693
  }
3684
3694
  function sendAdImpressionTracking(_0, _1) {
3685
3695
  return _async_to_generator(function(licenseKey, adImpressionInfo) {
3686
- var context, _adImpressionInfo_adUrl, metricEvent, error;
3696
+ var context, metricEvent, error;
3687
3697
  var _arguments = arguments;
3688
3698
  return _ts_generator(this, function(_state) {
3689
3699
  switch(_state.label){
@@ -3696,9 +3706,9 @@ function sendAdImpressionTracking(_0, _1) {
3696
3706
  case 1:
3697
3707
  _state.trys.push([
3698
3708
  1,
3699
- 3,
3709
+ 5,
3700
3710
  ,
3701
- 4
3711
+ 6
3702
3712
  ]);
3703
3713
  return [
3704
3714
  4,
@@ -3708,30 +3718,43 @@ function sendAdImpressionTracking(_0, _1) {
3708
3718
  ];
3709
3719
  case 2:
3710
3720
  metricEvent = _state.sent();
3711
- publishTracking(licenseKey, "heartbeat", metricEvent, !!context.debugAdTiming);
3712
- publishTracking(licenseKey, "impressions", {
3713
- events: [
3714
- {
3715
- event_id: createUuid(),
3716
- player_id: metricEvent.player_id,
3717
- ad_played_count: 1,
3718
- ad_url: (_adImpressionInfo_adUrl = adImpressionInfo.adUrl) !== null && _adImpressionInfo_adUrl !== void 0 ? _adImpressionInfo_adUrl : adImpressionInfo.adId,
3719
- capture_at: adImpressionInfo.timestamp
3720
- }
3721
- ]
3722
- }, !!context.debugAdTiming);
3723
3721
  return [
3724
- 3,
3725
- 4
3722
+ 4,
3723
+ ingestPlayerTracking(licenseKey, "metrics", {
3724
+ events: [
3725
+ metricEvent
3726
+ ]
3727
+ })
3726
3728
  ];
3727
3729
  case 3:
3730
+ _state.sent();
3731
+ return [
3732
+ 4,
3733
+ ingestPlayerTracking(licenseKey, "impressions", {
3734
+ events: [
3735
+ {
3736
+ player_id: metricEvent.player_id,
3737
+ ad_played_count: 1,
3738
+ ad_url: adImpressionInfo.adUrl,
3739
+ capture_at: adImpressionInfo.timestamp
3740
+ }
3741
+ ]
3742
+ })
3743
+ ];
3744
+ case 4:
3745
+ _state.sent();
3746
+ return [
3747
+ 3,
3748
+ 6
3749
+ ];
3750
+ case 5:
3728
3751
  error = _state.sent();
3729
3752
  console.error("[StormcloudVideoPlayer] Error sending ad impression tracking:", error);
3730
3753
  return [
3731
3754
  3,
3732
- 4
3755
+ 6
3733
3756
  ];
3734
- case 4:
3757
+ case 6:
3735
3758
  return [
3736
3759
  2
3737
3760
  ];
@@ -3754,9 +3777,9 @@ function sendHeartbeat(_0) {
3754
3777
  case 1:
3755
3778
  _state.trys.push([
3756
3779
  1,
3757
- 3,
3780
+ 4,
3758
3781
  ,
3759
- 4
3782
+ 5
3760
3783
  ]);
3761
3784
  return [
3762
3785
  4,
@@ -3764,19 +3787,28 @@ function sendHeartbeat(_0) {
3764
3787
  ];
3765
3788
  case 2:
3766
3789
  heartbeatData = _state.sent();
3767
- publishTracking(licenseKey, "heartbeat", heartbeatData, !!context.debugAdTiming);
3768
3790
  return [
3769
- 3,
3770
- 4
3791
+ 4,
3792
+ ingestPlayerTracking(licenseKey, "metrics", {
3793
+ events: [
3794
+ heartbeatData
3795
+ ]
3796
+ })
3771
3797
  ];
3772
3798
  case 3:
3799
+ _state.sent();
3800
+ return [
3801
+ 3,
3802
+ 5
3803
+ ];
3804
+ case 4:
3773
3805
  error = _state.sent();
3774
3806
  console.error("[StormcloudVideoPlayer] Error sending heartbeat:", error);
3775
3807
  return [
3776
3808
  3,
3777
- 4
3809
+ 5
3778
3810
  ];
3779
- case 4:
3811
+ case 5:
3780
3812
  return [
3781
3813
  2
3782
3814
  ];
@@ -5650,7 +5682,6 @@ var AdConfigManager = /*#__PURE__*/ function() {
5650
5682
  ];
5651
5683
  case 4:
5652
5684
  data = _state.sent();
5653
- this.applyMqttConfigFromResponse(data);
5654
5685
  imaPayload = (_data_response = data.response) === null || _data_response === void 0 ? void 0 : (_data_response_ima = _data_response.ima) === null || _data_response_ima === void 0 ? void 0 : (_data_response_ima_publisherdeskima = _data_response_ima["publisherdesk.ima"]) === null || _data_response_ima_publisherdeskima === void 0 ? void 0 : _data_response_ima_publisherdeskima.payload;
5655
5686
  if (imaPayload) {
5656
5687
  decodedPayload = imaPayload;
@@ -5684,20 +5715,6 @@ var AdConfigManager = /*#__PURE__*/ function() {
5684
5715
  }).call(this);
5685
5716
  }
5686
5717
  },
5687
- {
5688
- key: "applyMqttConfigFromResponse",
5689
- value: function applyMqttConfigFromResponse(data) {
5690
- var _data_response;
5691
- var mqttConfig2 = (_data_response = data.response) === null || _data_response === void 0 ? void 0 : _data_response.mqtt_config;
5692
- if (!mqttConfig2 || (typeof mqttConfig2 === "undefined" ? "undefined" : _type_of(mqttConfig2)) !== "object") {
5693
- return;
5694
- }
5695
- applyMQTTConfig(mqttConfig2);
5696
- if (this.debug) {
5697
- console.log("[StormcloudVideoPlayer] Applied MQTT config from /ads/web:", mqttConfig2);
5698
- }
5699
- }
5700
- },
5701
5718
  {
5702
5719
  key: "fetchAndParseVmap",
5703
5720
  value: function fetchAndParseVmap(vmapUrl) {
@@ -7558,22 +7575,27 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7558
7575
  console.log("[POD] Playing pod ad ".concat((payload === null || payload === void 0 ? void 0 : payload.index) != null ? payload.index + 1 : "?", "/").concat((_ref = payload === null || payload === void 0 ? void 0 : payload.total) !== null && _ref !== void 0 ? _ref : "?"));
7559
7576
  }
7560
7577
  });
7561
- adPlayer.on("ad_impression", function(payload) {
7562
- var impressionInfo = {
7578
+ adPlayer.on("all_ads_completed", function() {
7579
+ sendAdImpressionTracking(_this.host.config.licenseKey, {
7563
7580
  source: "hls",
7564
7581
  adIndex: _this.timing.currentAdIndex,
7565
7582
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
7566
- };
7567
- if (payload === null || payload === void 0 ? void 0 : payload.adId) impressionInfo.adId = payload.adId;
7568
- if (payload === null || payload === void 0 ? void 0 : payload.mediaUrl) impressionInfo.adUrl = payload.mediaUrl;
7569
- if ((payload === null || payload === void 0 ? void 0 : payload.durationSeconds) != null) {
7570
- impressionInfo.durationSeconds = payload.durationSeconds;
7583
+ }, _this.analyticsContext).catch(function() {});
7584
+ _this.timing.recordPlayedAdDuration(_this.host.getAdPlayer());
7585
+ var remaining = _this.timing.getRemainingAdMs();
7586
+ _this.timing.consecutiveFailures = 0;
7587
+ if (_this.debug) {
7588
+ console.log("[StormcloudVideoPlayer] all_ads_completed event received - remaining=".concat(remaining, "ms, queued ads=").concat(_this.adRequestQueue.length), _this.adRequestQueue.length > 0 ? {
7589
+ queuedUrls: _to_consumable_array(_this.adRequestQueue)
7590
+ } : {});
7571
7591
  }
7572
- sendAdImpressionTracking(_this.host.config.licenseKey, impressionInfo, _this.analyticsContext).catch(function(error) {
7573
- if (_this.debug) {
7574
- console.warn("[AdBreakOrchestrator] Failed to send ad impression tracking:", error);
7592
+ if (_this.inAdBreak) {
7593
+ if (_this.timing.hasTimeToStartAnotherAd()) {
7594
+ _this.tryNextAvailableAdWithRateLimit();
7595
+ } else {
7596
+ _this.handleAdPodComplete();
7575
7597
  }
7576
- });
7598
+ }
7577
7599
  });
7578
7600
  adPlayer.on("ad_error", function(errorPayload) {
7579
7601
  var errorMessage = "Ad playback failed";
@@ -7616,6 +7638,11 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7616
7638
  }
7617
7639
  });
7618
7640
  adPlayer.on("content_resume", function() {
7641
+ sendAdImpressionTracking(_this.host.config.licenseKey, {
7642
+ source: "hls",
7643
+ adIndex: _this.timing.currentAdIndex,
7644
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
7645
+ }, _this.analyticsContext).catch(function() {});
7619
7646
  if (!_this.host.video.muted) {
7620
7647
  _this.host.video.muted = true;
7621
7648
  if (_this.debug) {
@@ -12391,47 +12418,37 @@ var StormcloudPlayer = createStormcloudPlayer(players_default, players_default[p
12391
12418
  var StormcloudPlayer_default = StormcloudPlayer;
12392
12419
  // Annotate the CommonJS export names for ESM import in node:
12393
12420
  0 && (module.exports = {
12394
- DEFAULT_MQTT_CONFIG: DEFAULT_MQTT_CONFIG,
12421
+ DEFAULT_TRACKING_INGEST_CONFIG: DEFAULT_TRACKING_INGEST_CONFIG,
12395
12422
  IS_BROWSER: IS_BROWSER,
12396
12423
  IS_GLOBAL: IS_GLOBAL,
12397
12424
  IS_IOS: IS_IOS,
12398
12425
  IS_SAFARI: IS_SAFARI,
12399
- MQTT_CA_CERT_FILE: MQTT_CA_CERT_FILE,
12400
12426
  SUPPORTS_DASH: SUPPORTS_DASH,
12401
12427
  SUPPORTS_HLS: SUPPORTS_HLS,
12402
12428
  StormcloudPlayer: StormcloudPlayer,
12403
12429
  StormcloudVideoPlayer: StormcloudVideoPlayer,
12404
12430
  StormcloudVideoPlayerComponent: StormcloudVideoPlayerComponent,
12405
- applyMQTTConfig: applyMQTTConfig,
12431
+ applyTrackingIngestConfig: applyTrackingIngestConfig,
12406
12432
  buildAnalyticsContext: buildAnalyticsContext,
12407
- buildMQTTBrokerUrl: buildMQTTBrokerUrl,
12408
- buildPlayerTopic: buildPlayerTopic,
12409
12433
  canPlay: canPlay,
12410
- configureMQTT: configureMQTT,
12434
+ configureTrackingIngest: configureTrackingIngest,
12411
12435
  createHlsAdPlayer: createHlsAdPlayer,
12412
12436
  createPalNonceManager: createPalNonceManager,
12413
12437
  createStormcloudPlayer: createStormcloudPlayer,
12414
12438
  detectBrowser: detectBrowser,
12415
- disconnectMQTT: disconnectMQTT,
12416
- ensureMQTTClient: ensureMQTTClient,
12417
12439
  getBrowserConfigOverrides: getBrowserConfigOverrides,
12418
12440
  getBrowserID: getBrowserID,
12419
12441
  getClientInfo: getClientInfo,
12420
- getMQTTStatus: getMQTTStatus,
12421
- initMQTTClient: initMQTTClient,
12442
+ ingestPlayerTracking: ingestPlayerTracking,
12422
12443
  initializePolyfills: initializePolyfills,
12423
- isMQTTConfigured: isMQTTConfigured,
12424
- isMQTTConnected: isMQTTConnected,
12425
- isMQTTEnabled: isMQTTEnabled,
12426
12444
  isMediaStream: isMediaStream,
12445
+ isTrackingIngestEnabled: isTrackingIngestEnabled,
12427
12446
  lazy: lazy,
12428
12447
  logBrowserInfo: logBrowserInfo,
12429
12448
  merge: merge,
12430
- mqttConfig: mqttConfig,
12431
12449
  omit: omit,
12432
12450
  parseQuery: parseQuery,
12433
12451
  players: players,
12434
- publishMQTT: publishMQTT,
12435
12452
  randomString: randomString,
12436
12453
  requiresMediaPipelineResetAfterAds: requiresMediaPipelineResetAfterAds,
12437
12454
  sendAdDetectTracking: sendAdDetectTracking,
@@ -12441,6 +12458,7 @@ var StormcloudPlayer_default = StormcloudPlayer;
12441
12458
  sendInitialTracking: sendInitialTracking,
12442
12459
  supportsFeature: supportsFeature,
12443
12460
  supportsModernJS: supportsModernJS,
12444
- supportsWebKitPresentationMode: supportsWebKitPresentationMode
12461
+ supportsWebKitPresentationMode: supportsWebKitPresentationMode,
12462
+ trackingIngestConfig: trackingIngestConfig
12445
12463
  });
12446
12464
  //# sourceMappingURL=index.cjs.map