stormcloud-video-player 0.8.2 → 0.8.4

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 (36) hide show
  1. package/dist/stormcloud-vp.min.js +3 -1
  2. package/lib/index.cjs +536 -341
  3. package/lib/index.cjs.map +1 -1
  4. package/lib/index.d.cts +37 -2
  5. package/lib/index.d.ts +37 -2
  6. package/lib/index.js +477 -342
  7. package/lib/index.js.map +1 -1
  8. package/lib/player/StormcloudVideoPlayer.cjs +266 -206
  9. package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
  10. package/lib/player/StormcloudVideoPlayer.d.cts +5 -2
  11. package/lib/players/FilePlayer.cjs.map +1 -1
  12. package/lib/players/HlsPlayer.cjs +266 -206
  13. package/lib/players/HlsPlayer.cjs.map +1 -1
  14. package/lib/players/HlsPlayer.d.cts +1 -1
  15. package/lib/players/index.cjs +266 -206
  16. package/lib/players/index.cjs.map +1 -1
  17. package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
  18. package/lib/sdk/hlsAdPlayer.d.cts +1 -1
  19. package/lib/sdk/pal.cjs.map +1 -1
  20. package/lib/{types-DDwAfBLt.d.cts → types-BmF_60m2.d.cts} +2 -0
  21. package/lib/ui/StormcloudVideoPlayer.cjs +450 -341
  22. package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
  23. package/lib/ui/StormcloudVideoPlayer.d.cts +1 -1
  24. package/lib/utils/browserCompat.cjs.map +1 -1
  25. package/lib/utils/mqttClient.cjs +245 -0
  26. package/lib/utils/mqttClient.cjs.map +1 -0
  27. package/lib/utils/mqttClient.d.cts +13 -0
  28. package/lib/utils/mqttConfig.cjs +141 -0
  29. package/lib/utils/mqttConfig.cjs.map +1 -0
  30. package/lib/utils/mqttConfig.d.cts +20 -0
  31. package/lib/utils/polyfills.cjs.map +1 -1
  32. package/lib/utils/tracking.cjs +182 -170
  33. package/lib/utils/tracking.cjs.map +1 -1
  34. package/lib/utils/tracking.d.cts +1 -1
  35. package/package.json +3 -1
  36. package/src/certs/emqxsl-ca.crt +22 -0
package/lib/index.cjs CHANGED
@@ -428,6 +428,9 @@ var __toCommonJS = function __toCommonJS(mod) {
428
428
  // src/index.ts
429
429
  var index_exports = {};
430
430
  __export(index_exports, {
431
+ DEFAULT_MQTT_CONFIG: function DEFAULT_MQTT_CONFIG1() {
432
+ return DEFAULT_MQTT_CONFIG;
433
+ },
431
434
  IS_BROWSER: function IS_BROWSER1() {
432
435
  return IS_BROWSER;
433
436
  },
@@ -440,6 +443,9 @@ __export(index_exports, {
440
443
  IS_SAFARI: function IS_SAFARI1() {
441
444
  return IS_SAFARI;
442
445
  },
446
+ MQTT_CA_CERT_FILE: function MQTT_CA_CERT_FILE1() {
447
+ return MQTT_CA_CERT_FILE;
448
+ },
443
449
  SUPPORTS_DASH: function SUPPORTS_DASH1() {
444
450
  return SUPPORTS_DASH;
445
451
  },
@@ -455,9 +461,21 @@ __export(index_exports, {
455
461
  StormcloudVideoPlayerComponent: function StormcloudVideoPlayerComponent1() {
456
462
  return StormcloudVideoPlayerComponent;
457
463
  },
464
+ applyMQTTConfig: function applyMQTTConfig1() {
465
+ return applyMQTTConfig;
466
+ },
467
+ buildMQTTBrokerUrl: function buildMQTTBrokerUrl1() {
468
+ return buildMQTTBrokerUrl;
469
+ },
470
+ buildPlayerTopic: function buildPlayerTopic1() {
471
+ return buildPlayerTopic;
472
+ },
458
473
  canPlay: function canPlay1() {
459
474
  return canPlay;
460
475
  },
476
+ configureMQTT: function configureMQTT1() {
477
+ return configureMQTT;
478
+ },
461
479
  createHlsAdPlayer: function createHlsAdPlayer1() {
462
480
  return createHlsAdPlayer;
463
481
  },
@@ -473,6 +491,12 @@ __export(index_exports, {
473
491
  detectBrowser: function detectBrowser1() {
474
492
  return detectBrowser;
475
493
  },
494
+ disconnectMQTT: function disconnectMQTT1() {
495
+ return disconnectMQTT;
496
+ },
497
+ ensureMQTTClient: function ensureMQTTClient1() {
498
+ return ensureMQTTClient;
499
+ },
476
500
  getBrowserConfigOverrides: function getBrowserConfigOverrides1() {
477
501
  return getBrowserConfigOverrides;
478
502
  },
@@ -482,9 +506,24 @@ __export(index_exports, {
482
506
  getClientInfo: function getClientInfo1() {
483
507
  return getClientInfo;
484
508
  },
509
+ getMQTTStatus: function getMQTTStatus1() {
510
+ return getMQTTStatus;
511
+ },
512
+ initMQTTClient: function initMQTTClient1() {
513
+ return initMQTTClient;
514
+ },
485
515
  initializePolyfills: function initializePolyfills1() {
486
516
  return initializePolyfills;
487
517
  },
518
+ isMQTTConfigured: function isMQTTConfigured1() {
519
+ return isMQTTConfigured;
520
+ },
521
+ isMQTTConnected: function isMQTTConnected1() {
522
+ return isMQTTConnected;
523
+ },
524
+ isMQTTEnabled: function isMQTTEnabled1() {
525
+ return isMQTTEnabled;
526
+ },
488
527
  isMediaStream: function isMediaStream1() {
489
528
  return isMediaStream;
490
529
  },
@@ -497,6 +536,9 @@ __export(index_exports, {
497
536
  merge: function merge1() {
498
537
  return merge;
499
538
  },
539
+ mqttConfig: function mqttConfig1() {
540
+ return mqttConfig;
541
+ },
500
542
  omit: function omit1() {
501
543
  return omit;
502
544
  },
@@ -506,6 +548,9 @@ __export(index_exports, {
506
548
  players: function players() {
507
549
  return players_default;
508
550
  },
551
+ publishMQTT: function publishMQTT1() {
552
+ return publishMQTT;
553
+ },
509
554
  randomString: function randomString1() {
510
555
  return randomString;
511
556
  },
@@ -1524,6 +1569,123 @@ function createPalNonceManager() {
1524
1569
  }
1525
1570
  };
1526
1571
  }
1572
+ // src/utils/mqttConfig.ts
1573
+ var MQTT_CA_CERT_FILE = "src/certs/emqxsl-ca.crt";
1574
+ var DEFAULT_MQTT_CONFIG = {
1575
+ enabled: true,
1576
+ brokerAddress: "vecbae77.ala.us-east-1.emqxsl.com",
1577
+ brokerPort: 8883,
1578
+ wsPort: 8084,
1579
+ username: "for-sonifi",
1580
+ password: "sonifi-mqtt",
1581
+ topicPrefix: "adstorm/players",
1582
+ qos: 1
1583
+ };
1584
+ var mqttConfig = _object_spread({}, DEFAULT_MQTT_CONFIG);
1585
+ function applyMQTTConfig(overrides) {
1586
+ Object.assign(mqttConfig, overrides);
1587
+ }
1588
+ function isMQTTEnabled() {
1589
+ return mqttConfig.enabled;
1590
+ }
1591
+ function buildMQTTBrokerUrl() {
1592
+ if (mqttConfig.brokerUrl) return mqttConfig.brokerUrl;
1593
+ return "wss://".concat(mqttConfig.brokerAddress, ":").concat(mqttConfig.wsPort, "/mqtt");
1594
+ }
1595
+ function buildPlayerTopic(licenseKey, channel) {
1596
+ return "".concat(mqttConfig.topicPrefix, "/").concat(licenseKey, "/").concat(channel);
1597
+ }
1598
+ // src/utils/mqttClient.ts
1599
+ var import_mqtt = __toESM(require("mqtt"), 1);
1600
+ var LOG = "[StormcloudVideoPlayer][MQTT]";
1601
+ var client = null;
1602
+ var status = "disconnected";
1603
+ function getMQTTStatus() {
1604
+ return status;
1605
+ }
1606
+ function isMQTTConnected() {
1607
+ return status === "connected" && client !== null && client.connected;
1608
+ }
1609
+ function isMQTTConfigured() {
1610
+ return isMQTTEnabled();
1611
+ }
1612
+ function configureMQTT(overrides) {
1613
+ applyMQTTConfig(overrides);
1614
+ disconnectMQTT();
1615
+ }
1616
+ function initMQTTClient() {
1617
+ if (client || !isMQTTEnabled()) return;
1618
+ var url = buildMQTTBrokerUrl();
1619
+ status = "connecting";
1620
+ var clientId = "stormcloud-vp-".concat(Math.random().toString(36).slice(2, 9));
1621
+ try {
1622
+ client = import_mqtt.default.connect(url, {
1623
+ clientId: clientId,
1624
+ username: mqttConfig.username,
1625
+ password: mqttConfig.password,
1626
+ keepalive: 60,
1627
+ clean: true,
1628
+ reconnectPeriod: 5e3,
1629
+ connectTimeout: 1e4,
1630
+ queueQoSZero: false
1631
+ });
1632
+ } catch (err) {
1633
+ status = "error";
1634
+ console.warn("".concat(LOG, " connect() threw:"), err);
1635
+ return;
1636
+ }
1637
+ client.on("connect", function() {
1638
+ status = "connected";
1639
+ console.info("".concat(LOG, " connected to ").concat(url));
1640
+ });
1641
+ client.on("reconnect", function() {
1642
+ status = "connecting";
1643
+ console.info("".concat(LOG, " reconnecting…"));
1644
+ });
1645
+ client.on("offline", function() {
1646
+ status = "disconnected";
1647
+ console.warn("".concat(LOG, " offline"));
1648
+ });
1649
+ client.on("error", function(err) {
1650
+ status = "error";
1651
+ console.warn("".concat(LOG, " error:"), err.message);
1652
+ });
1653
+ client.on("close", function() {
1654
+ if (status === "connected") {
1655
+ status = "disconnected";
1656
+ }
1657
+ });
1658
+ }
1659
+ function ensureMQTTClient() {
1660
+ if (isMQTTEnabled() && !client) {
1661
+ initMQTTClient();
1662
+ }
1663
+ }
1664
+ function publishMQTT(topic, payload) {
1665
+ if (!isMQTTEnabled()) {
1666
+ return false;
1667
+ }
1668
+ ensureMQTTClient();
1669
+ if (!client) {
1670
+ return false;
1671
+ }
1672
+ try {
1673
+ client.publish(topic, JSON.stringify(payload), {
1674
+ qos: mqttConfig.qos
1675
+ });
1676
+ return true;
1677
+ } catch (err) {
1678
+ console.warn("".concat(LOG, " publish failed on ").concat(topic, ":"), err);
1679
+ return false;
1680
+ }
1681
+ }
1682
+ function disconnectMQTT() {
1683
+ if (client) {
1684
+ client.end(true);
1685
+ client = null;
1686
+ status = "disconnected";
1687
+ }
1688
+ }
1527
1689
  // src/utils/tracking.ts
1528
1690
  var cachedBrowserId = null;
1529
1691
  function getClientInfo() {
@@ -1670,7 +1832,7 @@ function getClientInfo() {
1670
1832
  }
1671
1833
  function getBrowserID(clientInfo) {
1672
1834
  return _async_to_generator(function() {
1673
- var fingerprintString, encodedData, utf8, buffer, i, hashBuffer, hashArray, hashHex, error, hash, i1, char, fallbackHash, timestamp, random;
1835
+ var _crypto_subtle, fingerprintString, encodedData, utf8, buffer, i, hashBuffer, hashHex, unused, hash, i1, char, fallbackHash, timestamp, random;
1674
1836
  return _ts_generator(this, function(_state) {
1675
1837
  switch(_state.label){
1676
1838
  case 0:
@@ -1681,7 +1843,7 @@ function getBrowserID(clientInfo) {
1681
1843
  ];
1682
1844
  }
1683
1845
  fingerprintString = JSON.stringify(clientInfo);
1684
- if (!(typeof crypto !== "undefined" && crypto.subtle && crypto.subtle.digest)) return [
1846
+ if (!(typeof crypto !== "undefined" && ((_crypto_subtle = crypto.subtle) === null || _crypto_subtle === void 0 ? void 0 : _crypto_subtle.digest))) return [
1685
1847
  3,
1686
1848
  5
1687
1849
  ];
@@ -1719,8 +1881,7 @@ function getBrowserID(clientInfo) {
1719
1881
  ];
1720
1882
  case 3:
1721
1883
  hashBuffer = _state.sent();
1722
- hashArray = Array.from(new Uint8Array(hashBuffer));
1723
- hashHex = hashArray.map(function(b) {
1884
+ hashHex = Array.from(new Uint8Array(hashBuffer)).map(function(b) {
1724
1885
  return b.toString(16).padStart(2, "0");
1725
1886
  }).join("");
1726
1887
  cachedBrowserId = hashHex;
@@ -1729,8 +1890,8 @@ function getBrowserID(clientInfo) {
1729
1890
  hashHex
1730
1891
  ];
1731
1892
  case 4:
1732
- error = _state.sent();
1733
- console.warn("[StormcloudVideoPlayer] crypto.subtle.digest not supported, using fallback hash");
1893
+ unused = _state.sent();
1894
+ console.warn("[StormcloudVideoPlayer] crypto.subtle not supported, using fallback hash");
1734
1895
  return [
1735
1896
  3,
1736
1897
  5
@@ -1754,177 +1915,91 @@ function getBrowserID(clientInfo) {
1754
1915
  });
1755
1916
  })();
1756
1917
  }
1757
- var PLAYER_TRACKING_BASE_URL = "https://adstorm.co/api-adstorm-dev/adstorm/player-tracking";
1758
- var TRACK_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/metrics/ingest");
1759
- var HEARTBEAT_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/heartbeat");
1760
- var IMPRESSIONS_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/impressions/ingest");
1761
- function buildHeaders(licenseKey) {
1762
- var headers = {
1763
- "Content-Type": "application/json"
1764
- };
1765
- if (licenseKey) {
1766
- headers["Authorization"] = "Bearer ".concat(licenseKey);
1767
- }
1768
- return headers;
1918
+ function canPublish(licenseKey) {
1919
+ return Boolean(isMQTTEnabled() && licenseKey);
1769
1920
  }
1770
- function sendTrackRequest(licenseKey, body) {
1921
+ function buildPlayerMetricEvent() {
1771
1922
  return _async_to_generator(function() {
1772
- var response;
1773
- return _ts_generator(this, function(_state) {
1774
- switch(_state.label){
1775
- case 0:
1776
- return [
1777
- 4,
1778
- fetch(TRACK_URL, {
1779
- method: "POST",
1780
- headers: buildHeaders(licenseKey),
1781
- body: JSON.stringify(body)
1782
- })
1783
- ];
1784
- case 1:
1785
- response = _state.sent();
1786
- if (!response.ok) {
1787
- throw new Error("HTTP error! status: ".concat(response.status));
1788
- }
1789
- return [
1790
- 4,
1791
- response.json()
1792
- ];
1793
- case 2:
1794
- _state.sent();
1795
- return [
1796
- 2
1797
- ];
1798
- }
1799
- });
1800
- })();
1801
- }
1802
- function postJson(url, licenseKey, body) {
1803
- return _async_to_generator(function() {
1804
- var response;
1805
- return _ts_generator(this, function(_state) {
1806
- switch(_state.label){
1807
- case 0:
1808
- return [
1809
- 4,
1810
- fetch(url, {
1811
- method: "POST",
1812
- headers: buildHeaders(licenseKey),
1813
- body: JSON.stringify(body)
1814
- })
1815
- ];
1816
- case 1:
1817
- response = _state.sent();
1818
- if (!response.ok) {
1819
- throw new Error("HTTP error! status: ".concat(response.status));
1820
- }
1821
- return [
1822
- 4,
1823
- response.json()
1824
- ];
1825
- case 2:
1826
- _state.sent();
1827
- return [
1828
- 2
1829
- ];
1830
- }
1831
- });
1832
- })();
1833
- }
1834
- function buildPlayerMetricEvent(_0) {
1835
- return _async_to_generator(function(licenseKey) {
1836
- var context, flags, _flags_captureAt, clientInfo, browserId, captureAt;
1923
+ var context, flags, _flags_captureAt, _flags_adLoaded, _flags_adDetect, clientInfo, playerId, captureAt;
1837
1924
  var _arguments = arguments;
1838
1925
  return _ts_generator(this, function(_state) {
1839
1926
  switch(_state.label){
1840
1927
  case 0:
1841
- context = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {}, flags = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : {};
1928
+ context = _arguments.length > 0 && _arguments[0] !== void 0 ? _arguments[0] : {}, flags = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {};
1842
1929
  clientInfo = getClientInfo();
1843
1930
  return [
1844
1931
  4,
1845
1932
  getBrowserID(clientInfo)
1846
1933
  ];
1847
1934
  case 1:
1848
- browserId = _state.sent();
1935
+ playerId = _state.sent();
1849
1936
  captureAt = (_flags_captureAt = flags.captureAt) !== null && _flags_captureAt !== void 0 ? _flags_captureAt : /* @__PURE__ */ new Date().toISOString();
1850
1937
  return [
1851
1938
  2,
1852
- {
1853
- player_id: browserId,
1854
- browserId: browserId,
1939
+ _object_spread({
1940
+ player_id: playerId,
1855
1941
  device_type: clientInfo.deviceType,
1856
- deviceType: clientInfo.deviceType,
1857
- input_stream_type: context.inputStreamType,
1858
- os: clientInfo.os,
1859
- ad_loaded: flags.adLoaded,
1860
- ad_detect: flags.adDetect,
1861
- license_key: licenseKey,
1862
- capture_at: captureAt,
1863
- timestamp: captureAt
1864
- }
1942
+ os: clientInfo.os.toLowerCase(),
1943
+ ad_loaded: (_flags_adLoaded = flags.adLoaded) !== null && _flags_adLoaded !== void 0 ? _flags_adLoaded : false,
1944
+ ad_detect: (_flags_adDetect = flags.adDetect) !== null && _flags_adDetect !== void 0 ? _flags_adDetect : false,
1945
+ capture_at: captureAt
1946
+ }, context.inputStreamType ? {
1947
+ input_stream_type: context.inputStreamType
1948
+ } : {})
1865
1949
  ];
1866
1950
  }
1867
1951
  });
1868
1952
  }).apply(this, arguments);
1869
1953
  }
1954
+ function publishTracking(licenseKey, channel, body) {
1955
+ ensureMQTTClient();
1956
+ publishMQTT(buildPlayerTopic(licenseKey, channel), body);
1957
+ }
1870
1958
  function sendInitialTracking(_0) {
1871
1959
  return _async_to_generator(function(licenseKey) {
1872
- var context, clientInfo, browserId, trackingData, error;
1960
+ var context, metricEvent, error;
1873
1961
  var _arguments = arguments;
1874
1962
  return _ts_generator(this, function(_state) {
1875
1963
  switch(_state.label){
1876
1964
  case 0:
1877
1965
  context = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {};
1966
+ if (!canPublish(licenseKey)) return [
1967
+ 2
1968
+ ];
1878
1969
  _state.label = 1;
1879
1970
  case 1:
1880
1971
  _state.trys.push([
1881
1972
  1,
1882
- 4,
1973
+ 3,
1883
1974
  ,
1884
- 5
1975
+ 4
1885
1976
  ]);
1886
- clientInfo = getClientInfo();
1887
1977
  return [
1888
1978
  4,
1889
- getBrowserID(clientInfo)
1890
- ];
1891
- case 2:
1892
- browserId = _state.sent();
1893
- trackingData = _object_spread({
1894
- browserId: browserId
1895
- }, clientInfo);
1896
- return [
1897
- 4,
1898
- sendTrackRequest(licenseKey, {
1899
- events: [
1900
- {
1901
- player_id: browserId,
1902
- device_type: clientInfo.deviceType,
1903
- input_stream_type: context.inputStreamType,
1904
- os: clientInfo.os,
1905
- ad_loaded: false,
1906
- ad_detect: false,
1907
- license_key: licenseKey,
1908
- capture_at: /* @__PURE__ */ new Date().toISOString()
1909
- }
1910
- ],
1911
- trackingData: trackingData
1979
+ buildPlayerMetricEvent(context, {
1980
+ adLoaded: false,
1981
+ adDetect: false
1912
1982
  })
1913
1983
  ];
1914
- case 3:
1915
- _state.sent();
1984
+ case 2:
1985
+ metricEvent = _state.sent();
1986
+ publishTracking(licenseKey, "metrics", {
1987
+ events: [
1988
+ metricEvent
1989
+ ]
1990
+ });
1916
1991
  return [
1917
1992
  3,
1918
- 5
1993
+ 4
1919
1994
  ];
1920
- case 4:
1995
+ case 3:
1921
1996
  error = _state.sent();
1922
1997
  console.error("[StormcloudVideoPlayer] Error sending initial tracking data:", error);
1923
1998
  return [
1924
1999
  3,
1925
- 5
2000
+ 4
1926
2001
  ];
1927
- case 5:
2002
+ case 4:
1928
2003
  return [
1929
2004
  2
1930
2005
  ];
@@ -2028,53 +2103,48 @@ function sendAdImpressionTracking(_0, _1) {
2028
2103
  switch(_state.label){
2029
2104
  case 0:
2030
2105
  context = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : {};
2106
+ if (!canPublish(licenseKey)) return [
2107
+ 2
2108
+ ];
2031
2109
  _state.label = 1;
2032
2110
  case 1:
2033
2111
  _state.trys.push([
2034
2112
  1,
2035
- 4,
2113
+ 3,
2036
2114
  ,
2037
- 5
2115
+ 4
2038
2116
  ]);
2039
2117
  return [
2040
2118
  4,
2041
- buildPlayerMetricEvent(licenseKey, context, {
2119
+ buildPlayerMetricEvent(context, {
2042
2120
  captureAt: adImpressionInfo.timestamp
2043
2121
  })
2044
2122
  ];
2045
2123
  case 2:
2046
2124
  metricEvent = _state.sent();
2047
- return [
2048
- 4,
2049
- Promise.all([
2050
- postJson(HEARTBEAT_URL, licenseKey, metricEvent),
2051
- postJson(IMPRESSIONS_URL, licenseKey, {
2052
- events: [
2053
- {
2054
- player_id: metricEvent.player_id,
2055
- ad_played_count: 1,
2056
- ad_url: adImpressionInfo.adUrl,
2057
- license_key: licenseKey,
2058
- capture_at: adImpressionInfo.timestamp
2059
- }
2060
- ]
2061
- })
2062
- ])
2063
- ];
2064
- case 3:
2065
- _state.sent();
2125
+ publishTracking(licenseKey, "heartbeat", metricEvent);
2126
+ publishTracking(licenseKey, "impressions", {
2127
+ events: [
2128
+ {
2129
+ player_id: metricEvent.player_id,
2130
+ ad_played_count: 1,
2131
+ ad_url: adImpressionInfo.adUrl,
2132
+ capture_at: adImpressionInfo.timestamp
2133
+ }
2134
+ ]
2135
+ });
2066
2136
  return [
2067
2137
  3,
2068
- 5
2138
+ 4
2069
2139
  ];
2070
- case 4:
2140
+ case 3:
2071
2141
  error = _state.sent();
2072
2142
  console.error("[StormcloudVideoPlayer] Error sending ad impression tracking:", error);
2073
2143
  return [
2074
2144
  3,
2075
- 5
2145
+ 4
2076
2146
  ];
2077
- case 5:
2147
+ case 4:
2078
2148
  return [
2079
2149
  2
2080
2150
  ];
@@ -2090,38 +2160,36 @@ function sendHeartbeat(_0) {
2090
2160
  switch(_state.label){
2091
2161
  case 0:
2092
2162
  context = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {}, flags = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : {};
2163
+ if (!canPublish(licenseKey)) return [
2164
+ 2
2165
+ ];
2093
2166
  _state.label = 1;
2094
2167
  case 1:
2095
2168
  _state.trys.push([
2096
2169
  1,
2097
- 4,
2170
+ 3,
2098
2171
  ,
2099
- 5
2172
+ 4
2100
2173
  ]);
2101
2174
  return [
2102
2175
  4,
2103
- buildPlayerMetricEvent(licenseKey, context, flags)
2176
+ buildPlayerMetricEvent(context, flags)
2104
2177
  ];
2105
2178
  case 2:
2106
2179
  heartbeatData = _state.sent();
2107
- return [
2108
- 4,
2109
- postJson(HEARTBEAT_URL, licenseKey, heartbeatData)
2110
- ];
2111
- case 3:
2112
- _state.sent();
2180
+ publishTracking(licenseKey, "heartbeat", heartbeatData);
2113
2181
  return [
2114
2182
  3,
2115
- 5
2183
+ 4
2116
2184
  ];
2117
- case 4:
2185
+ case 3:
2118
2186
  error = _state.sent();
2119
2187
  console.error("[StormcloudVideoPlayer] Error sending heartbeat:", error);
2120
2188
  return [
2121
2189
  3,
2122
- 5
2190
+ 4
2123
2191
  ];
2124
- case 5:
2192
+ case 4:
2125
2193
  return [
2126
2194
  2
2127
2195
  ];
@@ -2657,7 +2725,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2657
2725
  key: "load",
2658
2726
  value: function load() {
2659
2727
  return _async_to_generator(function() {
2660
- var _this, _this_config_lowLatencyMode, error, _this_config_lowLatencyMode1, _this_video_play;
2728
+ var _this, _this_config_lowLatencyMode, error, _this_config_isLiveStream, _this_config_lowLatencyMode1, _this_video_play;
2661
2729
  return _ts_generator(this, function(_state) {
2662
2730
  switch(_state.label){
2663
2731
  case 0:
@@ -2708,7 +2776,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2708
2776
  this.nativeHlsMode = true;
2709
2777
  this.videoSrcProtection = this.config.src;
2710
2778
  this.video.src = this.config.src;
2711
- this.isLiveStream = (_this_config_lowLatencyMode1 = this.config.lowLatencyMode) !== null && _this_config_lowLatencyMode1 !== void 0 ? _this_config_lowLatencyMode1 : false;
2779
+ this.isLiveStream = (_this_config_isLiveStream = this.config.isLiveStream) !== null && _this_config_isLiveStream !== void 0 ? _this_config_isLiveStream : (_this_config_lowLatencyMode1 = this.config.lowLatencyMode) !== null && _this_config_lowLatencyMode1 !== void 0 ? _this_config_lowLatencyMode1 : false;
2712
2780
  if (this.config.debugAdTiming) {
2713
2781
  console.log("[StormcloudVideoPlayer] Using native HLS playback - VOD mode:", {
2714
2782
  isLive: this.isLiveStream,
@@ -2759,15 +2827,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2759
2827
  });
2760
2828
  this.hls.on(import_hls2.default.Events.MANIFEST_PARSED, function(_, data) {
2761
2829
  return _async_to_generator(function() {
2762
- var _ref, _this_config_minSegmentsBeforePlay, _this_hls_levels, _this_hls, prerollKey, adBehavior, minSegments, _this_video_play;
2830
+ var _this_config_isLiveStream, _ref, _this_config_minSegmentsBeforePlay, _this_hls_levels, _this_hls, prerollKey, adBehavior, minSegments, _this_video_play;
2763
2831
  return _ts_generator(this, function(_state) {
2764
2832
  switch(_state.label){
2765
2833
  case 0:
2766
- 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) {
2834
+ this.isLiveStream = (_this_config_isLiveStream = this.config.isLiveStream) !== null && _this_config_isLiveStream !== void 0 ? _this_config_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) {
2767
2835
  var _level_details, _level_details1;
2768
2836
  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";
2769
2837
  })) !== null && _ref !== void 0 ? _ref : false;
2770
- if (!this.isLiveStream && this.vmapBreaks.length === 0 && this.apiVastTagUrl) {
2838
+ if (!this.isVmapEnabled() && !this.isLiveStream && this.vmapBreaks.length === 0 && this.apiVastTagUrl) {
2771
2839
  prerollKey = "synthetic-vod-preroll";
2772
2840
  if (!this.consumedVmapBreakIds.has(prerollKey)) {
2773
2841
  this.vmapBreaks = [
@@ -3352,12 +3420,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3352
3420
  _this.palNonce.sendPlaybackStart();
3353
3421
  }
3354
3422
  });
3355
- this.video.addEventListener("ended", function() {
3423
+ this.endedHandler = function() {
3356
3424
  if (_this.palPlaybackStarted) {
3357
3425
  _this.palPlaybackStarted = false;
3358
3426
  _this.palNonce.sendPlaybackEnd();
3359
3427
  }
3360
- });
3428
+ _this.onVideoEnded();
3429
+ };
3430
+ this.video.addEventListener("ended", this.endedHandler);
3361
3431
  this.video.addEventListener("mousedown", function(e) {
3362
3432
  _this.palNonce.sendAdTouch(e);
3363
3433
  });
@@ -4679,6 +4749,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4679
4749
  }
4680
4750
  }
4681
4751
  },
4752
+ {
4753
+ key: "isVmapEnabled",
4754
+ value: function isVmapEnabled() {
4755
+ var _this_config_vmapUrl;
4756
+ return !!(this.config.isVmap && ((_this_config_vmapUrl = this.config.vmapUrl) === null || _this_config_vmapUrl === void 0 ? void 0 : _this_config_vmapUrl.trim()));
4757
+ }
4758
+ },
4682
4759
  {
4683
4760
  key: "fetchAdConfiguration",
4684
4761
  value: function fetchAdConfiguration() {
@@ -4687,7 +4764,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4687
4764
  return _ts_generator(this, function(_state) {
4688
4765
  switch(_state.label){
4689
4766
  case 0:
4690
- if (!this.config.vmapUrl) return [
4767
+ if (!this.isVmapEnabled()) return [
4691
4768
  3,
4692
4769
  2
4693
4770
  ];
@@ -4697,7 +4774,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4697
4774
  ];
4698
4775
  case 1:
4699
4776
  _state.sent();
4700
- _state.label = 2;
4777
+ if (this.config.debugAdTiming) {
4778
+ console.log("[StormcloudVideoPlayer] VMAP mode enabled");
4779
+ }
4780
+ return [
4781
+ 2
4782
+ ];
4701
4783
  case 2:
4702
4784
  vastMode = this.config.vastMode || "default";
4703
4785
  if (this.config.debugAdTiming) {
@@ -4865,7 +4947,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4865
4947
  }
4866
4948
  return [];
4867
4949
  }
4868
- var adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
4950
+ var VMAP_NS = "http://www.iab.net/videosuite/vmap";
4951
+ var adBreakNodes = Array.from(doc.getElementsByTagNameNS(VMAP_NS, "AdBreak"));
4952
+ if (adBreakNodes.length === 0) {
4953
+ adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
4954
+ }
4955
+ if (adBreakNodes.length === 0) {
4956
+ adBreakNodes = Array.from(doc.getElementsByTagName("*")).filter(function(el) {
4957
+ return el.localName === "AdBreak";
4958
+ });
4959
+ }
4869
4960
  var parsed = [];
4870
4961
  adBreakNodes.forEach(function(node, index) {
4871
4962
  var timeOffsetRaw = (node.getAttribute("timeOffset") || "").trim();
@@ -4873,7 +4964,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4873
4964
  if (startTimeMs == null) {
4874
4965
  return;
4875
4966
  }
4876
- var adTagNode = node.querySelector("AdTagURI, vmap\\:AdTagURI");
4967
+ var adTagNode = node.getElementsByTagNameNS(VMAP_NS, "AdTagURI")[0];
4968
+ if (!adTagNode) {
4969
+ var _node_querySelector;
4970
+ adTagNode = (_node_querySelector = node.querySelector("AdTagURI, vmap\\:AdTagURI")) !== null && _node_querySelector !== void 0 ? _node_querySelector : void 0;
4971
+ }
4877
4972
  var adTagUrl = ((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim();
4878
4973
  if (!adTagUrl) {
4879
4974
  return;
@@ -6430,23 +6525,49 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6430
6525
  key: "onTimeUpdate",
6431
6526
  value: function onTimeUpdate(currentTimeSec) {
6432
6527
  var _this = this;
6528
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
6529
+ return;
6530
+ }
6433
6531
  if (this.adPlayer.isAdPlaying() || this.inAdBreak) return;
6434
6532
  var nowMs = currentTimeSec * 1e3;
6435
6533
  var breakToPlay = this.findBreakForTime(nowMs);
6436
6534
  if (breakToPlay) {
6437
- void this.handleMidAdJoin(breakToPlay, nowMs).catch(function(error) {
6535
+ void this.handleVmapAdBreak(breakToPlay, nowMs).catch(function(error) {
6536
+ if (_this.config.debugAdTiming) {
6537
+ console.warn("[StormcloudVideoPlayer] VMAP ad break failed gracefully:", error);
6538
+ }
6539
+ });
6540
+ }
6541
+ }
6542
+ },
6543
+ {
6544
+ key: "onVideoEnded",
6545
+ value: function onVideoEnded() {
6546
+ var _this = this;
6547
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
6548
+ return;
6549
+ }
6550
+ if (this.adPlayer.isAdPlaying() || this.inAdBreak) {
6551
+ return;
6552
+ }
6553
+ var durationMs = Number.isFinite(this.video.duration) ? Math.floor(this.video.duration * 1e3) : 0;
6554
+ var postroll = this.vmapBreaks.find(function(b) {
6555
+ return b.startTimeMs === -1 && !_this.consumedVmapBreakIds.has(_this.getAdBreakKey(b));
6556
+ });
6557
+ if (postroll) {
6558
+ void this.handleVmapAdBreak(postroll, durationMs).catch(function(error) {
6438
6559
  if (_this.config.debugAdTiming) {
6439
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP join failed gracefully:", error);
6560
+ console.warn("[StormcloudVideoPlayer] VMAP post-roll failed gracefully:", error);
6440
6561
  }
6441
6562
  });
6442
6563
  }
6443
6564
  }
6444
6565
  },
6445
6566
  {
6446
- key: "handleMidAdJoin",
6447
- value: function handleMidAdJoin(adBreak, nowMs) {
6567
+ key: "handleVmapAdBreak",
6568
+ value: function handleVmapAdBreak(adBreak, nowMs) {
6448
6569
  return _async_to_generator(function() {
6449
- var _adBreak_durationMs, _this_config_driftToleranceMs, key, breakStartMs, durationMs, endMs, tol, inWindow, remainingMs, tags, first, rest, error;
6570
+ var _adBreak_durationMs, key, breakStartMs, durationMs, endMs, inWindow, tags, first, rest, error;
6450
6571
  return _ts_generator(this, function(_state) {
6451
6572
  switch(_state.label){
6452
6573
  case 0:
@@ -6464,25 +6585,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6464
6585
  }
6465
6586
  durationMs = (_adBreak_durationMs = adBreak.durationMs) !== null && _adBreak_durationMs !== void 0 ? _adBreak_durationMs : 0;
6466
6587
  endMs = breakStartMs + durationMs;
6467
- tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6468
- inWindow = durationMs > 0 ? nowMs > breakStartMs && nowMs < endMs : nowMs + tol >= breakStartMs;
6588
+ inWindow = durationMs > 0 ? nowMs >= breakStartMs && nowMs < endMs : nowMs >= breakStartMs;
6469
6589
  if (!inWindow) return [
6470
6590
  3,
6471
6591
  4
6472
6592
  ];
6473
6593
  this.consumedVmapBreakIds.add(key);
6474
- remainingMs = durationMs > 0 ? Math.max(0, endMs - nowMs) : 0;
6475
- tags = this.selectVastTagsForBreak(adBreak) || (this.apiVastTagUrl ? [
6476
- this.apiVastTagUrl
6477
- ] : void 0);
6478
- if (!(tags && tags.length > 0)) return [
6479
- 3,
6480
- 4
6481
- ];
6594
+ tags = this.selectVastTagsForBreak(adBreak);
6595
+ if (!tags || tags.length === 0) {
6596
+ return [
6597
+ 2
6598
+ ];
6599
+ }
6482
6600
  first = tags[0];
6483
6601
  rest = tags.slice(1);
6484
6602
  this.adPodQueue = rest;
6485
6603
  this.adPlayer.updateOriginalMutedState(this.video.muted, this.video.volume);
6604
+ this.showAds = true;
6605
+ this.inAdBreak = true;
6606
+ this.currentAdBreakStartWallClockMs = Date.now();
6607
+ if (!this.video.paused) {
6608
+ this.video.pause();
6609
+ }
6486
6610
  _state.label = 1;
6487
6611
  case 1:
6488
6612
  _state.trys.push([
@@ -6497,10 +6621,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6497
6621
  ];
6498
6622
  case 2:
6499
6623
  _state.sent();
6500
- this.inAdBreak = true;
6501
- this.expectedAdBreakDurationMs = remainingMs;
6502
- this.currentAdBreakStartWallClockMs = Date.now();
6503
- this.scheduleAdStopCountdown(remainingMs);
6504
6624
  return [
6505
6625
  3,
6506
6626
  4
@@ -6508,8 +6628,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6508
6628
  case 3:
6509
6629
  error = _state.sent();
6510
6630
  this.adPodQueue = [];
6631
+ this.inAdBreak = false;
6632
+ this.showAds = false;
6511
6633
  if (this.config.debugAdTiming) {
6512
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP ad request failed:", error);
6634
+ console.warn("[StormcloudVideoPlayer] VMAP ad request failed:", error);
6513
6635
  }
6514
6636
  return [
6515
6637
  3,
@@ -7221,9 +7343,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7221
7343
  {
7222
7344
  key: "findBreakForTime",
7223
7345
  value: function findBreakForTime(nowMs) {
7224
- var _this_config_driftToleranceMs;
7225
7346
  var schedule = this.vmapBreaks;
7226
- var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
7227
7347
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
7228
7348
  try {
7229
7349
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
@@ -7235,9 +7355,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7235
7355
  if (breakStartMs == null) {
7236
7356
  continue;
7237
7357
  }
7238
- var end = breakStartMs + (b.durationMs || 0);
7239
- var effectiveTol = breakStartMs === 0 ? Math.max(tol, 3e4) : tol;
7240
- if (nowMs >= breakStartMs && (b.durationMs ? nowMs < end : nowMs <= breakStartMs + effectiveTol)) {
7358
+ if (b.durationMs) {
7359
+ var end = breakStartMs + b.durationMs;
7360
+ if (nowMs >= breakStartMs && nowMs < end) {
7361
+ return b;
7362
+ }
7363
+ continue;
7364
+ }
7365
+ if (nowMs >= breakStartMs) {
7241
7366
  return b;
7242
7367
  }
7243
7368
  }
@@ -7445,6 +7570,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7445
7570
  this.video.removeEventListener("timeupdate", this.timeUpdateHandler);
7446
7571
  delete this.timeUpdateHandler;
7447
7572
  }
7573
+ if (this.endedHandler) {
7574
+ this.video.removeEventListener("ended", this.endedHandler);
7575
+ delete this.endedHandler;
7576
+ }
7448
7577
  if (this.emptiedHandler) {
7449
7578
  this.video.removeEventListener("emptied", this.emptiedHandler);
7450
7579
  delete this.emptiedHandler;
@@ -7473,7 +7602,9 @@ var import_jsx_runtime = require("react/jsx-runtime");
7473
7602
  var CRITICAL_PROPS = [
7474
7603
  "src",
7475
7604
  "allowNativeHls",
7605
+ "isLiveStream",
7476
7606
  "licenseKey",
7607
+ "isVmap",
7477
7608
  "vmapUrl",
7478
7609
  "lowLatencyMode",
7479
7610
  "driftToleranceMs",
@@ -7482,12 +7613,13 @@ var CRITICAL_PROPS = [
7482
7613
  var CONTROLS_HIDE_DELAY = 3e3;
7483
7614
  var DEFAULT_PLAYER_ASPECT_RATIO = 16 / 9;
7484
7615
  var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
7485
- var src = props.src, autoplay = props.autoplay, muted = props.muted, lowLatencyMode = props.lowLatencyMode, allowNativeHls = props.allowNativeHls, driftToleranceMs = props.driftToleranceMs, immediateManifestAds = props.immediateManifestAds, debugAdTiming = props.debugAdTiming, showCustomControls = props.showCustomControls, hideLoadingIndicator = props.hideLoadingIndicator, onVolumeToggle = props.onVolumeToggle, onFullscreenToggle = props.onFullscreenToggle, onControlClick = props.onControlClick, onReady = props.onReady, wrapperClassName = props.wrapperClassName, wrapperStyle = props.wrapperStyle, className = props.className, style = props.style, controls = props.controls, playsInline = props.playsInline, preload = props.preload, poster = props.poster, children = props.children, licenseKey = props.licenseKey, vastMode = props.vastMode, vastTagUrl = props.vastTagUrl, vmapUrl = props.vmapUrl, minSegmentsBeforePlay = props.minSegmentsBeforePlay, restVideoAttrs = _object_without_properties(props, [
7616
+ var src = props.src, autoplay = props.autoplay, muted = props.muted, lowLatencyMode = props.lowLatencyMode, allowNativeHls = props.allowNativeHls, isLiveStream = props.isLiveStream, driftToleranceMs = props.driftToleranceMs, immediateManifestAds = props.immediateManifestAds, debugAdTiming = props.debugAdTiming, showCustomControls = props.showCustomControls, hideLoadingIndicator = props.hideLoadingIndicator, onVolumeToggle = props.onVolumeToggle, onFullscreenToggle = props.onFullscreenToggle, onControlClick = props.onControlClick, onReady = props.onReady, wrapperClassName = props.wrapperClassName, wrapperStyle = props.wrapperStyle, className = props.className, style = props.style, controls = props.controls, playsInline = props.playsInline, preload = props.preload, poster = props.poster, children = props.children, licenseKey = props.licenseKey, vastMode = props.vastMode, vastTagUrl = props.vastTagUrl, isVmap = props.isVmap, vmapUrl = props.vmapUrl, minSegmentsBeforePlay = props.minSegmentsBeforePlay, restVideoAttrs = _object_without_properties(props, [
7486
7617
  "src",
7487
7618
  "autoplay",
7488
7619
  "muted",
7489
7620
  "lowLatencyMode",
7490
7621
  "allowNativeHls",
7622
+ "isLiveStream",
7491
7623
  "driftToleranceMs",
7492
7624
  "immediateManifestAds",
7493
7625
  "debugAdTiming",
@@ -7509,6 +7641,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
7509
7641
  "licenseKey",
7510
7642
  "vastMode",
7511
7643
  "vastTagUrl",
7644
+ "isVmap",
7512
7645
  "vmapUrl",
7513
7646
  "minSegmentsBeforePlay"
7514
7647
  ]);
@@ -7641,7 +7774,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
7641
7774
  setShowSpeedMenu(false);
7642
7775
  };
7643
7776
  var isHlsStream = (src === null || src === void 0 ? void 0 : src.toLowerCase().includes(".m3u8")) || (src === null || src === void 0 ? void 0 : src.toLowerCase().includes("/hls/"));
7644
- var shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls : true);
7777
+ var shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls || isLiveStream === false : true);
7645
7778
  var criticalPropsKey = (0, import_react.useMemo)(function() {
7646
7779
  return CRITICAL_PROPS.map(function(prop) {
7647
7780
  return "".concat(prop, ":").concat(props[prop]);
@@ -7649,7 +7782,9 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
7649
7782
  }, [
7650
7783
  src,
7651
7784
  allowNativeHls,
7785
+ isLiveStream,
7652
7786
  licenseKey,
7787
+ isVmap,
7653
7788
  vmapUrl,
7654
7789
  lowLatencyMode,
7655
7790
  driftToleranceMs,
@@ -7683,6 +7818,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
7683
7818
  if (muted !== void 0) cfg.muted = muted;
7684
7819
  if (lowLatencyMode !== void 0) cfg.lowLatencyMode = lowLatencyMode;
7685
7820
  if (allowNativeHls !== void 0) cfg.allowNativeHls = allowNativeHls;
7821
+ if (isLiveStream !== void 0) cfg.isLiveStream = isLiveStream;
7686
7822
  if (driftToleranceMs !== void 0) cfg.driftToleranceMs = driftToleranceMs;
7687
7823
  if (immediateManifestAds !== void 0) cfg.immediateManifestAds = immediateManifestAds;
7688
7824
  if (debugAdTiming !== void 0) cfg.debugAdTiming = debugAdTiming;
@@ -7693,6 +7829,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
7693
7829
  if (licenseKey !== void 0) cfg.licenseKey = licenseKey;
7694
7830
  if (vastMode !== void 0) cfg.vastMode = vastMode;
7695
7831
  if (vastTagUrl !== void 0) cfg.vastTagUrl = vastTagUrl;
7832
+ if (isVmap !== void 0) cfg.isVmap = isVmap;
7696
7833
  if (vmapUrl !== void 0) cfg.vmapUrl = vmapUrl;
7697
7834
  if (minSegmentsBeforePlay !== void 0) cfg.minSegmentsBeforePlay = minSegmentsBeforePlay;
7698
7835
  var player = new StormcloudVideoPlayer(cfg);
@@ -8521,161 +8658,202 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
8521
8658
  ]
8522
8659
  })
8523
8660
  ]
8524
- }) : showCustomControls && !showLicenseWarning && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
8525
- className: "sc-controls-bar",
8526
- style: {
8527
- position: "absolute",
8528
- bottom: "".concat(10 * responsiveScale, "px"),
8529
- right: "".concat(10 * responsiveScale, "px"),
8530
- display: "flex",
8531
- flexDirection: isPortrait ? "column" : "row",
8532
- gap: "".concat(8 * responsiveScale, "px"),
8533
- zIndex: 10,
8534
- opacity: controlsVisible ? 1 : 0,
8535
- transform: controlsVisible ? "translateY(0)" : "translateY(4px)",
8536
- pointerEvents: controlsVisible ? "auto" : "none"
8537
- },
8661
+ }) : showCustomControls && !showLicenseWarning && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, {
8538
8662
  children: [
8539
8663
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
8540
8664
  style: {
8665
+ position: "absolute",
8666
+ top: "".concat(10 * responsiveScale, "px"),
8667
+ left: "".concat(10 * responsiveScale, "px"),
8541
8668
  display: "flex",
8542
8669
  alignItems: "center",
8543
- background: "rgba(0, 0, 0, 0.6)",
8544
- borderRadius: "".concat(18 * responsiveScale, "px"),
8545
- padding: "2px",
8546
- paddingRight: "".concat(8 * responsiveScale, "px")
8547
- },
8548
- onMouseEnter: function onMouseEnter() {
8549
- return setShowVolumeSlider(true);
8670
+ gap: "6px",
8671
+ zIndex: 10,
8672
+ opacity: controlsVisible ? 1 : 0,
8673
+ transition: "opacity 0.35s ease"
8550
8674
  },
8551
- onMouseLeave: function onMouseLeave() {
8552
- return setShowVolumeSlider(false);
8675
+ children: [
8676
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
8677
+ style: {
8678
+ width: "8px",
8679
+ height: "8px",
8680
+ borderRadius: "50%",
8681
+ background: "#ff3b30",
8682
+ animation: "sc-pulse 1.5s ease-in-out infinite",
8683
+ flexShrink: 0
8684
+ }
8685
+ }),
8686
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
8687
+ style: {
8688
+ fontSize: "".concat(12 * responsiveScale, "px"),
8689
+ fontFamily: "'SF Pro Display', 'Segoe UI', Arial, sans-serif",
8690
+ fontWeight: 700,
8691
+ letterSpacing: "0.08em",
8692
+ color: "#fff",
8693
+ textShadow: "0 1px 3px rgba(0,0,0,0.6)",
8694
+ userSelect: "none"
8695
+ },
8696
+ children: "LIVE"
8697
+ })
8698
+ ]
8699
+ }),
8700
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
8701
+ className: "sc-controls-bar",
8702
+ style: {
8703
+ position: "absolute",
8704
+ bottom: "".concat(10 * responsiveScale, "px"),
8705
+ right: "".concat(10 * responsiveScale, "px"),
8706
+ display: "flex",
8707
+ flexDirection: isPortrait ? "column" : "row",
8708
+ gap: "".concat(8 * responsiveScale, "px"),
8709
+ zIndex: 10,
8710
+ opacity: controlsVisible ? 1 : 0,
8711
+ transform: controlsVisible ? "translateY(0)" : "translateY(4px)",
8712
+ pointerEvents: controlsVisible ? "auto" : "none"
8553
8713
  },
8554
8714
  children: [
8715
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
8716
+ style: {
8717
+ display: "flex",
8718
+ alignItems: "center",
8719
+ background: "rgba(0, 0, 0, 0.6)",
8720
+ borderRadius: "".concat(18 * responsiveScale, "px"),
8721
+ padding: "2px",
8722
+ paddingRight: "".concat(8 * responsiveScale, "px")
8723
+ },
8724
+ onMouseEnter: function onMouseEnter() {
8725
+ return setShowVolumeSlider(true);
8726
+ },
8727
+ onMouseLeave: function onMouseLeave() {
8728
+ return setShowVolumeSlider(false);
8729
+ },
8730
+ children: [
8731
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
8732
+ className: "sc-ctrl-btn",
8733
+ onClick: function onClick() {
8734
+ if (playerRef.current) playerRef.current.toggleMute();
8735
+ onVolumeToggle === null || onVolumeToggle === void 0 ? void 0 : onVolumeToggle();
8736
+ resetControlsTimer();
8737
+ },
8738
+ style: {
8739
+ padding: "".concat(8 * responsiveScale, "px"),
8740
+ borderRadius: "50%",
8741
+ minWidth: "".concat(36 * responsiveScale, "px"),
8742
+ minHeight: "".concat(36 * responsiveScale, "px")
8743
+ },
8744
+ title: isMuted ? "Unmute" : "Mute",
8745
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VolumeIcon, {
8746
+ size: Math.max(14, 18 * responsiveScale)
8747
+ })
8748
+ }),
8749
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
8750
+ style: {
8751
+ width: showVolumeSlider ? "".concat(68 * responsiveScale, "px") : "0px",
8752
+ overflow: "hidden",
8753
+ transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
8754
+ display: "flex",
8755
+ alignItems: "center",
8756
+ paddingLeft: showVolumeSlider ? "".concat(3 * responsiveScale, "px") : "0",
8757
+ paddingRight: showVolumeSlider ? "".concat(10 * responsiveScale, "px") : "0"
8758
+ },
8759
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
8760
+ style: {
8761
+ position: "relative",
8762
+ width: "".concat(56 * responsiveScale, "px"),
8763
+ height: "3px",
8764
+ cursor: "pointer",
8765
+ borderRadius: "1.5px"
8766
+ },
8767
+ onMouseDown: function onMouseDown(e) {
8768
+ e.preventDefault();
8769
+ var el = e.currentTarget;
8770
+ var move = function move(ev) {
8771
+ var r2 = el.getBoundingClientRect();
8772
+ handleVolumeChange(Math.max(0, Math.min(1, (ev.clientX - r2.left) / r2.width)));
8773
+ };
8774
+ var up = function up1() {
8775
+ document.removeEventListener("mousemove", move);
8776
+ document.removeEventListener("mouseup", up);
8777
+ };
8778
+ document.addEventListener("mousemove", move);
8779
+ document.addEventListener("mouseup", up);
8780
+ var r = el.getBoundingClientRect();
8781
+ handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
8782
+ },
8783
+ onClick: function onClick(e) {
8784
+ e.stopPropagation();
8785
+ var r = e.currentTarget.getBoundingClientRect();
8786
+ handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
8787
+ },
8788
+ children: [
8789
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
8790
+ style: {
8791
+ position: "absolute",
8792
+ inset: 0,
8793
+ background: "rgba(255, 255, 255, 0.2)",
8794
+ borderRadius: "1.5px"
8795
+ }
8796
+ }),
8797
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
8798
+ style: {
8799
+ position: "absolute",
8800
+ top: 0,
8801
+ left: 0,
8802
+ bottom: 0,
8803
+ width: "".concat((isMuted ? 0 : volume) * 100, "%"),
8804
+ background: "#fff",
8805
+ borderRadius: "1.5px",
8806
+ transition: "width 0.1s ease-out"
8807
+ }
8808
+ }),
8809
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
8810
+ style: {
8811
+ position: "absolute",
8812
+ top: "50%",
8813
+ left: "".concat((isMuted ? 0 : volume) * 100, "%"),
8814
+ transform: "translate(-50%, -50%)",
8815
+ width: "12px",
8816
+ height: "12px",
8817
+ background: "#fff",
8818
+ borderRadius: "50%",
8819
+ boxShadow: "0 0 3px rgba(0, 0, 0, 0.3)",
8820
+ transition: "left 0.1s ease-out"
8821
+ }
8822
+ })
8823
+ ]
8824
+ })
8825
+ })
8826
+ ]
8827
+ }),
8555
8828
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
8556
8829
  className: "sc-ctrl-btn",
8557
8830
  onClick: function onClick() {
8558
- if (playerRef.current) playerRef.current.toggleMute();
8559
- onVolumeToggle === null || onVolumeToggle === void 0 ? void 0 : onVolumeToggle();
8831
+ if (onFullscreenToggle) {
8832
+ onFullscreenToggle();
8833
+ } else if (wrapperRef.current) {
8834
+ if (!document.fullscreenElement) {
8835
+ wrapperRef.current.requestFullscreen().catch(function() {});
8836
+ } else {
8837
+ document.exitFullscreen().catch(function() {});
8838
+ }
8839
+ }
8560
8840
  resetControlsTimer();
8561
8841
  },
8562
8842
  style: {
8563
8843
  padding: "".concat(8 * responsiveScale, "px"),
8564
8844
  borderRadius: "50%",
8565
8845
  minWidth: "".concat(36 * responsiveScale, "px"),
8566
- minHeight: "".concat(36 * responsiveScale, "px")
8846
+ minHeight: "".concat(36 * responsiveScale, "px"),
8847
+ background: "rgba(0, 0, 0, 0.6)"
8567
8848
  },
8568
- title: isMuted ? "Unmute" : "Mute",
8569
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VolumeIcon, {
8849
+ title: isFullscreen ? "Exit Fullscreen" : "Enter Fullscreen",
8850
+ children: isFullscreen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaCompress, {
8851
+ size: Math.max(14, 18 * responsiveScale)
8852
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaExpand, {
8570
8853
  size: Math.max(14, 18 * responsiveScale)
8571
- })
8572
- }),
8573
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
8574
- style: {
8575
- width: showVolumeSlider ? "".concat(68 * responsiveScale, "px") : "0px",
8576
- overflow: "hidden",
8577
- transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
8578
- display: "flex",
8579
- alignItems: "center",
8580
- paddingLeft: showVolumeSlider ? "".concat(3 * responsiveScale, "px") : "0",
8581
- paddingRight: showVolumeSlider ? "".concat(10 * responsiveScale, "px") : "0"
8582
- },
8583
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
8584
- style: {
8585
- position: "relative",
8586
- width: "".concat(56 * responsiveScale, "px"),
8587
- height: "3px",
8588
- cursor: "pointer",
8589
- borderRadius: "1.5px"
8590
- },
8591
- onMouseDown: function onMouseDown(e) {
8592
- e.preventDefault();
8593
- var el = e.currentTarget;
8594
- var move = function move(ev) {
8595
- var r2 = el.getBoundingClientRect();
8596
- handleVolumeChange(Math.max(0, Math.min(1, (ev.clientX - r2.left) / r2.width)));
8597
- };
8598
- var up = function up1() {
8599
- document.removeEventListener("mousemove", move);
8600
- document.removeEventListener("mouseup", up);
8601
- };
8602
- document.addEventListener("mousemove", move);
8603
- document.addEventListener("mouseup", up);
8604
- var r = el.getBoundingClientRect();
8605
- handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
8606
- },
8607
- onClick: function onClick(e) {
8608
- e.stopPropagation();
8609
- var r = e.currentTarget.getBoundingClientRect();
8610
- handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
8611
- },
8612
- children: [
8613
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
8614
- style: {
8615
- position: "absolute",
8616
- inset: 0,
8617
- background: "rgba(255, 255, 255, 0.2)",
8618
- borderRadius: "1.5px"
8619
- }
8620
- }),
8621
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
8622
- style: {
8623
- position: "absolute",
8624
- top: 0,
8625
- left: 0,
8626
- bottom: 0,
8627
- width: "".concat((isMuted ? 0 : volume) * 100, "%"),
8628
- background: "#fff",
8629
- borderRadius: "1.5px",
8630
- transition: "width 0.1s ease-out"
8631
- }
8632
- }),
8633
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
8634
- style: {
8635
- position: "absolute",
8636
- top: "50%",
8637
- left: "".concat((isMuted ? 0 : volume) * 100, "%"),
8638
- transform: "translate(-50%, -50%)",
8639
- width: "12px",
8640
- height: "12px",
8641
- background: "#fff",
8642
- borderRadius: "50%",
8643
- boxShadow: "0 0 3px rgba(0, 0, 0, 0.3)",
8644
- transition: "left 0.1s ease-out"
8645
- }
8646
- })
8647
- ]
8648
8854
  })
8649
8855
  })
8650
8856
  ]
8651
- }),
8652
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
8653
- className: "sc-ctrl-btn",
8654
- onClick: function onClick() {
8655
- if (onFullscreenToggle) {
8656
- onFullscreenToggle();
8657
- } else if (wrapperRef.current) {
8658
- if (!document.fullscreenElement) {
8659
- wrapperRef.current.requestFullscreen().catch(function() {});
8660
- } else {
8661
- document.exitFullscreen().catch(function() {});
8662
- }
8663
- }
8664
- resetControlsTimer();
8665
- },
8666
- style: {
8667
- padding: "".concat(8 * responsiveScale, "px"),
8668
- borderRadius: "50%",
8669
- minWidth: "".concat(36 * responsiveScale, "px"),
8670
- minHeight: "".concat(36 * responsiveScale, "px"),
8671
- background: "rgba(0, 0, 0, 0.6)"
8672
- },
8673
- title: isFullscreen ? "Exit Fullscreen" : "Enter Fullscreen",
8674
- children: isFullscreen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaCompress, {
8675
- size: Math.max(14, 18 * responsiveScale)
8676
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaExpand, {
8677
- size: Math.max(14, 18 * responsiveScale)
8678
- })
8679
8857
  })
8680
8858
  ]
8681
8859
  }),
@@ -8814,6 +8992,7 @@ var defaultProps = {
8814
8992
  showCustomControls: false,
8815
8993
  hideLoadingIndicator: false,
8816
8994
  licenseKey: "",
8995
+ isVmap: false,
8817
8996
  vmapUrl: "",
8818
8997
  adFailsafeTimeoutMs: 1e4,
8819
8998
  minSegmentsBeforePlay: 2,
@@ -9758,6 +9937,7 @@ var SUPPORTED_PROPS = [
9758
9937
  "debugAdTiming",
9759
9938
  "showCustomControls",
9760
9939
  "licenseKey",
9940
+ "isVmap",
9761
9941
  "vmapUrl",
9762
9942
  "adFailsafeTimeoutMs",
9763
9943
  "minSegmentsBeforePlay",
@@ -9947,31 +10127,46 @@ var StormcloudPlayer = createStormcloudPlayer(players_default, players_default[p
9947
10127
  var StormcloudPlayer_default = StormcloudPlayer;
9948
10128
  // Annotate the CommonJS export names for ESM import in node:
9949
10129
  0 && (module.exports = {
10130
+ DEFAULT_MQTT_CONFIG: DEFAULT_MQTT_CONFIG,
9950
10131
  IS_BROWSER: IS_BROWSER,
9951
10132
  IS_GLOBAL: IS_GLOBAL,
9952
10133
  IS_IOS: IS_IOS,
9953
10134
  IS_SAFARI: IS_SAFARI,
10135
+ MQTT_CA_CERT_FILE: MQTT_CA_CERT_FILE,
9954
10136
  SUPPORTS_DASH: SUPPORTS_DASH,
9955
10137
  SUPPORTS_HLS: SUPPORTS_HLS,
9956
10138
  StormcloudPlayer: StormcloudPlayer,
9957
10139
  StormcloudVideoPlayer: StormcloudVideoPlayer,
9958
10140
  StormcloudVideoPlayerComponent: StormcloudVideoPlayerComponent,
10141
+ applyMQTTConfig: applyMQTTConfig,
10142
+ buildMQTTBrokerUrl: buildMQTTBrokerUrl,
10143
+ buildPlayerTopic: buildPlayerTopic,
9959
10144
  canPlay: canPlay,
10145
+ configureMQTT: configureMQTT,
9960
10146
  createHlsAdPlayer: createHlsAdPlayer,
9961
10147
  createPalNonceManager: createPalNonceManager,
9962
10148
  createStormcloudPlayer: createStormcloudPlayer,
9963
10149
  detectBrowser: detectBrowser,
10150
+ disconnectMQTT: disconnectMQTT,
10151
+ ensureMQTTClient: ensureMQTTClient,
9964
10152
  getBrowserConfigOverrides: getBrowserConfigOverrides,
9965
10153
  getBrowserID: getBrowserID,
9966
10154
  getClientInfo: getClientInfo,
10155
+ getMQTTStatus: getMQTTStatus,
10156
+ initMQTTClient: initMQTTClient,
9967
10157
  initializePolyfills: initializePolyfills,
10158
+ isMQTTConfigured: isMQTTConfigured,
10159
+ isMQTTConnected: isMQTTConnected,
10160
+ isMQTTEnabled: isMQTTEnabled,
9968
10161
  isMediaStream: isMediaStream,
9969
10162
  lazy: lazy,
9970
10163
  logBrowserInfo: logBrowserInfo,
9971
10164
  merge: merge,
10165
+ mqttConfig: mqttConfig,
9972
10166
  omit: omit,
9973
10167
  parseQuery: parseQuery,
9974
10168
  players: players,
10169
+ publishMQTT: publishMQTT,
9975
10170
  randomString: randomString,
9976
10171
  sendAdDetectTracking: sendAdDetectTracking,
9977
10172
  sendAdImpressionTracking: sendAdImpressionTracking,