stormcloud-video-player 0.8.3 → 0.8.5

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.
@@ -1421,6 +1421,99 @@ function createPalNonceManager() {
1421
1421
  }
1422
1422
  };
1423
1423
  }
1424
+ // src/utils/mqttConfig.ts
1425
+ var DEFAULT_MQTT_CONFIG = {
1426
+ enabled: true,
1427
+ brokerAddress: "vecbae77.ala.us-east-1.emqxsl.com",
1428
+ brokerPort: 8883,
1429
+ wsPort: 8084,
1430
+ username: "for-sonifi",
1431
+ password: "sonifi-mqtt",
1432
+ topicPrefix: "adstorm/players",
1433
+ qos: 1
1434
+ };
1435
+ var mqttConfig = _object_spread({}, DEFAULT_MQTT_CONFIG);
1436
+ function isMQTTEnabled() {
1437
+ return mqttConfig.enabled;
1438
+ }
1439
+ function buildMQTTBrokerUrl() {
1440
+ if (mqttConfig.brokerUrl) return mqttConfig.brokerUrl;
1441
+ return "wss://".concat(mqttConfig.brokerAddress, ":").concat(mqttConfig.wsPort, "/mqtt");
1442
+ }
1443
+ function buildPlayerTopic(licenseKey, channel) {
1444
+ return "".concat(mqttConfig.topicPrefix, "/").concat(licenseKey, "/").concat(channel);
1445
+ }
1446
+ // src/utils/mqttClient.ts
1447
+ var import_mqtt = __toESM(require("mqtt"), 1);
1448
+ var LOG = "[StormcloudVideoPlayer][MQTT]";
1449
+ var client = null;
1450
+ var status = "disconnected";
1451
+ function initMQTTClient() {
1452
+ if (client || !isMQTTEnabled()) return;
1453
+ var url = buildMQTTBrokerUrl();
1454
+ status = "connecting";
1455
+ var clientId = "stormcloud-vp-".concat(Math.random().toString(36).slice(2, 9));
1456
+ try {
1457
+ client = import_mqtt.default.connect(url, {
1458
+ clientId: clientId,
1459
+ username: mqttConfig.username,
1460
+ password: mqttConfig.password,
1461
+ keepalive: 60,
1462
+ clean: true,
1463
+ reconnectPeriod: 5e3,
1464
+ connectTimeout: 1e4,
1465
+ queueQoSZero: false
1466
+ });
1467
+ } catch (err) {
1468
+ status = "error";
1469
+ console.warn("".concat(LOG, " connect() threw:"), err);
1470
+ return;
1471
+ }
1472
+ client.on("connect", function() {
1473
+ status = "connected";
1474
+ console.info("".concat(LOG, " connected to ").concat(url));
1475
+ });
1476
+ client.on("reconnect", function() {
1477
+ status = "connecting";
1478
+ console.info("".concat(LOG, " reconnecting…"));
1479
+ });
1480
+ client.on("offline", function() {
1481
+ status = "disconnected";
1482
+ console.warn("".concat(LOG, " offline"));
1483
+ });
1484
+ client.on("error", function(err) {
1485
+ status = "error";
1486
+ console.warn("".concat(LOG, " error:"), err.message);
1487
+ });
1488
+ client.on("close", function() {
1489
+ if (status === "connected") {
1490
+ status = "disconnected";
1491
+ }
1492
+ });
1493
+ }
1494
+ function ensureMQTTClient() {
1495
+ if (isMQTTEnabled() && !client) {
1496
+ initMQTTClient();
1497
+ }
1498
+ }
1499
+ function publishMQTT(topic, payload) {
1500
+ if (!isMQTTEnabled()) {
1501
+ return false;
1502
+ }
1503
+ ensureMQTTClient();
1504
+ if (!client) {
1505
+ return false;
1506
+ }
1507
+ try {
1508
+ client.publish(topic, JSON.stringify(payload), {
1509
+ qos: mqttConfig.qos
1510
+ });
1511
+ return true;
1512
+ } catch (err) {
1513
+ console.warn("".concat(LOG, " publish failed on ").concat(topic, ":"), err);
1514
+ return false;
1515
+ }
1516
+ }
1424
1517
  // src/utils/tracking.ts
1425
1518
  var cachedBrowserId = null;
1426
1519
  function getClientInfo() {
@@ -1567,7 +1660,7 @@ function getClientInfo() {
1567
1660
  }
1568
1661
  function getBrowserID(clientInfo) {
1569
1662
  return _async_to_generator(function() {
1570
- var fingerprintString, encodedData, utf8, buffer, i, hashBuffer, hashArray, hashHex, error, hash, i1, char, fallbackHash, timestamp, random;
1663
+ var _crypto_subtle, fingerprintString, encodedData, utf8, buffer, i, hashBuffer, hashHex, unused, hash, i1, char, fallbackHash, timestamp, random;
1571
1664
  return _ts_generator(this, function(_state) {
1572
1665
  switch(_state.label){
1573
1666
  case 0:
@@ -1578,7 +1671,7 @@ function getBrowserID(clientInfo) {
1578
1671
  ];
1579
1672
  }
1580
1673
  fingerprintString = JSON.stringify(clientInfo);
1581
- if (!(typeof crypto !== "undefined" && crypto.subtle && crypto.subtle.digest)) return [
1674
+ if (!(typeof crypto !== "undefined" && ((_crypto_subtle = crypto.subtle) === null || _crypto_subtle === void 0 ? void 0 : _crypto_subtle.digest))) return [
1582
1675
  3,
1583
1676
  5
1584
1677
  ];
@@ -1616,8 +1709,7 @@ function getBrowserID(clientInfo) {
1616
1709
  ];
1617
1710
  case 3:
1618
1711
  hashBuffer = _state.sent();
1619
- hashArray = Array.from(new Uint8Array(hashBuffer));
1620
- hashHex = hashArray.map(function(b) {
1712
+ hashHex = Array.from(new Uint8Array(hashBuffer)).map(function(b) {
1621
1713
  return b.toString(16).padStart(2, "0");
1622
1714
  }).join("");
1623
1715
  cachedBrowserId = hashHex;
@@ -1626,8 +1718,8 @@ function getBrowserID(clientInfo) {
1626
1718
  hashHex
1627
1719
  ];
1628
1720
  case 4:
1629
- error = _state.sent();
1630
- console.warn("[StormcloudVideoPlayer] crypto.subtle.digest not supported, using fallback hash");
1721
+ unused = _state.sent();
1722
+ console.warn("[StormcloudVideoPlayer] crypto.subtle not supported, using fallback hash");
1631
1723
  return [
1632
1724
  3,
1633
1725
  5
@@ -1651,177 +1743,91 @@ function getBrowserID(clientInfo) {
1651
1743
  });
1652
1744
  })();
1653
1745
  }
1654
- var PLAYER_TRACKING_BASE_URL = "https://adstorm.co/api-adstorm-dev/adstorm/player-tracking";
1655
- var TRACK_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/metrics/ingest");
1656
- var HEARTBEAT_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/heartbeat");
1657
- var IMPRESSIONS_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/impressions/ingest");
1658
- function buildHeaders(licenseKey) {
1659
- var headers = {
1660
- "Content-Type": "application/json"
1661
- };
1662
- if (licenseKey) {
1663
- headers["Authorization"] = "Bearer ".concat(licenseKey);
1664
- }
1665
- return headers;
1666
- }
1667
- function sendTrackRequest(licenseKey, body) {
1668
- return _async_to_generator(function() {
1669
- var response;
1670
- return _ts_generator(this, function(_state) {
1671
- switch(_state.label){
1672
- case 0:
1673
- return [
1674
- 4,
1675
- fetch(TRACK_URL, {
1676
- method: "POST",
1677
- headers: buildHeaders(licenseKey),
1678
- body: JSON.stringify(body)
1679
- })
1680
- ];
1681
- case 1:
1682
- response = _state.sent();
1683
- if (!response.ok) {
1684
- throw new Error("HTTP error! status: ".concat(response.status));
1685
- }
1686
- return [
1687
- 4,
1688
- response.json()
1689
- ];
1690
- case 2:
1691
- _state.sent();
1692
- return [
1693
- 2
1694
- ];
1695
- }
1696
- });
1697
- })();
1746
+ function canPublish(licenseKey) {
1747
+ return Boolean(isMQTTEnabled() && licenseKey);
1698
1748
  }
1699
- function postJson(url, licenseKey, body) {
1749
+ function buildPlayerMetricEvent() {
1700
1750
  return _async_to_generator(function() {
1701
- var response;
1702
- return _ts_generator(this, function(_state) {
1703
- switch(_state.label){
1704
- case 0:
1705
- return [
1706
- 4,
1707
- fetch(url, {
1708
- method: "POST",
1709
- headers: buildHeaders(licenseKey),
1710
- body: JSON.stringify(body)
1711
- })
1712
- ];
1713
- case 1:
1714
- response = _state.sent();
1715
- if (!response.ok) {
1716
- throw new Error("HTTP error! status: ".concat(response.status));
1717
- }
1718
- return [
1719
- 4,
1720
- response.json()
1721
- ];
1722
- case 2:
1723
- _state.sent();
1724
- return [
1725
- 2
1726
- ];
1727
- }
1728
- });
1729
- })();
1730
- }
1731
- function buildPlayerMetricEvent(_0) {
1732
- return _async_to_generator(function(licenseKey) {
1733
- var context, flags, _flags_captureAt, clientInfo, browserId, captureAt;
1751
+ var context, flags, _flags_captureAt, _flags_adLoaded, _flags_adDetect, clientInfo, playerId, captureAt;
1734
1752
  var _arguments = arguments;
1735
1753
  return _ts_generator(this, function(_state) {
1736
1754
  switch(_state.label){
1737
1755
  case 0:
1738
- context = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {}, flags = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : {};
1756
+ context = _arguments.length > 0 && _arguments[0] !== void 0 ? _arguments[0] : {}, flags = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {};
1739
1757
  clientInfo = getClientInfo();
1740
1758
  return [
1741
1759
  4,
1742
1760
  getBrowserID(clientInfo)
1743
1761
  ];
1744
1762
  case 1:
1745
- browserId = _state.sent();
1763
+ playerId = _state.sent();
1746
1764
  captureAt = (_flags_captureAt = flags.captureAt) !== null && _flags_captureAt !== void 0 ? _flags_captureAt : /* @__PURE__ */ new Date().toISOString();
1747
1765
  return [
1748
1766
  2,
1749
- {
1750
- player_id: browserId,
1751
- browserId: browserId,
1767
+ _object_spread({
1768
+ player_id: playerId,
1752
1769
  device_type: clientInfo.deviceType,
1753
- deviceType: clientInfo.deviceType,
1754
- input_stream_type: context.inputStreamType,
1755
- os: clientInfo.os,
1756
- ad_loaded: flags.adLoaded,
1757
- ad_detect: flags.adDetect,
1758
- license_key: licenseKey,
1759
- capture_at: captureAt,
1760
- timestamp: captureAt
1761
- }
1770
+ os: clientInfo.os.toLowerCase(),
1771
+ ad_loaded: (_flags_adLoaded = flags.adLoaded) !== null && _flags_adLoaded !== void 0 ? _flags_adLoaded : false,
1772
+ ad_detect: (_flags_adDetect = flags.adDetect) !== null && _flags_adDetect !== void 0 ? _flags_adDetect : false,
1773
+ capture_at: captureAt
1774
+ }, context.inputStreamType ? {
1775
+ input_stream_type: context.inputStreamType
1776
+ } : {})
1762
1777
  ];
1763
1778
  }
1764
1779
  });
1765
1780
  }).apply(this, arguments);
1766
1781
  }
1782
+ function publishTracking(licenseKey, channel, body) {
1783
+ ensureMQTTClient();
1784
+ publishMQTT(buildPlayerTopic(licenseKey, channel), body);
1785
+ }
1767
1786
  function sendInitialTracking(_0) {
1768
1787
  return _async_to_generator(function(licenseKey) {
1769
- var context, clientInfo, browserId, trackingData, error;
1788
+ var context, metricEvent, error;
1770
1789
  var _arguments = arguments;
1771
1790
  return _ts_generator(this, function(_state) {
1772
1791
  switch(_state.label){
1773
1792
  case 0:
1774
1793
  context = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {};
1794
+ if (!canPublish(licenseKey)) return [
1795
+ 2
1796
+ ];
1775
1797
  _state.label = 1;
1776
1798
  case 1:
1777
1799
  _state.trys.push([
1778
1800
  1,
1779
- 4,
1801
+ 3,
1780
1802
  ,
1781
- 5
1803
+ 4
1782
1804
  ]);
1783
- clientInfo = getClientInfo();
1784
- return [
1785
- 4,
1786
- getBrowserID(clientInfo)
1787
- ];
1788
- case 2:
1789
- browserId = _state.sent();
1790
- trackingData = _object_spread({
1791
- browserId: browserId
1792
- }, clientInfo);
1793
1805
  return [
1794
1806
  4,
1795
- sendTrackRequest(licenseKey, {
1796
- events: [
1797
- {
1798
- player_id: browserId,
1799
- device_type: clientInfo.deviceType,
1800
- input_stream_type: context.inputStreamType,
1801
- os: clientInfo.os,
1802
- ad_loaded: false,
1803
- ad_detect: false,
1804
- license_key: licenseKey,
1805
- capture_at: /* @__PURE__ */ new Date().toISOString()
1806
- }
1807
- ],
1808
- trackingData: trackingData
1807
+ buildPlayerMetricEvent(context, {
1808
+ adLoaded: false,
1809
+ adDetect: false
1809
1810
  })
1810
1811
  ];
1811
- case 3:
1812
- _state.sent();
1812
+ case 2:
1813
+ metricEvent = _state.sent();
1814
+ publishTracking(licenseKey, "metrics", {
1815
+ events: [
1816
+ metricEvent
1817
+ ]
1818
+ });
1813
1819
  return [
1814
1820
  3,
1815
- 5
1821
+ 4
1816
1822
  ];
1817
- case 4:
1823
+ case 3:
1818
1824
  error = _state.sent();
1819
1825
  console.error("[StormcloudVideoPlayer] Error sending initial tracking data:", error);
1820
1826
  return [
1821
1827
  3,
1822
- 5
1828
+ 4
1823
1829
  ];
1824
- case 5:
1830
+ case 4:
1825
1831
  return [
1826
1832
  2
1827
1833
  ];
@@ -1925,53 +1931,48 @@ function sendAdImpressionTracking(_0, _1) {
1925
1931
  switch(_state.label){
1926
1932
  case 0:
1927
1933
  context = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : {};
1934
+ if (!canPublish(licenseKey)) return [
1935
+ 2
1936
+ ];
1928
1937
  _state.label = 1;
1929
1938
  case 1:
1930
1939
  _state.trys.push([
1931
1940
  1,
1932
- 4,
1941
+ 3,
1933
1942
  ,
1934
- 5
1943
+ 4
1935
1944
  ]);
1936
1945
  return [
1937
1946
  4,
1938
- buildPlayerMetricEvent(licenseKey, context, {
1947
+ buildPlayerMetricEvent(context, {
1939
1948
  captureAt: adImpressionInfo.timestamp
1940
1949
  })
1941
1950
  ];
1942
1951
  case 2:
1943
1952
  metricEvent = _state.sent();
1944
- return [
1945
- 4,
1946
- Promise.all([
1947
- postJson(HEARTBEAT_URL, licenseKey, metricEvent),
1948
- postJson(IMPRESSIONS_URL, licenseKey, {
1949
- events: [
1950
- {
1951
- player_id: metricEvent.player_id,
1952
- ad_played_count: 1,
1953
- ad_url: adImpressionInfo.adUrl,
1954
- license_key: licenseKey,
1955
- capture_at: adImpressionInfo.timestamp
1956
- }
1957
- ]
1958
- })
1959
- ])
1960
- ];
1961
- case 3:
1962
- _state.sent();
1953
+ publishTracking(licenseKey, "heartbeat", metricEvent);
1954
+ publishTracking(licenseKey, "impressions", {
1955
+ events: [
1956
+ {
1957
+ player_id: metricEvent.player_id,
1958
+ ad_played_count: 1,
1959
+ ad_url: adImpressionInfo.adUrl,
1960
+ capture_at: adImpressionInfo.timestamp
1961
+ }
1962
+ ]
1963
+ });
1963
1964
  return [
1964
1965
  3,
1965
- 5
1966
+ 4
1966
1967
  ];
1967
- case 4:
1968
+ case 3:
1968
1969
  error = _state.sent();
1969
1970
  console.error("[StormcloudVideoPlayer] Error sending ad impression tracking:", error);
1970
1971
  return [
1971
1972
  3,
1972
- 5
1973
+ 4
1973
1974
  ];
1974
- case 5:
1975
+ case 4:
1975
1976
  return [
1976
1977
  2
1977
1978
  ];
@@ -1987,38 +1988,36 @@ function sendHeartbeat(_0) {
1987
1988
  switch(_state.label){
1988
1989
  case 0:
1989
1990
  context = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {}, flags = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : {};
1991
+ if (!canPublish(licenseKey)) return [
1992
+ 2
1993
+ ];
1990
1994
  _state.label = 1;
1991
1995
  case 1:
1992
1996
  _state.trys.push([
1993
1997
  1,
1994
- 4,
1998
+ 3,
1995
1999
  ,
1996
- 5
2000
+ 4
1997
2001
  ]);
1998
2002
  return [
1999
2003
  4,
2000
- buildPlayerMetricEvent(licenseKey, context, flags)
2004
+ buildPlayerMetricEvent(context, flags)
2001
2005
  ];
2002
2006
  case 2:
2003
2007
  heartbeatData = _state.sent();
2004
- return [
2005
- 4,
2006
- postJson(HEARTBEAT_URL, licenseKey, heartbeatData)
2007
- ];
2008
- case 3:
2009
- _state.sent();
2008
+ publishTracking(licenseKey, "heartbeat", heartbeatData);
2010
2009
  return [
2011
2010
  3,
2012
- 5
2011
+ 4
2013
2012
  ];
2014
- case 4:
2013
+ case 3:
2015
2014
  error = _state.sent();
2016
2015
  console.error("[StormcloudVideoPlayer] Error sending heartbeat:", error);
2017
2016
  return [
2018
2017
  3,
2019
- 5
2018
+ 4
2020
2019
  ];
2021
- case 5:
2020
+ case 4:
2022
2021
  return [
2023
2022
  2
2024
2023
  ];
@@ -2277,6 +2276,166 @@ function initializePolyfills() {
2277
2276
  polyfillTextEncoder();
2278
2277
  polyfillPromiseFinally();
2279
2278
  }
2279
+ // src/utils/vastMacros.ts
2280
+ function generateCorrelator() {
2281
+ if (typeof crypto !== "undefined" && crypto.getRandomValues) {
2282
+ try {
2283
+ var _buf_, _buf_1;
2284
+ var buf = new Uint32Array(2);
2285
+ crypto.getRandomValues(buf);
2286
+ var value = ((_buf_ = buf[0]) !== null && _buf_ !== void 0 ? _buf_ : 0) * 2097152 + (((_buf_1 = buf[1]) !== null && _buf_1 !== void 0 ? _buf_1 : 0) & 2097151);
2287
+ if (value > 0) {
2288
+ return String(value);
2289
+ }
2290
+ } catch (unused) {}
2291
+ }
2292
+ return String(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER) + 1);
2293
+ }
2294
+ var UNEXPANDED_MACRO_PATTERN = /^(\[[^\]]*\]|\{[^}]*\}|%%[^%]*%%)$/;
2295
+ function applyVastMacros(baseUrl, ctx) {
2296
+ var url;
2297
+ try {
2298
+ url = new URL(baseUrl);
2299
+ } catch (unused) {
2300
+ return replaceCorrelatorFallback(baseUrl, ctx.correlator);
2301
+ }
2302
+ var params = url.searchParams;
2303
+ params.set("correlator", ctx.correlator);
2304
+ params.set("scor", ctx.streamCorrelator);
2305
+ if (ctx.pod != null) {
2306
+ params.set("pod", String(ctx.pod));
2307
+ }
2308
+ if (ctx.adPosition != null) {
2309
+ params.set("ppos", String(ctx.adPosition));
2310
+ }
2311
+ if (ctx.pageUrl) {
2312
+ params.set("url", ctx.pageUrl);
2313
+ params.set("description_url", ctx.pageUrl);
2314
+ }
2315
+ if (ctx.adWillPlayMuted != null) {
2316
+ params.set("vpmute", ctx.adWillPlayMuted ? "1" : "0");
2317
+ }
2318
+ if (ctx.adWillAutoPlay != null) {
2319
+ params.set("vpa", ctx.adWillAutoPlay ? "auto" : "click");
2320
+ }
2321
+ if (ctx.deviceId && ctx.deviceIdType) {
2322
+ params.set("rdid", ctx.deviceId);
2323
+ params.set("idtype", ctx.deviceIdType);
2324
+ params.set("is_lat", ctx.limitAdTracking ? "1" : "0");
2325
+ } else {
2326
+ params.delete("rdid");
2327
+ params.delete("idtype");
2328
+ params.delete("is_lat");
2329
+ }
2330
+ var consent = ctx.consent;
2331
+ if ((consent === null || consent === void 0 ? void 0 : consent.gdpr) != null) {
2332
+ params.set("gdpr", consent.gdpr);
2333
+ }
2334
+ if ((consent === null || consent === void 0 ? void 0 : consent.gdprConsent) != null) {
2335
+ params.set("gdpr_consent", consent.gdprConsent);
2336
+ }
2337
+ if ((consent === null || consent === void 0 ? void 0 : consent.usPrivacy) != null) {
2338
+ params.set("us_privacy", consent.usPrivacy);
2339
+ }
2340
+ if (ctx.adTest) {
2341
+ params.set("adtest", "on");
2342
+ }
2343
+ var staleKeys = [];
2344
+ params.forEach(function(value, key) {
2345
+ if (UNEXPANDED_MACRO_PATTERN.test(value)) {
2346
+ staleKeys.push(key);
2347
+ }
2348
+ });
2349
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2350
+ try {
2351
+ for(var _iterator = staleKeys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2352
+ var key = _step.value;
2353
+ params.delete(key);
2354
+ }
2355
+ } catch (err) {
2356
+ _didIteratorError = true;
2357
+ _iteratorError = err;
2358
+ } finally{
2359
+ try {
2360
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2361
+ _iterator.return();
2362
+ }
2363
+ } finally{
2364
+ if (_didIteratorError) {
2365
+ throw _iteratorError;
2366
+ }
2367
+ }
2368
+ }
2369
+ return url.toString();
2370
+ }
2371
+ function replaceCorrelatorFallback(baseUrl, correlator) {
2372
+ var correlatorRegex = /([?&])correlator=([^&]*)/;
2373
+ if (correlatorRegex.test(baseUrl)) {
2374
+ return baseUrl.replace(correlatorRegex, "$1correlator=".concat(correlator));
2375
+ }
2376
+ var sep = baseUrl.includes("?") ? "&" : "?";
2377
+ return "".concat(baseUrl).concat(sep, "correlator=").concat(correlator);
2378
+ }
2379
+ function fetchConsentSignals() {
2380
+ var timeoutMs = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : 1500;
2381
+ var signals = {};
2382
+ if (typeof window === "undefined") {
2383
+ return Promise.resolve(signals);
2384
+ }
2385
+ var tasks = [];
2386
+ var tcfApi = window.__tcfapi;
2387
+ if (typeof tcfApi === "function") {
2388
+ tasks.push(new Promise(function(resolve) {
2389
+ var settled = false;
2390
+ try {
2391
+ tcfApi("addEventListener", 2, function(tcData, success) {
2392
+ if (settled) return;
2393
+ if (success && tcData && (tcData.eventStatus === "tcloaded" || tcData.eventStatus === "useractioncomplete")) {
2394
+ settled = true;
2395
+ signals.gdpr = tcData.gdprApplies ? "1" : "0";
2396
+ if (typeof tcData.tcString === "string" && tcData.tcString) {
2397
+ signals.gdprConsent = tcData.tcString;
2398
+ }
2399
+ try {
2400
+ tcfApi("removeEventListener", 2, function() {}, tcData.listenerId);
2401
+ } catch (unused) {}
2402
+ resolve();
2403
+ }
2404
+ });
2405
+ } catch (unused) {
2406
+ resolve();
2407
+ }
2408
+ setTimeout(function() {
2409
+ if (!settled) {
2410
+ settled = true;
2411
+ resolve();
2412
+ }
2413
+ }, timeoutMs);
2414
+ }));
2415
+ }
2416
+ var uspApi = window.__uspapi;
2417
+ if (typeof uspApi === "function") {
2418
+ tasks.push(new Promise(function(resolve) {
2419
+ try {
2420
+ uspApi("getUSPData", 1, function(data, success) {
2421
+ if (success && typeof (data === null || data === void 0 ? void 0 : data.uspString) === "string" && data.uspString) {
2422
+ signals.usPrivacy = data.uspString;
2423
+ }
2424
+ resolve();
2425
+ });
2426
+ } catch (unused) {
2427
+ resolve();
2428
+ }
2429
+ setTimeout(resolve, timeoutMs);
2430
+ }));
2431
+ }
2432
+ if (tasks.length === 0) {
2433
+ return Promise.resolve(signals);
2434
+ }
2435
+ return Promise.all(tasks).then(function() {
2436
+ return signals;
2437
+ });
2438
+ }
2280
2439
  // src/utils/browserCompat.ts
2281
2440
  function getChromeVersion(ua) {
2282
2441
  var match = ua.match(/Chrome\/(\d+)/);
@@ -2502,6 +2661,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2502
2661
  this.preloadPoolLoopRunning = false;
2503
2662
  this.adDetectSentForCurrentBreak = false;
2504
2663
  this.palPlaybackStarted = false;
2664
+ this.streamCorrelator = generateCorrelator();
2665
+ this.consentSignals = {};
2666
+ this.podCounter = 0;
2667
+ this.podAssignedByPrefetch = false;
2668
+ this.adRequestPositionInBreak = 0;
2505
2669
  this.continuousFetchLoopRunning = false;
2506
2670
  initializePolyfills();
2507
2671
  var browserOverrides = getBrowserConfigOverrides();
@@ -2574,6 +2738,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2574
2738
  adWillPlayMuted: !!this.config.muted,
2575
2739
  continuousPlayback: (_this_config_lowLatencyMode = this.config.lowLatencyMode) !== null && _this_config_lowLatencyMode !== void 0 ? _this_config_lowLatencyMode : false
2576
2740
  }).catch(function() {});
2741
+ fetchConsentSignals().then(function(signals) {
2742
+ _this.consentSignals = signals;
2743
+ }).catch(function() {});
2577
2744
  this.initializeTracking();
2578
2745
  if (!this.shouldUseNativeHls()) return [
2579
2746
  3,
@@ -2641,7 +2808,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2641
2808
  var _level_details, _level_details1;
2642
2809
  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";
2643
2810
  })) !== null && _ref !== void 0 ? _ref : false;
2644
- if (!this.isLiveStream && this.vmapBreaks.length === 0 && this.apiVastTagUrl) {
2811
+ if (!this.isVmapEnabled() && !this.isLiveStream && this.vmapBreaks.length === 0 && this.apiVastTagUrl) {
2645
2812
  prerollKey = "synthetic-vod-preroll";
2646
2813
  if (!this.consumedVmapBreakIds.has(prerollKey)) {
2647
2814
  this.vmapBreaks = [
@@ -3226,12 +3393,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3226
3393
  _this.palNonce.sendPlaybackStart();
3227
3394
  }
3228
3395
  });
3229
- this.video.addEventListener("ended", function() {
3396
+ this.endedHandler = function() {
3230
3397
  if (_this.palPlaybackStarted) {
3231
3398
  _this.palPlaybackStarted = false;
3232
3399
  _this.palNonce.sendPlaybackEnd();
3233
3400
  }
3234
- });
3401
+ _this.onVideoEnded();
3402
+ };
3403
+ this.video.addEventListener("ended", this.endedHandler);
3235
3404
  this.video.addEventListener("mousedown", function(e) {
3236
3405
  _this.palNonce.sendAdTouch(e);
3237
3406
  });
@@ -4553,6 +4722,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4553
4722
  }
4554
4723
  }
4555
4724
  },
4725
+ {
4726
+ key: "isVmapEnabled",
4727
+ value: function isVmapEnabled() {
4728
+ var _this_config_vmapUrl;
4729
+ return !!(this.config.isVmap && ((_this_config_vmapUrl = this.config.vmapUrl) === null || _this_config_vmapUrl === void 0 ? void 0 : _this_config_vmapUrl.trim()));
4730
+ }
4731
+ },
4556
4732
  {
4557
4733
  key: "fetchAdConfiguration",
4558
4734
  value: function fetchAdConfiguration() {
@@ -4561,7 +4737,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4561
4737
  return _ts_generator(this, function(_state) {
4562
4738
  switch(_state.label){
4563
4739
  case 0:
4564
- if (!this.config.vmapUrl) return [
4740
+ if (!this.isVmapEnabled()) return [
4565
4741
  3,
4566
4742
  2
4567
4743
  ];
@@ -4571,7 +4747,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4571
4747
  ];
4572
4748
  case 1:
4573
4749
  _state.sent();
4574
- _state.label = 2;
4750
+ if (this.config.debugAdTiming) {
4751
+ console.log("[StormcloudVideoPlayer] VMAP mode enabled");
4752
+ }
4753
+ return [
4754
+ 2
4755
+ ];
4575
4756
  case 2:
4576
4757
  vastMode = this.config.vastMode || "default";
4577
4758
  if (this.config.debugAdTiming) {
@@ -4739,7 +4920,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4739
4920
  }
4740
4921
  return [];
4741
4922
  }
4742
- var adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
4923
+ var VMAP_NS = "http://www.iab.net/videosuite/vmap";
4924
+ var adBreakNodes = Array.from(doc.getElementsByTagNameNS(VMAP_NS, "AdBreak"));
4925
+ if (adBreakNodes.length === 0) {
4926
+ adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
4927
+ }
4928
+ if (adBreakNodes.length === 0) {
4929
+ adBreakNodes = Array.from(doc.getElementsByTagName("*")).filter(function(el) {
4930
+ return el.localName === "AdBreak";
4931
+ });
4932
+ }
4743
4933
  var parsed = [];
4744
4934
  adBreakNodes.forEach(function(node, index) {
4745
4935
  var timeOffsetRaw = (node.getAttribute("timeOffset") || "").trim();
@@ -4747,7 +4937,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4747
4937
  if (startTimeMs == null) {
4748
4938
  return;
4749
4939
  }
4750
- var adTagNode = node.querySelector("AdTagURI, vmap\\:AdTagURI");
4940
+ var adTagNode = node.getElementsByTagNameNS(VMAP_NS, "AdTagURI")[0];
4941
+ if (!adTagNode) {
4942
+ var _node_querySelector;
4943
+ adTagNode = (_node_querySelector = node.querySelector("AdTagURI, vmap\\:AdTagURI")) !== null && _node_querySelector !== void 0 ? _node_querySelector : void 0;
4944
+ }
4751
4945
  var adTagUrl = ((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim();
4752
4946
  if (!adTagUrl) {
4753
4947
  return;
@@ -4843,25 +5037,35 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4843
5037
  return this.getRemainingAdMs();
4844
5038
  }
4845
5039
  },
5040
+ {
5041
+ key: "beginNewAdPod",
5042
+ value: function beginNewAdPod() {
5043
+ this.podCounter++;
5044
+ this.adRequestPositionInBreak = 0;
5045
+ }
5046
+ },
4846
5047
  {
4847
5048
  key: "generateVastUrlsWithCorrelators",
4848
5049
  value: function generateVastUrlsWithCorrelators(baseUrl, count) {
4849
5050
  var urls = [];
4850
- var baseTimestamp = Date.now();
4851
5051
  for(var i = 0; i < count; i++){
4852
- var timestamp = baseTimestamp + i;
4853
- var random = Math.floor(Math.random() * 1e12);
4854
- var uniqueCorrelator = "".concat(timestamp, "_").concat(random, "_").concat(i);
4855
- var urlWithCorrelator = void 0;
4856
- var correlatorRegex = /([?&])correlator=([^&]*)/;
4857
- if (correlatorRegex.test(baseUrl)) {
4858
- urlWithCorrelator = baseUrl.replace(correlatorRegex, "$1correlator=".concat(uniqueCorrelator));
4859
- } else if (baseUrl.includes("?")) {
4860
- urlWithCorrelator = "".concat(baseUrl, "&correlator=").concat(uniqueCorrelator);
4861
- } else {
4862
- urlWithCorrelator = "".concat(baseUrl, "?correlator=").concat(uniqueCorrelator);
4863
- }
4864
- urls.push(this.palNonce.injectNonce(urlWithCorrelator));
5052
+ this.adRequestPositionInBreak++;
5053
+ var adWillPlayMuted = this.inAdBreak ? this.adPlayer.getOriginalMutedState() : this.video.muted;
5054
+ var urlWithMacros = applyVastMacros(baseUrl, {
5055
+ correlator: generateCorrelator(),
5056
+ streamCorrelator: this.streamCorrelator,
5057
+ pod: this.podCounter > 0 ? this.podCounter : void 0,
5058
+ adPosition: this.adRequestPositionInBreak,
5059
+ pageUrl: typeof window !== "undefined" ? window.location.href : void 0,
5060
+ adWillPlayMuted: adWillPlayMuted,
5061
+ adWillAutoPlay: !!this.config.autoplay,
5062
+ deviceId: this.config.deviceId,
5063
+ deviceIdType: this.config.deviceIdType,
5064
+ limitAdTracking: this.config.limitAdTracking,
5065
+ adTest: this.config.adTest,
5066
+ consent: this.consentSignals
5067
+ });
5068
+ urls.push(this.palNonce.injectNonce(urlWithMacros));
4865
5069
  }
4866
5070
  return urls;
4867
5071
  }
@@ -4931,6 +5135,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4931
5135
  }
4932
5136
  return;
4933
5137
  }
5138
+ this.beginNewAdPod();
5139
+ this.podAssignedByPrefetch = true;
4934
5140
  var urlsToPregenerate = 5;
4935
5141
  var generatedUrls = this.generateVastUrlsWithCorrelators(baseVastUrl, urlsToPregenerate);
4936
5142
  this.pendingAdBreak = _object_spread_props(_object_spread({
@@ -4968,6 +5174,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4968
5174
  }
4969
5175
  this.pendingAdBreak = null;
4970
5176
  this.pendingScte35CueKey = void 0;
5177
+ this.podAssignedByPrefetch = false;
4971
5178
  }
4972
5179
  },
4973
5180
  {
@@ -5404,6 +5611,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5404
5611
  this.continuousFetchingActive = true;
5405
5612
  this.isShowingPlaceholder = false;
5406
5613
  this.totalAdRequestsInBreak = 0;
5614
+ if (this.podAssignedByPrefetch) {
5615
+ this.podAssignedByPrefetch = false;
5616
+ } else {
5617
+ this.beginNewAdPod();
5618
+ }
5407
5619
  currentMuted = this.video.muted;
5408
5620
  currentVolume = this.video.volume;
5409
5621
  this.adPlayer.updateOriginalMutedState(currentMuted, currentVolume);
@@ -6304,23 +6516,49 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6304
6516
  key: "onTimeUpdate",
6305
6517
  value: function onTimeUpdate(currentTimeSec) {
6306
6518
  var _this = this;
6519
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
6520
+ return;
6521
+ }
6307
6522
  if (this.adPlayer.isAdPlaying() || this.inAdBreak) return;
6308
6523
  var nowMs = currentTimeSec * 1e3;
6309
6524
  var breakToPlay = this.findBreakForTime(nowMs);
6310
6525
  if (breakToPlay) {
6311
- void this.handleMidAdJoin(breakToPlay, nowMs).catch(function(error) {
6526
+ void this.handleVmapAdBreak(breakToPlay, nowMs).catch(function(error) {
6312
6527
  if (_this.config.debugAdTiming) {
6313
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP join failed gracefully:", error);
6528
+ console.warn("[StormcloudVideoPlayer] VMAP ad break failed gracefully:", error);
6314
6529
  }
6315
6530
  });
6316
6531
  }
6317
6532
  }
6318
6533
  },
6319
6534
  {
6320
- key: "handleMidAdJoin",
6321
- value: function handleMidAdJoin(adBreak, nowMs) {
6535
+ key: "onVideoEnded",
6536
+ value: function onVideoEnded() {
6537
+ var _this = this;
6538
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
6539
+ return;
6540
+ }
6541
+ if (this.adPlayer.isAdPlaying() || this.inAdBreak) {
6542
+ return;
6543
+ }
6544
+ var durationMs = Number.isFinite(this.video.duration) ? Math.floor(this.video.duration * 1e3) : 0;
6545
+ var postroll = this.vmapBreaks.find(function(b) {
6546
+ return b.startTimeMs === -1 && !_this.consumedVmapBreakIds.has(_this.getAdBreakKey(b));
6547
+ });
6548
+ if (postroll) {
6549
+ void this.handleVmapAdBreak(postroll, durationMs).catch(function(error) {
6550
+ if (_this.config.debugAdTiming) {
6551
+ console.warn("[StormcloudVideoPlayer] VMAP post-roll failed gracefully:", error);
6552
+ }
6553
+ });
6554
+ }
6555
+ }
6556
+ },
6557
+ {
6558
+ key: "handleVmapAdBreak",
6559
+ value: function handleVmapAdBreak(adBreak, nowMs) {
6322
6560
  return _async_to_generator(function() {
6323
- var _adBreak_durationMs, _this_config_driftToleranceMs, key, breakStartMs, durationMs, endMs, tol, inWindow, remainingMs, tags, first, rest, error;
6561
+ var _adBreak_durationMs, key, breakStartMs, durationMs, endMs, inWindow, tags, first, rest, error;
6324
6562
  return _ts_generator(this, function(_state) {
6325
6563
  switch(_state.label){
6326
6564
  case 0:
@@ -6338,25 +6576,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6338
6576
  }
6339
6577
  durationMs = (_adBreak_durationMs = adBreak.durationMs) !== null && _adBreak_durationMs !== void 0 ? _adBreak_durationMs : 0;
6340
6578
  endMs = breakStartMs + durationMs;
6341
- tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6342
- inWindow = durationMs > 0 ? nowMs > breakStartMs && nowMs < endMs : nowMs + tol >= breakStartMs;
6579
+ inWindow = durationMs > 0 ? nowMs >= breakStartMs && nowMs < endMs : nowMs >= breakStartMs;
6343
6580
  if (!inWindow) return [
6344
6581
  3,
6345
6582
  4
6346
6583
  ];
6347
6584
  this.consumedVmapBreakIds.add(key);
6348
- remainingMs = durationMs > 0 ? Math.max(0, endMs - nowMs) : 0;
6349
- tags = this.selectVastTagsForBreak(adBreak) || (this.apiVastTagUrl ? [
6350
- this.apiVastTagUrl
6351
- ] : void 0);
6352
- if (!(tags && tags.length > 0)) return [
6353
- 3,
6354
- 4
6355
- ];
6585
+ tags = this.selectVastTagsForBreak(adBreak);
6586
+ if (!tags || tags.length === 0) {
6587
+ return [
6588
+ 2
6589
+ ];
6590
+ }
6356
6591
  first = tags[0];
6357
6592
  rest = tags.slice(1);
6358
6593
  this.adPodQueue = rest;
6359
6594
  this.adPlayer.updateOriginalMutedState(this.video.muted, this.video.volume);
6595
+ this.showAds = true;
6596
+ this.inAdBreak = true;
6597
+ this.currentAdBreakStartWallClockMs = Date.now();
6598
+ if (!this.video.paused) {
6599
+ this.video.pause();
6600
+ }
6360
6601
  _state.label = 1;
6361
6602
  case 1:
6362
6603
  _state.trys.push([
@@ -6371,10 +6612,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6371
6612
  ];
6372
6613
  case 2:
6373
6614
  _state.sent();
6374
- this.inAdBreak = true;
6375
- this.expectedAdBreakDurationMs = remainingMs;
6376
- this.currentAdBreakStartWallClockMs = Date.now();
6377
- this.scheduleAdStopCountdown(remainingMs);
6378
6615
  return [
6379
6616
  3,
6380
6617
  4
@@ -6382,8 +6619,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6382
6619
  case 3:
6383
6620
  error = _state.sent();
6384
6621
  this.adPodQueue = [];
6622
+ this.inAdBreak = false;
6623
+ this.showAds = false;
6385
6624
  if (this.config.debugAdTiming) {
6386
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP ad request failed:", error);
6625
+ console.warn("[StormcloudVideoPlayer] VMAP ad request failed:", error);
6387
6626
  }
6388
6627
  return [
6389
6628
  3,
@@ -7095,9 +7334,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7095
7334
  {
7096
7335
  key: "findBreakForTime",
7097
7336
  value: function findBreakForTime(nowMs) {
7098
- var _this_config_driftToleranceMs;
7099
7337
  var schedule = this.vmapBreaks;
7100
- var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
7101
7338
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
7102
7339
  try {
7103
7340
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
@@ -7109,9 +7346,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7109
7346
  if (breakStartMs == null) {
7110
7347
  continue;
7111
7348
  }
7112
- var end = breakStartMs + (b.durationMs || 0);
7113
- var effectiveTol = breakStartMs === 0 ? Math.max(tol, 3e4) : tol;
7114
- if (nowMs >= breakStartMs && (b.durationMs ? nowMs < end : nowMs <= breakStartMs + effectiveTol)) {
7349
+ if (b.durationMs) {
7350
+ var end = breakStartMs + b.durationMs;
7351
+ if (nowMs >= breakStartMs && nowMs < end) {
7352
+ return b;
7353
+ }
7354
+ continue;
7355
+ }
7356
+ if (nowMs >= breakStartMs) {
7115
7357
  return b;
7116
7358
  }
7117
7359
  }
@@ -7319,6 +7561,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7319
7561
  this.video.removeEventListener("timeupdate", this.timeUpdateHandler);
7320
7562
  delete this.timeUpdateHandler;
7321
7563
  }
7564
+ if (this.endedHandler) {
7565
+ this.video.removeEventListener("ended", this.endedHandler);
7566
+ delete this.endedHandler;
7567
+ }
7322
7568
  if (this.emptiedHandler) {
7323
7569
  this.video.removeEventListener("emptied", this.emptiedHandler);
7324
7570
  delete this.emptiedHandler;