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.
@@ -1385,6 +1385,99 @@ function createPalNonceManager() {
1385
1385
  }
1386
1386
  };
1387
1387
  }
1388
+ // src/utils/mqttConfig.ts
1389
+ var DEFAULT_MQTT_CONFIG = {
1390
+ enabled: true,
1391
+ brokerAddress: "vecbae77.ala.us-east-1.emqxsl.com",
1392
+ brokerPort: 8883,
1393
+ wsPort: 8084,
1394
+ username: "for-sonifi",
1395
+ password: "sonifi-mqtt",
1396
+ topicPrefix: "adstorm/players",
1397
+ qos: 1
1398
+ };
1399
+ var mqttConfig = _object_spread({}, DEFAULT_MQTT_CONFIG);
1400
+ function isMQTTEnabled() {
1401
+ return mqttConfig.enabled;
1402
+ }
1403
+ function buildMQTTBrokerUrl() {
1404
+ if (mqttConfig.brokerUrl) return mqttConfig.brokerUrl;
1405
+ return "wss://".concat(mqttConfig.brokerAddress, ":").concat(mqttConfig.wsPort, "/mqtt");
1406
+ }
1407
+ function buildPlayerTopic(licenseKey, channel) {
1408
+ return "".concat(mqttConfig.topicPrefix, "/").concat(licenseKey, "/").concat(channel);
1409
+ }
1410
+ // src/utils/mqttClient.ts
1411
+ var import_mqtt = __toESM(require("mqtt"), 1);
1412
+ var LOG = "[StormcloudVideoPlayer][MQTT]";
1413
+ var client = null;
1414
+ var status = "disconnected";
1415
+ function initMQTTClient() {
1416
+ if (client || !isMQTTEnabled()) return;
1417
+ var url = buildMQTTBrokerUrl();
1418
+ status = "connecting";
1419
+ var clientId = "stormcloud-vp-".concat(Math.random().toString(36).slice(2, 9));
1420
+ try {
1421
+ client = import_mqtt.default.connect(url, {
1422
+ clientId: clientId,
1423
+ username: mqttConfig.username,
1424
+ password: mqttConfig.password,
1425
+ keepalive: 60,
1426
+ clean: true,
1427
+ reconnectPeriod: 5e3,
1428
+ connectTimeout: 1e4,
1429
+ queueQoSZero: false
1430
+ });
1431
+ } catch (err) {
1432
+ status = "error";
1433
+ console.warn("".concat(LOG, " connect() threw:"), err);
1434
+ return;
1435
+ }
1436
+ client.on("connect", function() {
1437
+ status = "connected";
1438
+ console.info("".concat(LOG, " connected to ").concat(url));
1439
+ });
1440
+ client.on("reconnect", function() {
1441
+ status = "connecting";
1442
+ console.info("".concat(LOG, " reconnecting…"));
1443
+ });
1444
+ client.on("offline", function() {
1445
+ status = "disconnected";
1446
+ console.warn("".concat(LOG, " offline"));
1447
+ });
1448
+ client.on("error", function(err) {
1449
+ status = "error";
1450
+ console.warn("".concat(LOG, " error:"), err.message);
1451
+ });
1452
+ client.on("close", function() {
1453
+ if (status === "connected") {
1454
+ status = "disconnected";
1455
+ }
1456
+ });
1457
+ }
1458
+ function ensureMQTTClient() {
1459
+ if (isMQTTEnabled() && !client) {
1460
+ initMQTTClient();
1461
+ }
1462
+ }
1463
+ function publishMQTT(topic, payload) {
1464
+ if (!isMQTTEnabled()) {
1465
+ return false;
1466
+ }
1467
+ ensureMQTTClient();
1468
+ if (!client) {
1469
+ return false;
1470
+ }
1471
+ try {
1472
+ client.publish(topic, JSON.stringify(payload), {
1473
+ qos: mqttConfig.qos
1474
+ });
1475
+ return true;
1476
+ } catch (err) {
1477
+ console.warn("".concat(LOG, " publish failed on ").concat(topic, ":"), err);
1478
+ return false;
1479
+ }
1480
+ }
1388
1481
  // src/utils/tracking.ts
1389
1482
  var cachedBrowserId = null;
1390
1483
  function getClientInfo() {
@@ -1531,7 +1624,7 @@ function getClientInfo() {
1531
1624
  }
1532
1625
  function getBrowserID(clientInfo) {
1533
1626
  return _async_to_generator(function() {
1534
- var fingerprintString, encodedData, utf8, buffer, i, hashBuffer, hashArray, hashHex, error, hash, i1, char, fallbackHash, timestamp, random;
1627
+ var _crypto_subtle, fingerprintString, encodedData, utf8, buffer, i, hashBuffer, hashHex, unused, hash, i1, char, fallbackHash, timestamp, random;
1535
1628
  return _ts_generator(this, function(_state) {
1536
1629
  switch(_state.label){
1537
1630
  case 0:
@@ -1542,7 +1635,7 @@ function getBrowserID(clientInfo) {
1542
1635
  ];
1543
1636
  }
1544
1637
  fingerprintString = JSON.stringify(clientInfo);
1545
- if (!(typeof crypto !== "undefined" && crypto.subtle && crypto.subtle.digest)) return [
1638
+ if (!(typeof crypto !== "undefined" && ((_crypto_subtle = crypto.subtle) === null || _crypto_subtle === void 0 ? void 0 : _crypto_subtle.digest))) return [
1546
1639
  3,
1547
1640
  5
1548
1641
  ];
@@ -1580,8 +1673,7 @@ function getBrowserID(clientInfo) {
1580
1673
  ];
1581
1674
  case 3:
1582
1675
  hashBuffer = _state.sent();
1583
- hashArray = Array.from(new Uint8Array(hashBuffer));
1584
- hashHex = hashArray.map(function(b) {
1676
+ hashHex = Array.from(new Uint8Array(hashBuffer)).map(function(b) {
1585
1677
  return b.toString(16).padStart(2, "0");
1586
1678
  }).join("");
1587
1679
  cachedBrowserId = hashHex;
@@ -1590,8 +1682,8 @@ function getBrowserID(clientInfo) {
1590
1682
  hashHex
1591
1683
  ];
1592
1684
  case 4:
1593
- error = _state.sent();
1594
- console.warn("[StormcloudVideoPlayer] crypto.subtle.digest not supported, using fallback hash");
1685
+ unused = _state.sent();
1686
+ console.warn("[StormcloudVideoPlayer] crypto.subtle not supported, using fallback hash");
1595
1687
  return [
1596
1688
  3,
1597
1689
  5
@@ -1615,177 +1707,91 @@ function getBrowserID(clientInfo) {
1615
1707
  });
1616
1708
  })();
1617
1709
  }
1618
- var PLAYER_TRACKING_BASE_URL = "https://adstorm.co/api-adstorm-dev/adstorm/player-tracking";
1619
- var TRACK_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/metrics/ingest");
1620
- var HEARTBEAT_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/heartbeat");
1621
- var IMPRESSIONS_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/impressions/ingest");
1622
- function buildHeaders(licenseKey) {
1623
- var headers = {
1624
- "Content-Type": "application/json"
1625
- };
1626
- if (licenseKey) {
1627
- headers["Authorization"] = "Bearer ".concat(licenseKey);
1628
- }
1629
- return headers;
1630
- }
1631
- function sendTrackRequest(licenseKey, body) {
1632
- return _async_to_generator(function() {
1633
- var response;
1634
- return _ts_generator(this, function(_state) {
1635
- switch(_state.label){
1636
- case 0:
1637
- return [
1638
- 4,
1639
- fetch(TRACK_URL, {
1640
- method: "POST",
1641
- headers: buildHeaders(licenseKey),
1642
- body: JSON.stringify(body)
1643
- })
1644
- ];
1645
- case 1:
1646
- response = _state.sent();
1647
- if (!response.ok) {
1648
- throw new Error("HTTP error! status: ".concat(response.status));
1649
- }
1650
- return [
1651
- 4,
1652
- response.json()
1653
- ];
1654
- case 2:
1655
- _state.sent();
1656
- return [
1657
- 2
1658
- ];
1659
- }
1660
- });
1661
- })();
1710
+ function canPublish(licenseKey) {
1711
+ return Boolean(isMQTTEnabled() && licenseKey);
1662
1712
  }
1663
- function postJson(url, licenseKey, body) {
1713
+ function buildPlayerMetricEvent() {
1664
1714
  return _async_to_generator(function() {
1665
- var response;
1666
- return _ts_generator(this, function(_state) {
1667
- switch(_state.label){
1668
- case 0:
1669
- return [
1670
- 4,
1671
- fetch(url, {
1672
- method: "POST",
1673
- headers: buildHeaders(licenseKey),
1674
- body: JSON.stringify(body)
1675
- })
1676
- ];
1677
- case 1:
1678
- response = _state.sent();
1679
- if (!response.ok) {
1680
- throw new Error("HTTP error! status: ".concat(response.status));
1681
- }
1682
- return [
1683
- 4,
1684
- response.json()
1685
- ];
1686
- case 2:
1687
- _state.sent();
1688
- return [
1689
- 2
1690
- ];
1691
- }
1692
- });
1693
- })();
1694
- }
1695
- function buildPlayerMetricEvent(_0) {
1696
- return _async_to_generator(function(licenseKey) {
1697
- var context, flags, _flags_captureAt, clientInfo, browserId, captureAt;
1715
+ var context, flags, _flags_captureAt, _flags_adLoaded, _flags_adDetect, clientInfo, playerId, captureAt;
1698
1716
  var _arguments = arguments;
1699
1717
  return _ts_generator(this, function(_state) {
1700
1718
  switch(_state.label){
1701
1719
  case 0:
1702
- context = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {}, flags = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : {};
1720
+ context = _arguments.length > 0 && _arguments[0] !== void 0 ? _arguments[0] : {}, flags = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {};
1703
1721
  clientInfo = getClientInfo();
1704
1722
  return [
1705
1723
  4,
1706
1724
  getBrowserID(clientInfo)
1707
1725
  ];
1708
1726
  case 1:
1709
- browserId = _state.sent();
1727
+ playerId = _state.sent();
1710
1728
  captureAt = (_flags_captureAt = flags.captureAt) !== null && _flags_captureAt !== void 0 ? _flags_captureAt : /* @__PURE__ */ new Date().toISOString();
1711
1729
  return [
1712
1730
  2,
1713
- {
1714
- player_id: browserId,
1715
- browserId: browserId,
1731
+ _object_spread({
1732
+ player_id: playerId,
1716
1733
  device_type: clientInfo.deviceType,
1717
- deviceType: clientInfo.deviceType,
1718
- input_stream_type: context.inputStreamType,
1719
- os: clientInfo.os,
1720
- ad_loaded: flags.adLoaded,
1721
- ad_detect: flags.adDetect,
1722
- license_key: licenseKey,
1723
- capture_at: captureAt,
1724
- timestamp: captureAt
1725
- }
1734
+ os: clientInfo.os.toLowerCase(),
1735
+ ad_loaded: (_flags_adLoaded = flags.adLoaded) !== null && _flags_adLoaded !== void 0 ? _flags_adLoaded : false,
1736
+ ad_detect: (_flags_adDetect = flags.adDetect) !== null && _flags_adDetect !== void 0 ? _flags_adDetect : false,
1737
+ capture_at: captureAt
1738
+ }, context.inputStreamType ? {
1739
+ input_stream_type: context.inputStreamType
1740
+ } : {})
1726
1741
  ];
1727
1742
  }
1728
1743
  });
1729
1744
  }).apply(this, arguments);
1730
1745
  }
1746
+ function publishTracking(licenseKey, channel, body) {
1747
+ ensureMQTTClient();
1748
+ publishMQTT(buildPlayerTopic(licenseKey, channel), body);
1749
+ }
1731
1750
  function sendInitialTracking(_0) {
1732
1751
  return _async_to_generator(function(licenseKey) {
1733
- var context, clientInfo, browserId, trackingData, error;
1752
+ var context, metricEvent, error;
1734
1753
  var _arguments = arguments;
1735
1754
  return _ts_generator(this, function(_state) {
1736
1755
  switch(_state.label){
1737
1756
  case 0:
1738
1757
  context = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {};
1758
+ if (!canPublish(licenseKey)) return [
1759
+ 2
1760
+ ];
1739
1761
  _state.label = 1;
1740
1762
  case 1:
1741
1763
  _state.trys.push([
1742
1764
  1,
1743
- 4,
1765
+ 3,
1744
1766
  ,
1745
- 5
1767
+ 4
1746
1768
  ]);
1747
- clientInfo = getClientInfo();
1748
- return [
1749
- 4,
1750
- getBrowserID(clientInfo)
1751
- ];
1752
- case 2:
1753
- browserId = _state.sent();
1754
- trackingData = _object_spread({
1755
- browserId: browserId
1756
- }, clientInfo);
1757
1769
  return [
1758
1770
  4,
1759
- sendTrackRequest(licenseKey, {
1760
- events: [
1761
- {
1762
- player_id: browserId,
1763
- device_type: clientInfo.deviceType,
1764
- input_stream_type: context.inputStreamType,
1765
- os: clientInfo.os,
1766
- ad_loaded: false,
1767
- ad_detect: false,
1768
- license_key: licenseKey,
1769
- capture_at: /* @__PURE__ */ new Date().toISOString()
1770
- }
1771
- ],
1772
- trackingData: trackingData
1771
+ buildPlayerMetricEvent(context, {
1772
+ adLoaded: false,
1773
+ adDetect: false
1773
1774
  })
1774
1775
  ];
1775
- case 3:
1776
- _state.sent();
1776
+ case 2:
1777
+ metricEvent = _state.sent();
1778
+ publishTracking(licenseKey, "metrics", {
1779
+ events: [
1780
+ metricEvent
1781
+ ]
1782
+ });
1777
1783
  return [
1778
1784
  3,
1779
- 5
1785
+ 4
1780
1786
  ];
1781
- case 4:
1787
+ case 3:
1782
1788
  error = _state.sent();
1783
1789
  console.error("[StormcloudVideoPlayer] Error sending initial tracking data:", error);
1784
1790
  return [
1785
1791
  3,
1786
- 5
1792
+ 4
1787
1793
  ];
1788
- case 5:
1794
+ case 4:
1789
1795
  return [
1790
1796
  2
1791
1797
  ];
@@ -1889,53 +1895,48 @@ function sendAdImpressionTracking(_0, _1) {
1889
1895
  switch(_state.label){
1890
1896
  case 0:
1891
1897
  context = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : {};
1898
+ if (!canPublish(licenseKey)) return [
1899
+ 2
1900
+ ];
1892
1901
  _state.label = 1;
1893
1902
  case 1:
1894
1903
  _state.trys.push([
1895
1904
  1,
1896
- 4,
1905
+ 3,
1897
1906
  ,
1898
- 5
1907
+ 4
1899
1908
  ]);
1900
1909
  return [
1901
1910
  4,
1902
- buildPlayerMetricEvent(licenseKey, context, {
1911
+ buildPlayerMetricEvent(context, {
1903
1912
  captureAt: adImpressionInfo.timestamp
1904
1913
  })
1905
1914
  ];
1906
1915
  case 2:
1907
1916
  metricEvent = _state.sent();
1908
- return [
1909
- 4,
1910
- Promise.all([
1911
- postJson(HEARTBEAT_URL, licenseKey, metricEvent),
1912
- postJson(IMPRESSIONS_URL, licenseKey, {
1913
- events: [
1914
- {
1915
- player_id: metricEvent.player_id,
1916
- ad_played_count: 1,
1917
- ad_url: adImpressionInfo.adUrl,
1918
- license_key: licenseKey,
1919
- capture_at: adImpressionInfo.timestamp
1920
- }
1921
- ]
1922
- })
1923
- ])
1924
- ];
1925
- case 3:
1926
- _state.sent();
1917
+ publishTracking(licenseKey, "heartbeat", metricEvent);
1918
+ publishTracking(licenseKey, "impressions", {
1919
+ events: [
1920
+ {
1921
+ player_id: metricEvent.player_id,
1922
+ ad_played_count: 1,
1923
+ ad_url: adImpressionInfo.adUrl,
1924
+ capture_at: adImpressionInfo.timestamp
1925
+ }
1926
+ ]
1927
+ });
1927
1928
  return [
1928
1929
  3,
1929
- 5
1930
+ 4
1930
1931
  ];
1931
- case 4:
1932
+ case 3:
1932
1933
  error = _state.sent();
1933
1934
  console.error("[StormcloudVideoPlayer] Error sending ad impression tracking:", error);
1934
1935
  return [
1935
1936
  3,
1936
- 5
1937
+ 4
1937
1938
  ];
1938
- case 5:
1939
+ case 4:
1939
1940
  return [
1940
1941
  2
1941
1942
  ];
@@ -1951,38 +1952,36 @@ function sendHeartbeat(_0) {
1951
1952
  switch(_state.label){
1952
1953
  case 0:
1953
1954
  context = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {}, flags = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : {};
1955
+ if (!canPublish(licenseKey)) return [
1956
+ 2
1957
+ ];
1954
1958
  _state.label = 1;
1955
1959
  case 1:
1956
1960
  _state.trys.push([
1957
1961
  1,
1958
- 4,
1962
+ 3,
1959
1963
  ,
1960
- 5
1964
+ 4
1961
1965
  ]);
1962
1966
  return [
1963
1967
  4,
1964
- buildPlayerMetricEvent(licenseKey, context, flags)
1968
+ buildPlayerMetricEvent(context, flags)
1965
1969
  ];
1966
1970
  case 2:
1967
1971
  heartbeatData = _state.sent();
1968
- return [
1969
- 4,
1970
- postJson(HEARTBEAT_URL, licenseKey, heartbeatData)
1971
- ];
1972
- case 3:
1973
- _state.sent();
1972
+ publishTracking(licenseKey, "heartbeat", heartbeatData);
1974
1973
  return [
1975
1974
  3,
1976
- 5
1975
+ 4
1977
1976
  ];
1978
- case 4:
1977
+ case 3:
1979
1978
  error = _state.sent();
1980
1979
  console.error("[StormcloudVideoPlayer] Error sending heartbeat:", error);
1981
1980
  return [
1982
1981
  3,
1983
- 5
1982
+ 4
1984
1983
  ];
1985
- case 5:
1984
+ case 4:
1986
1985
  return [
1987
1986
  2
1988
1987
  ];
@@ -2241,6 +2240,166 @@ function initializePolyfills() {
2241
2240
  polyfillTextEncoder();
2242
2241
  polyfillPromiseFinally();
2243
2242
  }
2243
+ // src/utils/vastMacros.ts
2244
+ function generateCorrelator() {
2245
+ if (typeof crypto !== "undefined" && crypto.getRandomValues) {
2246
+ try {
2247
+ var _buf_, _buf_1;
2248
+ var buf = new Uint32Array(2);
2249
+ crypto.getRandomValues(buf);
2250
+ 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);
2251
+ if (value > 0) {
2252
+ return String(value);
2253
+ }
2254
+ } catch (unused) {}
2255
+ }
2256
+ return String(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER) + 1);
2257
+ }
2258
+ var UNEXPANDED_MACRO_PATTERN = /^(\[[^\]]*\]|\{[^}]*\}|%%[^%]*%%)$/;
2259
+ function applyVastMacros(baseUrl, ctx) {
2260
+ var url;
2261
+ try {
2262
+ url = new URL(baseUrl);
2263
+ } catch (unused) {
2264
+ return replaceCorrelatorFallback(baseUrl, ctx.correlator);
2265
+ }
2266
+ var params = url.searchParams;
2267
+ params.set("correlator", ctx.correlator);
2268
+ params.set("scor", ctx.streamCorrelator);
2269
+ if (ctx.pod != null) {
2270
+ params.set("pod", String(ctx.pod));
2271
+ }
2272
+ if (ctx.adPosition != null) {
2273
+ params.set("ppos", String(ctx.adPosition));
2274
+ }
2275
+ if (ctx.pageUrl) {
2276
+ params.set("url", ctx.pageUrl);
2277
+ params.set("description_url", ctx.pageUrl);
2278
+ }
2279
+ if (ctx.adWillPlayMuted != null) {
2280
+ params.set("vpmute", ctx.adWillPlayMuted ? "1" : "0");
2281
+ }
2282
+ if (ctx.adWillAutoPlay != null) {
2283
+ params.set("vpa", ctx.adWillAutoPlay ? "auto" : "click");
2284
+ }
2285
+ if (ctx.deviceId && ctx.deviceIdType) {
2286
+ params.set("rdid", ctx.deviceId);
2287
+ params.set("idtype", ctx.deviceIdType);
2288
+ params.set("is_lat", ctx.limitAdTracking ? "1" : "0");
2289
+ } else {
2290
+ params.delete("rdid");
2291
+ params.delete("idtype");
2292
+ params.delete("is_lat");
2293
+ }
2294
+ var consent = ctx.consent;
2295
+ if ((consent === null || consent === void 0 ? void 0 : consent.gdpr) != null) {
2296
+ params.set("gdpr", consent.gdpr);
2297
+ }
2298
+ if ((consent === null || consent === void 0 ? void 0 : consent.gdprConsent) != null) {
2299
+ params.set("gdpr_consent", consent.gdprConsent);
2300
+ }
2301
+ if ((consent === null || consent === void 0 ? void 0 : consent.usPrivacy) != null) {
2302
+ params.set("us_privacy", consent.usPrivacy);
2303
+ }
2304
+ if (ctx.adTest) {
2305
+ params.set("adtest", "on");
2306
+ }
2307
+ var staleKeys = [];
2308
+ params.forEach(function(value, key) {
2309
+ if (UNEXPANDED_MACRO_PATTERN.test(value)) {
2310
+ staleKeys.push(key);
2311
+ }
2312
+ });
2313
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2314
+ try {
2315
+ for(var _iterator = staleKeys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2316
+ var key = _step.value;
2317
+ params.delete(key);
2318
+ }
2319
+ } catch (err) {
2320
+ _didIteratorError = true;
2321
+ _iteratorError = err;
2322
+ } finally{
2323
+ try {
2324
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2325
+ _iterator.return();
2326
+ }
2327
+ } finally{
2328
+ if (_didIteratorError) {
2329
+ throw _iteratorError;
2330
+ }
2331
+ }
2332
+ }
2333
+ return url.toString();
2334
+ }
2335
+ function replaceCorrelatorFallback(baseUrl, correlator) {
2336
+ var correlatorRegex = /([?&])correlator=([^&]*)/;
2337
+ if (correlatorRegex.test(baseUrl)) {
2338
+ return baseUrl.replace(correlatorRegex, "$1correlator=".concat(correlator));
2339
+ }
2340
+ var sep = baseUrl.includes("?") ? "&" : "?";
2341
+ return "".concat(baseUrl).concat(sep, "correlator=").concat(correlator);
2342
+ }
2343
+ function fetchConsentSignals() {
2344
+ var timeoutMs = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : 1500;
2345
+ var signals = {};
2346
+ if (typeof window === "undefined") {
2347
+ return Promise.resolve(signals);
2348
+ }
2349
+ var tasks = [];
2350
+ var tcfApi = window.__tcfapi;
2351
+ if (typeof tcfApi === "function") {
2352
+ tasks.push(new Promise(function(resolve) {
2353
+ var settled = false;
2354
+ try {
2355
+ tcfApi("addEventListener", 2, function(tcData, success) {
2356
+ if (settled) return;
2357
+ if (success && tcData && (tcData.eventStatus === "tcloaded" || tcData.eventStatus === "useractioncomplete")) {
2358
+ settled = true;
2359
+ signals.gdpr = tcData.gdprApplies ? "1" : "0";
2360
+ if (typeof tcData.tcString === "string" && tcData.tcString) {
2361
+ signals.gdprConsent = tcData.tcString;
2362
+ }
2363
+ try {
2364
+ tcfApi("removeEventListener", 2, function() {}, tcData.listenerId);
2365
+ } catch (unused) {}
2366
+ resolve();
2367
+ }
2368
+ });
2369
+ } catch (unused) {
2370
+ resolve();
2371
+ }
2372
+ setTimeout(function() {
2373
+ if (!settled) {
2374
+ settled = true;
2375
+ resolve();
2376
+ }
2377
+ }, timeoutMs);
2378
+ }));
2379
+ }
2380
+ var uspApi = window.__uspapi;
2381
+ if (typeof uspApi === "function") {
2382
+ tasks.push(new Promise(function(resolve) {
2383
+ try {
2384
+ uspApi("getUSPData", 1, function(data, success) {
2385
+ if (success && typeof (data === null || data === void 0 ? void 0 : data.uspString) === "string" && data.uspString) {
2386
+ signals.usPrivacy = data.uspString;
2387
+ }
2388
+ resolve();
2389
+ });
2390
+ } catch (unused) {
2391
+ resolve();
2392
+ }
2393
+ setTimeout(resolve, timeoutMs);
2394
+ }));
2395
+ }
2396
+ if (tasks.length === 0) {
2397
+ return Promise.resolve(signals);
2398
+ }
2399
+ return Promise.all(tasks).then(function() {
2400
+ return signals;
2401
+ });
2402
+ }
2244
2403
  // src/utils/browserCompat.ts
2245
2404
  function getChromeVersion(ua) {
2246
2405
  var match = ua.match(/Chrome\/(\d+)/);
@@ -2466,6 +2625,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2466
2625
  this.preloadPoolLoopRunning = false;
2467
2626
  this.adDetectSentForCurrentBreak = false;
2468
2627
  this.palPlaybackStarted = false;
2628
+ this.streamCorrelator = generateCorrelator();
2629
+ this.consentSignals = {};
2630
+ this.podCounter = 0;
2631
+ this.podAssignedByPrefetch = false;
2632
+ this.adRequestPositionInBreak = 0;
2469
2633
  this.continuousFetchLoopRunning = false;
2470
2634
  initializePolyfills();
2471
2635
  var browserOverrides = getBrowserConfigOverrides();
@@ -2538,6 +2702,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2538
2702
  adWillPlayMuted: !!this.config.muted,
2539
2703
  continuousPlayback: (_this_config_lowLatencyMode = this.config.lowLatencyMode) !== null && _this_config_lowLatencyMode !== void 0 ? _this_config_lowLatencyMode : false
2540
2704
  }).catch(function() {});
2705
+ fetchConsentSignals().then(function(signals) {
2706
+ _this.consentSignals = signals;
2707
+ }).catch(function() {});
2541
2708
  this.initializeTracking();
2542
2709
  if (!this.shouldUseNativeHls()) return [
2543
2710
  3,
@@ -2605,7 +2772,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2605
2772
  var _level_details, _level_details1;
2606
2773
  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";
2607
2774
  })) !== null && _ref !== void 0 ? _ref : false;
2608
- if (!this.isLiveStream && this.vmapBreaks.length === 0 && this.apiVastTagUrl) {
2775
+ if (!this.isVmapEnabled() && !this.isLiveStream && this.vmapBreaks.length === 0 && this.apiVastTagUrl) {
2609
2776
  prerollKey = "synthetic-vod-preroll";
2610
2777
  if (!this.consumedVmapBreakIds.has(prerollKey)) {
2611
2778
  this.vmapBreaks = [
@@ -3190,12 +3357,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3190
3357
  _this.palNonce.sendPlaybackStart();
3191
3358
  }
3192
3359
  });
3193
- this.video.addEventListener("ended", function() {
3360
+ this.endedHandler = function() {
3194
3361
  if (_this.palPlaybackStarted) {
3195
3362
  _this.palPlaybackStarted = false;
3196
3363
  _this.palNonce.sendPlaybackEnd();
3197
3364
  }
3198
- });
3365
+ _this.onVideoEnded();
3366
+ };
3367
+ this.video.addEventListener("ended", this.endedHandler);
3199
3368
  this.video.addEventListener("mousedown", function(e) {
3200
3369
  _this.palNonce.sendAdTouch(e);
3201
3370
  });
@@ -4517,6 +4686,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4517
4686
  }
4518
4687
  }
4519
4688
  },
4689
+ {
4690
+ key: "isVmapEnabled",
4691
+ value: function isVmapEnabled() {
4692
+ var _this_config_vmapUrl;
4693
+ return !!(this.config.isVmap && ((_this_config_vmapUrl = this.config.vmapUrl) === null || _this_config_vmapUrl === void 0 ? void 0 : _this_config_vmapUrl.trim()));
4694
+ }
4695
+ },
4520
4696
  {
4521
4697
  key: "fetchAdConfiguration",
4522
4698
  value: function fetchAdConfiguration() {
@@ -4525,7 +4701,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4525
4701
  return _ts_generator(this, function(_state) {
4526
4702
  switch(_state.label){
4527
4703
  case 0:
4528
- if (!this.config.vmapUrl) return [
4704
+ if (!this.isVmapEnabled()) return [
4529
4705
  3,
4530
4706
  2
4531
4707
  ];
@@ -4535,7 +4711,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4535
4711
  ];
4536
4712
  case 1:
4537
4713
  _state.sent();
4538
- _state.label = 2;
4714
+ if (this.config.debugAdTiming) {
4715
+ console.log("[StormcloudVideoPlayer] VMAP mode enabled");
4716
+ }
4717
+ return [
4718
+ 2
4719
+ ];
4539
4720
  case 2:
4540
4721
  vastMode = this.config.vastMode || "default";
4541
4722
  if (this.config.debugAdTiming) {
@@ -4703,7 +4884,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4703
4884
  }
4704
4885
  return [];
4705
4886
  }
4706
- var adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
4887
+ var VMAP_NS = "http://www.iab.net/videosuite/vmap";
4888
+ var adBreakNodes = Array.from(doc.getElementsByTagNameNS(VMAP_NS, "AdBreak"));
4889
+ if (adBreakNodes.length === 0) {
4890
+ adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
4891
+ }
4892
+ if (adBreakNodes.length === 0) {
4893
+ adBreakNodes = Array.from(doc.getElementsByTagName("*")).filter(function(el) {
4894
+ return el.localName === "AdBreak";
4895
+ });
4896
+ }
4707
4897
  var parsed = [];
4708
4898
  adBreakNodes.forEach(function(node, index) {
4709
4899
  var timeOffsetRaw = (node.getAttribute("timeOffset") || "").trim();
@@ -4711,7 +4901,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4711
4901
  if (startTimeMs == null) {
4712
4902
  return;
4713
4903
  }
4714
- var adTagNode = node.querySelector("AdTagURI, vmap\\:AdTagURI");
4904
+ var adTagNode = node.getElementsByTagNameNS(VMAP_NS, "AdTagURI")[0];
4905
+ if (!adTagNode) {
4906
+ var _node_querySelector;
4907
+ adTagNode = (_node_querySelector = node.querySelector("AdTagURI, vmap\\:AdTagURI")) !== null && _node_querySelector !== void 0 ? _node_querySelector : void 0;
4908
+ }
4715
4909
  var adTagUrl = ((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim();
4716
4910
  if (!adTagUrl) {
4717
4911
  return;
@@ -4807,25 +5001,35 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4807
5001
  return this.getRemainingAdMs();
4808
5002
  }
4809
5003
  },
5004
+ {
5005
+ key: "beginNewAdPod",
5006
+ value: function beginNewAdPod() {
5007
+ this.podCounter++;
5008
+ this.adRequestPositionInBreak = 0;
5009
+ }
5010
+ },
4810
5011
  {
4811
5012
  key: "generateVastUrlsWithCorrelators",
4812
5013
  value: function generateVastUrlsWithCorrelators(baseUrl, count) {
4813
5014
  var urls = [];
4814
- var baseTimestamp = Date.now();
4815
5015
  for(var i = 0; i < count; i++){
4816
- var timestamp = baseTimestamp + i;
4817
- var random = Math.floor(Math.random() * 1e12);
4818
- var uniqueCorrelator = "".concat(timestamp, "_").concat(random, "_").concat(i);
4819
- var urlWithCorrelator = void 0;
4820
- var correlatorRegex = /([?&])correlator=([^&]*)/;
4821
- if (correlatorRegex.test(baseUrl)) {
4822
- urlWithCorrelator = baseUrl.replace(correlatorRegex, "$1correlator=".concat(uniqueCorrelator));
4823
- } else if (baseUrl.includes("?")) {
4824
- urlWithCorrelator = "".concat(baseUrl, "&correlator=").concat(uniqueCorrelator);
4825
- } else {
4826
- urlWithCorrelator = "".concat(baseUrl, "?correlator=").concat(uniqueCorrelator);
4827
- }
4828
- urls.push(this.palNonce.injectNonce(urlWithCorrelator));
5016
+ this.adRequestPositionInBreak++;
5017
+ var adWillPlayMuted = this.inAdBreak ? this.adPlayer.getOriginalMutedState() : this.video.muted;
5018
+ var urlWithMacros = applyVastMacros(baseUrl, {
5019
+ correlator: generateCorrelator(),
5020
+ streamCorrelator: this.streamCorrelator,
5021
+ pod: this.podCounter > 0 ? this.podCounter : void 0,
5022
+ adPosition: this.adRequestPositionInBreak,
5023
+ pageUrl: typeof window !== "undefined" ? window.location.href : void 0,
5024
+ adWillPlayMuted: adWillPlayMuted,
5025
+ adWillAutoPlay: !!this.config.autoplay,
5026
+ deviceId: this.config.deviceId,
5027
+ deviceIdType: this.config.deviceIdType,
5028
+ limitAdTracking: this.config.limitAdTracking,
5029
+ adTest: this.config.adTest,
5030
+ consent: this.consentSignals
5031
+ });
5032
+ urls.push(this.palNonce.injectNonce(urlWithMacros));
4829
5033
  }
4830
5034
  return urls;
4831
5035
  }
@@ -4895,6 +5099,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4895
5099
  }
4896
5100
  return;
4897
5101
  }
5102
+ this.beginNewAdPod();
5103
+ this.podAssignedByPrefetch = true;
4898
5104
  var urlsToPregenerate = 5;
4899
5105
  var generatedUrls = this.generateVastUrlsWithCorrelators(baseVastUrl, urlsToPregenerate);
4900
5106
  this.pendingAdBreak = _object_spread_props(_object_spread({
@@ -4932,6 +5138,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4932
5138
  }
4933
5139
  this.pendingAdBreak = null;
4934
5140
  this.pendingScte35CueKey = void 0;
5141
+ this.podAssignedByPrefetch = false;
4935
5142
  }
4936
5143
  },
4937
5144
  {
@@ -5368,6 +5575,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5368
5575
  this.continuousFetchingActive = true;
5369
5576
  this.isShowingPlaceholder = false;
5370
5577
  this.totalAdRequestsInBreak = 0;
5578
+ if (this.podAssignedByPrefetch) {
5579
+ this.podAssignedByPrefetch = false;
5580
+ } else {
5581
+ this.beginNewAdPod();
5582
+ }
5371
5583
  currentMuted = this.video.muted;
5372
5584
  currentVolume = this.video.volume;
5373
5585
  this.adPlayer.updateOriginalMutedState(currentMuted, currentVolume);
@@ -6268,23 +6480,49 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6268
6480
  key: "onTimeUpdate",
6269
6481
  value: function onTimeUpdate(currentTimeSec) {
6270
6482
  var _this = this;
6483
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
6484
+ return;
6485
+ }
6271
6486
  if (this.adPlayer.isAdPlaying() || this.inAdBreak) return;
6272
6487
  var nowMs = currentTimeSec * 1e3;
6273
6488
  var breakToPlay = this.findBreakForTime(nowMs);
6274
6489
  if (breakToPlay) {
6275
- void this.handleMidAdJoin(breakToPlay, nowMs).catch(function(error) {
6490
+ void this.handleVmapAdBreak(breakToPlay, nowMs).catch(function(error) {
6276
6491
  if (_this.config.debugAdTiming) {
6277
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP join failed gracefully:", error);
6492
+ console.warn("[StormcloudVideoPlayer] VMAP ad break failed gracefully:", error);
6278
6493
  }
6279
6494
  });
6280
6495
  }
6281
6496
  }
6282
6497
  },
6283
6498
  {
6284
- key: "handleMidAdJoin",
6285
- value: function handleMidAdJoin(adBreak, nowMs) {
6499
+ key: "onVideoEnded",
6500
+ value: function onVideoEnded() {
6501
+ var _this = this;
6502
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
6503
+ return;
6504
+ }
6505
+ if (this.adPlayer.isAdPlaying() || this.inAdBreak) {
6506
+ return;
6507
+ }
6508
+ var durationMs = Number.isFinite(this.video.duration) ? Math.floor(this.video.duration * 1e3) : 0;
6509
+ var postroll = this.vmapBreaks.find(function(b) {
6510
+ return b.startTimeMs === -1 && !_this.consumedVmapBreakIds.has(_this.getAdBreakKey(b));
6511
+ });
6512
+ if (postroll) {
6513
+ void this.handleVmapAdBreak(postroll, durationMs).catch(function(error) {
6514
+ if (_this.config.debugAdTiming) {
6515
+ console.warn("[StormcloudVideoPlayer] VMAP post-roll failed gracefully:", error);
6516
+ }
6517
+ });
6518
+ }
6519
+ }
6520
+ },
6521
+ {
6522
+ key: "handleVmapAdBreak",
6523
+ value: function handleVmapAdBreak(adBreak, nowMs) {
6286
6524
  return _async_to_generator(function() {
6287
- var _adBreak_durationMs, _this_config_driftToleranceMs, key, breakStartMs, durationMs, endMs, tol, inWindow, remainingMs, tags, first, rest, error;
6525
+ var _adBreak_durationMs, key, breakStartMs, durationMs, endMs, inWindow, tags, first, rest, error;
6288
6526
  return _ts_generator(this, function(_state) {
6289
6527
  switch(_state.label){
6290
6528
  case 0:
@@ -6302,25 +6540,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6302
6540
  }
6303
6541
  durationMs = (_adBreak_durationMs = adBreak.durationMs) !== null && _adBreak_durationMs !== void 0 ? _adBreak_durationMs : 0;
6304
6542
  endMs = breakStartMs + durationMs;
6305
- tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6306
- inWindow = durationMs > 0 ? nowMs > breakStartMs && nowMs < endMs : nowMs + tol >= breakStartMs;
6543
+ inWindow = durationMs > 0 ? nowMs >= breakStartMs && nowMs < endMs : nowMs >= breakStartMs;
6307
6544
  if (!inWindow) return [
6308
6545
  3,
6309
6546
  4
6310
6547
  ];
6311
6548
  this.consumedVmapBreakIds.add(key);
6312
- remainingMs = durationMs > 0 ? Math.max(0, endMs - nowMs) : 0;
6313
- tags = this.selectVastTagsForBreak(adBreak) || (this.apiVastTagUrl ? [
6314
- this.apiVastTagUrl
6315
- ] : void 0);
6316
- if (!(tags && tags.length > 0)) return [
6317
- 3,
6318
- 4
6319
- ];
6549
+ tags = this.selectVastTagsForBreak(adBreak);
6550
+ if (!tags || tags.length === 0) {
6551
+ return [
6552
+ 2
6553
+ ];
6554
+ }
6320
6555
  first = tags[0];
6321
6556
  rest = tags.slice(1);
6322
6557
  this.adPodQueue = rest;
6323
6558
  this.adPlayer.updateOriginalMutedState(this.video.muted, this.video.volume);
6559
+ this.showAds = true;
6560
+ this.inAdBreak = true;
6561
+ this.currentAdBreakStartWallClockMs = Date.now();
6562
+ if (!this.video.paused) {
6563
+ this.video.pause();
6564
+ }
6324
6565
  _state.label = 1;
6325
6566
  case 1:
6326
6567
  _state.trys.push([
@@ -6335,10 +6576,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6335
6576
  ];
6336
6577
  case 2:
6337
6578
  _state.sent();
6338
- this.inAdBreak = true;
6339
- this.expectedAdBreakDurationMs = remainingMs;
6340
- this.currentAdBreakStartWallClockMs = Date.now();
6341
- this.scheduleAdStopCountdown(remainingMs);
6342
6579
  return [
6343
6580
  3,
6344
6581
  4
@@ -6346,8 +6583,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6346
6583
  case 3:
6347
6584
  error = _state.sent();
6348
6585
  this.adPodQueue = [];
6586
+ this.inAdBreak = false;
6587
+ this.showAds = false;
6349
6588
  if (this.config.debugAdTiming) {
6350
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP ad request failed:", error);
6589
+ console.warn("[StormcloudVideoPlayer] VMAP ad request failed:", error);
6351
6590
  }
6352
6591
  return [
6353
6592
  3,
@@ -7059,9 +7298,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7059
7298
  {
7060
7299
  key: "findBreakForTime",
7061
7300
  value: function findBreakForTime(nowMs) {
7062
- var _this_config_driftToleranceMs;
7063
7301
  var schedule = this.vmapBreaks;
7064
- var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
7065
7302
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
7066
7303
  try {
7067
7304
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
@@ -7073,9 +7310,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7073
7310
  if (breakStartMs == null) {
7074
7311
  continue;
7075
7312
  }
7076
- var end = breakStartMs + (b.durationMs || 0);
7077
- var effectiveTol = breakStartMs === 0 ? Math.max(tol, 3e4) : tol;
7078
- if (nowMs >= breakStartMs && (b.durationMs ? nowMs < end : nowMs <= breakStartMs + effectiveTol)) {
7313
+ if (b.durationMs) {
7314
+ var end = breakStartMs + b.durationMs;
7315
+ if (nowMs >= breakStartMs && nowMs < end) {
7316
+ return b;
7317
+ }
7318
+ continue;
7319
+ }
7320
+ if (nowMs >= breakStartMs) {
7079
7321
  return b;
7080
7322
  }
7081
7323
  }
@@ -7283,6 +7525,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7283
7525
  this.video.removeEventListener("timeupdate", this.timeUpdateHandler);
7284
7526
  delete this.timeUpdateHandler;
7285
7527
  }
7528
+ if (this.endedHandler) {
7529
+ this.video.removeEventListener("ended", this.endedHandler);
7530
+ delete this.endedHandler;
7531
+ }
7286
7532
  if (this.emptiedHandler) {
7287
7533
  this.video.removeEventListener("emptied", this.emptiedHandler);
7288
7534
  delete this.emptiedHandler;