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.
@@ -1333,6 +1333,99 @@ function createPalNonceManager() {
1333
1333
  }
1334
1334
  };
1335
1335
  }
1336
+ // src/utils/mqttConfig.ts
1337
+ var DEFAULT_MQTT_CONFIG = {
1338
+ enabled: true,
1339
+ brokerAddress: "vecbae77.ala.us-east-1.emqxsl.com",
1340
+ brokerPort: 8883,
1341
+ wsPort: 8084,
1342
+ username: "for-sonifi",
1343
+ password: "sonifi-mqtt",
1344
+ topicPrefix: "adstorm/players",
1345
+ qos: 1
1346
+ };
1347
+ var mqttConfig = _object_spread({}, DEFAULT_MQTT_CONFIG);
1348
+ function isMQTTEnabled() {
1349
+ return mqttConfig.enabled;
1350
+ }
1351
+ function buildMQTTBrokerUrl() {
1352
+ if (mqttConfig.brokerUrl) return mqttConfig.brokerUrl;
1353
+ return "wss://".concat(mqttConfig.brokerAddress, ":").concat(mqttConfig.wsPort, "/mqtt");
1354
+ }
1355
+ function buildPlayerTopic(licenseKey, channel) {
1356
+ return "".concat(mqttConfig.topicPrefix, "/").concat(licenseKey, "/").concat(channel);
1357
+ }
1358
+ // src/utils/mqttClient.ts
1359
+ var import_mqtt = __toESM(require("mqtt"), 1);
1360
+ var LOG = "[StormcloudVideoPlayer][MQTT]";
1361
+ var client = null;
1362
+ var status = "disconnected";
1363
+ function initMQTTClient() {
1364
+ if (client || !isMQTTEnabled()) return;
1365
+ var url = buildMQTTBrokerUrl();
1366
+ status = "connecting";
1367
+ var clientId = "stormcloud-vp-".concat(Math.random().toString(36).slice(2, 9));
1368
+ try {
1369
+ client = import_mqtt.default.connect(url, {
1370
+ clientId: clientId,
1371
+ username: mqttConfig.username,
1372
+ password: mqttConfig.password,
1373
+ keepalive: 60,
1374
+ clean: true,
1375
+ reconnectPeriod: 5e3,
1376
+ connectTimeout: 1e4,
1377
+ queueQoSZero: false
1378
+ });
1379
+ } catch (err) {
1380
+ status = "error";
1381
+ console.warn("".concat(LOG, " connect() threw:"), err);
1382
+ return;
1383
+ }
1384
+ client.on("connect", function() {
1385
+ status = "connected";
1386
+ console.info("".concat(LOG, " connected to ").concat(url));
1387
+ });
1388
+ client.on("reconnect", function() {
1389
+ status = "connecting";
1390
+ console.info("".concat(LOG, " reconnecting…"));
1391
+ });
1392
+ client.on("offline", function() {
1393
+ status = "disconnected";
1394
+ console.warn("".concat(LOG, " offline"));
1395
+ });
1396
+ client.on("error", function(err) {
1397
+ status = "error";
1398
+ console.warn("".concat(LOG, " error:"), err.message);
1399
+ });
1400
+ client.on("close", function() {
1401
+ if (status === "connected") {
1402
+ status = "disconnected";
1403
+ }
1404
+ });
1405
+ }
1406
+ function ensureMQTTClient() {
1407
+ if (isMQTTEnabled() && !client) {
1408
+ initMQTTClient();
1409
+ }
1410
+ }
1411
+ function publishMQTT(topic, payload) {
1412
+ if (!isMQTTEnabled()) {
1413
+ return false;
1414
+ }
1415
+ ensureMQTTClient();
1416
+ if (!client) {
1417
+ return false;
1418
+ }
1419
+ try {
1420
+ client.publish(topic, JSON.stringify(payload), {
1421
+ qos: mqttConfig.qos
1422
+ });
1423
+ return true;
1424
+ } catch (err) {
1425
+ console.warn("".concat(LOG, " publish failed on ").concat(topic, ":"), err);
1426
+ return false;
1427
+ }
1428
+ }
1336
1429
  // src/utils/tracking.ts
1337
1430
  var cachedBrowserId = null;
1338
1431
  function getClientInfo() {
@@ -1479,7 +1572,7 @@ function getClientInfo() {
1479
1572
  }
1480
1573
  function getBrowserID(clientInfo) {
1481
1574
  return _async_to_generator(function() {
1482
- var fingerprintString, encodedData, utf8, buffer, i, hashBuffer, hashArray, hashHex, error, hash, i1, char, fallbackHash, timestamp, random;
1575
+ var _crypto_subtle, fingerprintString, encodedData, utf8, buffer, i, hashBuffer, hashHex, unused, hash, i1, char, fallbackHash, timestamp, random;
1483
1576
  return _ts_generator(this, function(_state) {
1484
1577
  switch(_state.label){
1485
1578
  case 0:
@@ -1490,7 +1583,7 @@ function getBrowserID(clientInfo) {
1490
1583
  ];
1491
1584
  }
1492
1585
  fingerprintString = JSON.stringify(clientInfo);
1493
- if (!(typeof crypto !== "undefined" && crypto.subtle && crypto.subtle.digest)) return [
1586
+ if (!(typeof crypto !== "undefined" && ((_crypto_subtle = crypto.subtle) === null || _crypto_subtle === void 0 ? void 0 : _crypto_subtle.digest))) return [
1494
1587
  3,
1495
1588
  5
1496
1589
  ];
@@ -1528,8 +1621,7 @@ function getBrowserID(clientInfo) {
1528
1621
  ];
1529
1622
  case 3:
1530
1623
  hashBuffer = _state.sent();
1531
- hashArray = Array.from(new Uint8Array(hashBuffer));
1532
- hashHex = hashArray.map(function(b) {
1624
+ hashHex = Array.from(new Uint8Array(hashBuffer)).map(function(b) {
1533
1625
  return b.toString(16).padStart(2, "0");
1534
1626
  }).join("");
1535
1627
  cachedBrowserId = hashHex;
@@ -1538,8 +1630,8 @@ function getBrowserID(clientInfo) {
1538
1630
  hashHex
1539
1631
  ];
1540
1632
  case 4:
1541
- error = _state.sent();
1542
- console.warn("[StormcloudVideoPlayer] crypto.subtle.digest not supported, using fallback hash");
1633
+ unused = _state.sent();
1634
+ console.warn("[StormcloudVideoPlayer] crypto.subtle not supported, using fallback hash");
1543
1635
  return [
1544
1636
  3,
1545
1637
  5
@@ -1563,177 +1655,91 @@ function getBrowserID(clientInfo) {
1563
1655
  });
1564
1656
  })();
1565
1657
  }
1566
- var PLAYER_TRACKING_BASE_URL = "https://adstorm.co/api-adstorm-dev/adstorm/player-tracking";
1567
- var TRACK_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/metrics/ingest");
1568
- var HEARTBEAT_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/heartbeat");
1569
- var IMPRESSIONS_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/impressions/ingest");
1570
- function buildHeaders(licenseKey) {
1571
- var headers = {
1572
- "Content-Type": "application/json"
1573
- };
1574
- if (licenseKey) {
1575
- headers["Authorization"] = "Bearer ".concat(licenseKey);
1576
- }
1577
- return headers;
1578
- }
1579
- function sendTrackRequest(licenseKey, body) {
1580
- return _async_to_generator(function() {
1581
- var response;
1582
- return _ts_generator(this, function(_state) {
1583
- switch(_state.label){
1584
- case 0:
1585
- return [
1586
- 4,
1587
- fetch(TRACK_URL, {
1588
- method: "POST",
1589
- headers: buildHeaders(licenseKey),
1590
- body: JSON.stringify(body)
1591
- })
1592
- ];
1593
- case 1:
1594
- response = _state.sent();
1595
- if (!response.ok) {
1596
- throw new Error("HTTP error! status: ".concat(response.status));
1597
- }
1598
- return [
1599
- 4,
1600
- response.json()
1601
- ];
1602
- case 2:
1603
- _state.sent();
1604
- return [
1605
- 2
1606
- ];
1607
- }
1608
- });
1609
- })();
1658
+ function canPublish(licenseKey) {
1659
+ return Boolean(isMQTTEnabled() && licenseKey);
1610
1660
  }
1611
- function postJson(url, licenseKey, body) {
1661
+ function buildPlayerMetricEvent() {
1612
1662
  return _async_to_generator(function() {
1613
- var response;
1614
- return _ts_generator(this, function(_state) {
1615
- switch(_state.label){
1616
- case 0:
1617
- return [
1618
- 4,
1619
- fetch(url, {
1620
- method: "POST",
1621
- headers: buildHeaders(licenseKey),
1622
- body: JSON.stringify(body)
1623
- })
1624
- ];
1625
- case 1:
1626
- response = _state.sent();
1627
- if (!response.ok) {
1628
- throw new Error("HTTP error! status: ".concat(response.status));
1629
- }
1630
- return [
1631
- 4,
1632
- response.json()
1633
- ];
1634
- case 2:
1635
- _state.sent();
1636
- return [
1637
- 2
1638
- ];
1639
- }
1640
- });
1641
- })();
1642
- }
1643
- function buildPlayerMetricEvent(_0) {
1644
- return _async_to_generator(function(licenseKey) {
1645
- var context, flags, _flags_captureAt, clientInfo, browserId, captureAt;
1663
+ var context, flags, _flags_captureAt, _flags_adLoaded, _flags_adDetect, clientInfo, playerId, captureAt;
1646
1664
  var _arguments = arguments;
1647
1665
  return _ts_generator(this, function(_state) {
1648
1666
  switch(_state.label){
1649
1667
  case 0:
1650
- context = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {}, flags = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : {};
1668
+ context = _arguments.length > 0 && _arguments[0] !== void 0 ? _arguments[0] : {}, flags = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {};
1651
1669
  clientInfo = getClientInfo();
1652
1670
  return [
1653
1671
  4,
1654
1672
  getBrowserID(clientInfo)
1655
1673
  ];
1656
1674
  case 1:
1657
- browserId = _state.sent();
1675
+ playerId = _state.sent();
1658
1676
  captureAt = (_flags_captureAt = flags.captureAt) !== null && _flags_captureAt !== void 0 ? _flags_captureAt : /* @__PURE__ */ new Date().toISOString();
1659
1677
  return [
1660
1678
  2,
1661
- {
1662
- player_id: browserId,
1663
- browserId: browserId,
1679
+ _object_spread({
1680
+ player_id: playerId,
1664
1681
  device_type: clientInfo.deviceType,
1665
- deviceType: clientInfo.deviceType,
1666
- input_stream_type: context.inputStreamType,
1667
- os: clientInfo.os,
1668
- ad_loaded: flags.adLoaded,
1669
- ad_detect: flags.adDetect,
1670
- license_key: licenseKey,
1671
- capture_at: captureAt,
1672
- timestamp: captureAt
1673
- }
1682
+ os: clientInfo.os.toLowerCase(),
1683
+ ad_loaded: (_flags_adLoaded = flags.adLoaded) !== null && _flags_adLoaded !== void 0 ? _flags_adLoaded : false,
1684
+ ad_detect: (_flags_adDetect = flags.adDetect) !== null && _flags_adDetect !== void 0 ? _flags_adDetect : false,
1685
+ capture_at: captureAt
1686
+ }, context.inputStreamType ? {
1687
+ input_stream_type: context.inputStreamType
1688
+ } : {})
1674
1689
  ];
1675
1690
  }
1676
1691
  });
1677
1692
  }).apply(this, arguments);
1678
1693
  }
1694
+ function publishTracking(licenseKey, channel, body) {
1695
+ ensureMQTTClient();
1696
+ publishMQTT(buildPlayerTopic(licenseKey, channel), body);
1697
+ }
1679
1698
  function sendInitialTracking(_0) {
1680
1699
  return _async_to_generator(function(licenseKey) {
1681
- var context, clientInfo, browserId, trackingData, error;
1700
+ var context, metricEvent, error;
1682
1701
  var _arguments = arguments;
1683
1702
  return _ts_generator(this, function(_state) {
1684
1703
  switch(_state.label){
1685
1704
  case 0:
1686
1705
  context = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {};
1706
+ if (!canPublish(licenseKey)) return [
1707
+ 2
1708
+ ];
1687
1709
  _state.label = 1;
1688
1710
  case 1:
1689
1711
  _state.trys.push([
1690
1712
  1,
1691
- 4,
1713
+ 3,
1692
1714
  ,
1693
- 5
1715
+ 4
1694
1716
  ]);
1695
- clientInfo = getClientInfo();
1696
- return [
1697
- 4,
1698
- getBrowserID(clientInfo)
1699
- ];
1700
- case 2:
1701
- browserId = _state.sent();
1702
- trackingData = _object_spread({
1703
- browserId: browserId
1704
- }, clientInfo);
1705
1717
  return [
1706
1718
  4,
1707
- sendTrackRequest(licenseKey, {
1708
- events: [
1709
- {
1710
- player_id: browserId,
1711
- device_type: clientInfo.deviceType,
1712
- input_stream_type: context.inputStreamType,
1713
- os: clientInfo.os,
1714
- ad_loaded: false,
1715
- ad_detect: false,
1716
- license_key: licenseKey,
1717
- capture_at: /* @__PURE__ */ new Date().toISOString()
1718
- }
1719
- ],
1720
- trackingData: trackingData
1719
+ buildPlayerMetricEvent(context, {
1720
+ adLoaded: false,
1721
+ adDetect: false
1721
1722
  })
1722
1723
  ];
1723
- case 3:
1724
- _state.sent();
1724
+ case 2:
1725
+ metricEvent = _state.sent();
1726
+ publishTracking(licenseKey, "metrics", {
1727
+ events: [
1728
+ metricEvent
1729
+ ]
1730
+ });
1725
1731
  return [
1726
1732
  3,
1727
- 5
1733
+ 4
1728
1734
  ];
1729
- case 4:
1735
+ case 3:
1730
1736
  error = _state.sent();
1731
1737
  console.error("[StormcloudVideoPlayer] Error sending initial tracking data:", error);
1732
1738
  return [
1733
1739
  3,
1734
- 5
1740
+ 4
1735
1741
  ];
1736
- case 5:
1742
+ case 4:
1737
1743
  return [
1738
1744
  2
1739
1745
  ];
@@ -1837,53 +1843,48 @@ function sendAdImpressionTracking(_0, _1) {
1837
1843
  switch(_state.label){
1838
1844
  case 0:
1839
1845
  context = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : {};
1846
+ if (!canPublish(licenseKey)) return [
1847
+ 2
1848
+ ];
1840
1849
  _state.label = 1;
1841
1850
  case 1:
1842
1851
  _state.trys.push([
1843
1852
  1,
1844
- 4,
1853
+ 3,
1845
1854
  ,
1846
- 5
1855
+ 4
1847
1856
  ]);
1848
1857
  return [
1849
1858
  4,
1850
- buildPlayerMetricEvent(licenseKey, context, {
1859
+ buildPlayerMetricEvent(context, {
1851
1860
  captureAt: adImpressionInfo.timestamp
1852
1861
  })
1853
1862
  ];
1854
1863
  case 2:
1855
1864
  metricEvent = _state.sent();
1856
- return [
1857
- 4,
1858
- Promise.all([
1859
- postJson(HEARTBEAT_URL, licenseKey, metricEvent),
1860
- postJson(IMPRESSIONS_URL, licenseKey, {
1861
- events: [
1862
- {
1863
- player_id: metricEvent.player_id,
1864
- ad_played_count: 1,
1865
- ad_url: adImpressionInfo.adUrl,
1866
- license_key: licenseKey,
1867
- capture_at: adImpressionInfo.timestamp
1868
- }
1869
- ]
1870
- })
1871
- ])
1872
- ];
1873
- case 3:
1874
- _state.sent();
1865
+ publishTracking(licenseKey, "heartbeat", metricEvent);
1866
+ publishTracking(licenseKey, "impressions", {
1867
+ events: [
1868
+ {
1869
+ player_id: metricEvent.player_id,
1870
+ ad_played_count: 1,
1871
+ ad_url: adImpressionInfo.adUrl,
1872
+ capture_at: adImpressionInfo.timestamp
1873
+ }
1874
+ ]
1875
+ });
1875
1876
  return [
1876
1877
  3,
1877
- 5
1878
+ 4
1878
1879
  ];
1879
- case 4:
1880
+ case 3:
1880
1881
  error = _state.sent();
1881
1882
  console.error("[StormcloudVideoPlayer] Error sending ad impression tracking:", error);
1882
1883
  return [
1883
1884
  3,
1884
- 5
1885
+ 4
1885
1886
  ];
1886
- case 5:
1887
+ case 4:
1887
1888
  return [
1888
1889
  2
1889
1890
  ];
@@ -1899,38 +1900,36 @@ function sendHeartbeat(_0) {
1899
1900
  switch(_state.label){
1900
1901
  case 0:
1901
1902
  context = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {}, flags = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : {};
1903
+ if (!canPublish(licenseKey)) return [
1904
+ 2
1905
+ ];
1902
1906
  _state.label = 1;
1903
1907
  case 1:
1904
1908
  _state.trys.push([
1905
1909
  1,
1906
- 4,
1910
+ 3,
1907
1911
  ,
1908
- 5
1912
+ 4
1909
1913
  ]);
1910
1914
  return [
1911
1915
  4,
1912
- buildPlayerMetricEvent(licenseKey, context, flags)
1916
+ buildPlayerMetricEvent(context, flags)
1913
1917
  ];
1914
1918
  case 2:
1915
1919
  heartbeatData = _state.sent();
1916
- return [
1917
- 4,
1918
- postJson(HEARTBEAT_URL, licenseKey, heartbeatData)
1919
- ];
1920
- case 3:
1921
- _state.sent();
1920
+ publishTracking(licenseKey, "heartbeat", heartbeatData);
1922
1921
  return [
1923
1922
  3,
1924
- 5
1923
+ 4
1925
1924
  ];
1926
- case 4:
1925
+ case 3:
1927
1926
  error = _state.sent();
1928
1927
  console.error("[StormcloudVideoPlayer] Error sending heartbeat:", error);
1929
1928
  return [
1930
1929
  3,
1931
- 5
1930
+ 4
1932
1931
  ];
1933
- case 5:
1932
+ case 4:
1934
1933
  return [
1935
1934
  2
1936
1935
  ];
@@ -2189,6 +2188,166 @@ function initializePolyfills() {
2189
2188
  polyfillTextEncoder();
2190
2189
  polyfillPromiseFinally();
2191
2190
  }
2191
+ // src/utils/vastMacros.ts
2192
+ function generateCorrelator() {
2193
+ if (typeof crypto !== "undefined" && crypto.getRandomValues) {
2194
+ try {
2195
+ var _buf_, _buf_1;
2196
+ var buf = new Uint32Array(2);
2197
+ crypto.getRandomValues(buf);
2198
+ 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);
2199
+ if (value > 0) {
2200
+ return String(value);
2201
+ }
2202
+ } catch (unused) {}
2203
+ }
2204
+ return String(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER) + 1);
2205
+ }
2206
+ var UNEXPANDED_MACRO_PATTERN = /^(\[[^\]]*\]|\{[^}]*\}|%%[^%]*%%)$/;
2207
+ function applyVastMacros(baseUrl, ctx) {
2208
+ var url;
2209
+ try {
2210
+ url = new URL(baseUrl);
2211
+ } catch (unused) {
2212
+ return replaceCorrelatorFallback(baseUrl, ctx.correlator);
2213
+ }
2214
+ var params = url.searchParams;
2215
+ params.set("correlator", ctx.correlator);
2216
+ params.set("scor", ctx.streamCorrelator);
2217
+ if (ctx.pod != null) {
2218
+ params.set("pod", String(ctx.pod));
2219
+ }
2220
+ if (ctx.adPosition != null) {
2221
+ params.set("ppos", String(ctx.adPosition));
2222
+ }
2223
+ if (ctx.pageUrl) {
2224
+ params.set("url", ctx.pageUrl);
2225
+ params.set("description_url", ctx.pageUrl);
2226
+ }
2227
+ if (ctx.adWillPlayMuted != null) {
2228
+ params.set("vpmute", ctx.adWillPlayMuted ? "1" : "0");
2229
+ }
2230
+ if (ctx.adWillAutoPlay != null) {
2231
+ params.set("vpa", ctx.adWillAutoPlay ? "auto" : "click");
2232
+ }
2233
+ if (ctx.deviceId && ctx.deviceIdType) {
2234
+ params.set("rdid", ctx.deviceId);
2235
+ params.set("idtype", ctx.deviceIdType);
2236
+ params.set("is_lat", ctx.limitAdTracking ? "1" : "0");
2237
+ } else {
2238
+ params.delete("rdid");
2239
+ params.delete("idtype");
2240
+ params.delete("is_lat");
2241
+ }
2242
+ var consent = ctx.consent;
2243
+ if ((consent === null || consent === void 0 ? void 0 : consent.gdpr) != null) {
2244
+ params.set("gdpr", consent.gdpr);
2245
+ }
2246
+ if ((consent === null || consent === void 0 ? void 0 : consent.gdprConsent) != null) {
2247
+ params.set("gdpr_consent", consent.gdprConsent);
2248
+ }
2249
+ if ((consent === null || consent === void 0 ? void 0 : consent.usPrivacy) != null) {
2250
+ params.set("us_privacy", consent.usPrivacy);
2251
+ }
2252
+ if (ctx.adTest) {
2253
+ params.set("adtest", "on");
2254
+ }
2255
+ var staleKeys = [];
2256
+ params.forEach(function(value, key) {
2257
+ if (UNEXPANDED_MACRO_PATTERN.test(value)) {
2258
+ staleKeys.push(key);
2259
+ }
2260
+ });
2261
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2262
+ try {
2263
+ for(var _iterator = staleKeys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2264
+ var key = _step.value;
2265
+ params.delete(key);
2266
+ }
2267
+ } catch (err) {
2268
+ _didIteratorError = true;
2269
+ _iteratorError = err;
2270
+ } finally{
2271
+ try {
2272
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2273
+ _iterator.return();
2274
+ }
2275
+ } finally{
2276
+ if (_didIteratorError) {
2277
+ throw _iteratorError;
2278
+ }
2279
+ }
2280
+ }
2281
+ return url.toString();
2282
+ }
2283
+ function replaceCorrelatorFallback(baseUrl, correlator) {
2284
+ var correlatorRegex = /([?&])correlator=([^&]*)/;
2285
+ if (correlatorRegex.test(baseUrl)) {
2286
+ return baseUrl.replace(correlatorRegex, "$1correlator=".concat(correlator));
2287
+ }
2288
+ var sep = baseUrl.includes("?") ? "&" : "?";
2289
+ return "".concat(baseUrl).concat(sep, "correlator=").concat(correlator);
2290
+ }
2291
+ function fetchConsentSignals() {
2292
+ var timeoutMs = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : 1500;
2293
+ var signals = {};
2294
+ if (typeof window === "undefined") {
2295
+ return Promise.resolve(signals);
2296
+ }
2297
+ var tasks = [];
2298
+ var tcfApi = window.__tcfapi;
2299
+ if (typeof tcfApi === "function") {
2300
+ tasks.push(new Promise(function(resolve) {
2301
+ var settled = false;
2302
+ try {
2303
+ tcfApi("addEventListener", 2, function(tcData, success) {
2304
+ if (settled) return;
2305
+ if (success && tcData && (tcData.eventStatus === "tcloaded" || tcData.eventStatus === "useractioncomplete")) {
2306
+ settled = true;
2307
+ signals.gdpr = tcData.gdprApplies ? "1" : "0";
2308
+ if (typeof tcData.tcString === "string" && tcData.tcString) {
2309
+ signals.gdprConsent = tcData.tcString;
2310
+ }
2311
+ try {
2312
+ tcfApi("removeEventListener", 2, function() {}, tcData.listenerId);
2313
+ } catch (unused) {}
2314
+ resolve();
2315
+ }
2316
+ });
2317
+ } catch (unused) {
2318
+ resolve();
2319
+ }
2320
+ setTimeout(function() {
2321
+ if (!settled) {
2322
+ settled = true;
2323
+ resolve();
2324
+ }
2325
+ }, timeoutMs);
2326
+ }));
2327
+ }
2328
+ var uspApi = window.__uspapi;
2329
+ if (typeof uspApi === "function") {
2330
+ tasks.push(new Promise(function(resolve) {
2331
+ try {
2332
+ uspApi("getUSPData", 1, function(data, success) {
2333
+ if (success && typeof (data === null || data === void 0 ? void 0 : data.uspString) === "string" && data.uspString) {
2334
+ signals.usPrivacy = data.uspString;
2335
+ }
2336
+ resolve();
2337
+ });
2338
+ } catch (unused) {
2339
+ resolve();
2340
+ }
2341
+ setTimeout(resolve, timeoutMs);
2342
+ }));
2343
+ }
2344
+ if (tasks.length === 0) {
2345
+ return Promise.resolve(signals);
2346
+ }
2347
+ return Promise.all(tasks).then(function() {
2348
+ return signals;
2349
+ });
2350
+ }
2192
2351
  // src/utils/browserCompat.ts
2193
2352
  function getChromeVersion(ua) {
2194
2353
  var match = ua.match(/Chrome\/(\d+)/);
@@ -2414,6 +2573,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2414
2573
  this.preloadPoolLoopRunning = false;
2415
2574
  this.adDetectSentForCurrentBreak = false;
2416
2575
  this.palPlaybackStarted = false;
2576
+ this.streamCorrelator = generateCorrelator();
2577
+ this.consentSignals = {};
2578
+ this.podCounter = 0;
2579
+ this.podAssignedByPrefetch = false;
2580
+ this.adRequestPositionInBreak = 0;
2417
2581
  this.continuousFetchLoopRunning = false;
2418
2582
  initializePolyfills();
2419
2583
  var browserOverrides = getBrowserConfigOverrides();
@@ -2486,6 +2650,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2486
2650
  adWillPlayMuted: !!this.config.muted,
2487
2651
  continuousPlayback: (_this_config_lowLatencyMode = this.config.lowLatencyMode) !== null && _this_config_lowLatencyMode !== void 0 ? _this_config_lowLatencyMode : false
2488
2652
  }).catch(function() {});
2653
+ fetchConsentSignals().then(function(signals) {
2654
+ _this.consentSignals = signals;
2655
+ }).catch(function() {});
2489
2656
  this.initializeTracking();
2490
2657
  if (!this.shouldUseNativeHls()) return [
2491
2658
  3,
@@ -2553,7 +2720,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2553
2720
  var _level_details, _level_details1;
2554
2721
  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";
2555
2722
  })) !== null && _ref !== void 0 ? _ref : false;
2556
- if (!this.isLiveStream && this.vmapBreaks.length === 0 && this.apiVastTagUrl) {
2723
+ if (!this.isVmapEnabled() && !this.isLiveStream && this.vmapBreaks.length === 0 && this.apiVastTagUrl) {
2557
2724
  prerollKey = "synthetic-vod-preroll";
2558
2725
  if (!this.consumedVmapBreakIds.has(prerollKey)) {
2559
2726
  this.vmapBreaks = [
@@ -3138,12 +3305,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3138
3305
  _this.palNonce.sendPlaybackStart();
3139
3306
  }
3140
3307
  });
3141
- this.video.addEventListener("ended", function() {
3308
+ this.endedHandler = function() {
3142
3309
  if (_this.palPlaybackStarted) {
3143
3310
  _this.palPlaybackStarted = false;
3144
3311
  _this.palNonce.sendPlaybackEnd();
3145
3312
  }
3146
- });
3313
+ _this.onVideoEnded();
3314
+ };
3315
+ this.video.addEventListener("ended", this.endedHandler);
3147
3316
  this.video.addEventListener("mousedown", function(e) {
3148
3317
  _this.palNonce.sendAdTouch(e);
3149
3318
  });
@@ -4465,6 +4634,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4465
4634
  }
4466
4635
  }
4467
4636
  },
4637
+ {
4638
+ key: "isVmapEnabled",
4639
+ value: function isVmapEnabled() {
4640
+ var _this_config_vmapUrl;
4641
+ return !!(this.config.isVmap && ((_this_config_vmapUrl = this.config.vmapUrl) === null || _this_config_vmapUrl === void 0 ? void 0 : _this_config_vmapUrl.trim()));
4642
+ }
4643
+ },
4468
4644
  {
4469
4645
  key: "fetchAdConfiguration",
4470
4646
  value: function fetchAdConfiguration() {
@@ -4473,7 +4649,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4473
4649
  return _ts_generator(this, function(_state) {
4474
4650
  switch(_state.label){
4475
4651
  case 0:
4476
- if (!this.config.vmapUrl) return [
4652
+ if (!this.isVmapEnabled()) return [
4477
4653
  3,
4478
4654
  2
4479
4655
  ];
@@ -4483,7 +4659,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4483
4659
  ];
4484
4660
  case 1:
4485
4661
  _state.sent();
4486
- _state.label = 2;
4662
+ if (this.config.debugAdTiming) {
4663
+ console.log("[StormcloudVideoPlayer] VMAP mode enabled");
4664
+ }
4665
+ return [
4666
+ 2
4667
+ ];
4487
4668
  case 2:
4488
4669
  vastMode = this.config.vastMode || "default";
4489
4670
  if (this.config.debugAdTiming) {
@@ -4651,7 +4832,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4651
4832
  }
4652
4833
  return [];
4653
4834
  }
4654
- var adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
4835
+ var VMAP_NS = "http://www.iab.net/videosuite/vmap";
4836
+ var adBreakNodes = Array.from(doc.getElementsByTagNameNS(VMAP_NS, "AdBreak"));
4837
+ if (adBreakNodes.length === 0) {
4838
+ adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
4839
+ }
4840
+ if (adBreakNodes.length === 0) {
4841
+ adBreakNodes = Array.from(doc.getElementsByTagName("*")).filter(function(el) {
4842
+ return el.localName === "AdBreak";
4843
+ });
4844
+ }
4655
4845
  var parsed = [];
4656
4846
  adBreakNodes.forEach(function(node, index) {
4657
4847
  var timeOffsetRaw = (node.getAttribute("timeOffset") || "").trim();
@@ -4659,7 +4849,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4659
4849
  if (startTimeMs == null) {
4660
4850
  return;
4661
4851
  }
4662
- var adTagNode = node.querySelector("AdTagURI, vmap\\:AdTagURI");
4852
+ var adTagNode = node.getElementsByTagNameNS(VMAP_NS, "AdTagURI")[0];
4853
+ if (!adTagNode) {
4854
+ var _node_querySelector;
4855
+ adTagNode = (_node_querySelector = node.querySelector("AdTagURI, vmap\\:AdTagURI")) !== null && _node_querySelector !== void 0 ? _node_querySelector : void 0;
4856
+ }
4663
4857
  var adTagUrl = ((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim();
4664
4858
  if (!adTagUrl) {
4665
4859
  return;
@@ -4755,25 +4949,35 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4755
4949
  return this.getRemainingAdMs();
4756
4950
  }
4757
4951
  },
4952
+ {
4953
+ key: "beginNewAdPod",
4954
+ value: function beginNewAdPod() {
4955
+ this.podCounter++;
4956
+ this.adRequestPositionInBreak = 0;
4957
+ }
4958
+ },
4758
4959
  {
4759
4960
  key: "generateVastUrlsWithCorrelators",
4760
4961
  value: function generateVastUrlsWithCorrelators(baseUrl, count) {
4761
4962
  var urls = [];
4762
- var baseTimestamp = Date.now();
4763
4963
  for(var i = 0; i < count; i++){
4764
- var timestamp = baseTimestamp + i;
4765
- var random = Math.floor(Math.random() * 1e12);
4766
- var uniqueCorrelator = "".concat(timestamp, "_").concat(random, "_").concat(i);
4767
- var urlWithCorrelator = void 0;
4768
- var correlatorRegex = /([?&])correlator=([^&]*)/;
4769
- if (correlatorRegex.test(baseUrl)) {
4770
- urlWithCorrelator = baseUrl.replace(correlatorRegex, "$1correlator=".concat(uniqueCorrelator));
4771
- } else if (baseUrl.includes("?")) {
4772
- urlWithCorrelator = "".concat(baseUrl, "&correlator=").concat(uniqueCorrelator);
4773
- } else {
4774
- urlWithCorrelator = "".concat(baseUrl, "?correlator=").concat(uniqueCorrelator);
4775
- }
4776
- urls.push(this.palNonce.injectNonce(urlWithCorrelator));
4964
+ this.adRequestPositionInBreak++;
4965
+ var adWillPlayMuted = this.inAdBreak ? this.adPlayer.getOriginalMutedState() : this.video.muted;
4966
+ var urlWithMacros = applyVastMacros(baseUrl, {
4967
+ correlator: generateCorrelator(),
4968
+ streamCorrelator: this.streamCorrelator,
4969
+ pod: this.podCounter > 0 ? this.podCounter : void 0,
4970
+ adPosition: this.adRequestPositionInBreak,
4971
+ pageUrl: typeof window !== "undefined" ? window.location.href : void 0,
4972
+ adWillPlayMuted: adWillPlayMuted,
4973
+ adWillAutoPlay: !!this.config.autoplay,
4974
+ deviceId: this.config.deviceId,
4975
+ deviceIdType: this.config.deviceIdType,
4976
+ limitAdTracking: this.config.limitAdTracking,
4977
+ adTest: this.config.adTest,
4978
+ consent: this.consentSignals
4979
+ });
4980
+ urls.push(this.palNonce.injectNonce(urlWithMacros));
4777
4981
  }
4778
4982
  return urls;
4779
4983
  }
@@ -4843,6 +5047,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4843
5047
  }
4844
5048
  return;
4845
5049
  }
5050
+ this.beginNewAdPod();
5051
+ this.podAssignedByPrefetch = true;
4846
5052
  var urlsToPregenerate = 5;
4847
5053
  var generatedUrls = this.generateVastUrlsWithCorrelators(baseVastUrl, urlsToPregenerate);
4848
5054
  this.pendingAdBreak = _object_spread_props(_object_spread({
@@ -4880,6 +5086,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4880
5086
  }
4881
5087
  this.pendingAdBreak = null;
4882
5088
  this.pendingScte35CueKey = void 0;
5089
+ this.podAssignedByPrefetch = false;
4883
5090
  }
4884
5091
  },
4885
5092
  {
@@ -5316,6 +5523,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5316
5523
  this.continuousFetchingActive = true;
5317
5524
  this.isShowingPlaceholder = false;
5318
5525
  this.totalAdRequestsInBreak = 0;
5526
+ if (this.podAssignedByPrefetch) {
5527
+ this.podAssignedByPrefetch = false;
5528
+ } else {
5529
+ this.beginNewAdPod();
5530
+ }
5319
5531
  currentMuted = this.video.muted;
5320
5532
  currentVolume = this.video.volume;
5321
5533
  this.adPlayer.updateOriginalMutedState(currentMuted, currentVolume);
@@ -6216,23 +6428,49 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6216
6428
  key: "onTimeUpdate",
6217
6429
  value: function onTimeUpdate(currentTimeSec) {
6218
6430
  var _this = this;
6431
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
6432
+ return;
6433
+ }
6219
6434
  if (this.adPlayer.isAdPlaying() || this.inAdBreak) return;
6220
6435
  var nowMs = currentTimeSec * 1e3;
6221
6436
  var breakToPlay = this.findBreakForTime(nowMs);
6222
6437
  if (breakToPlay) {
6223
- void this.handleMidAdJoin(breakToPlay, nowMs).catch(function(error) {
6438
+ void this.handleVmapAdBreak(breakToPlay, nowMs).catch(function(error) {
6224
6439
  if (_this.config.debugAdTiming) {
6225
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP join failed gracefully:", error);
6440
+ console.warn("[StormcloudVideoPlayer] VMAP ad break failed gracefully:", error);
6226
6441
  }
6227
6442
  });
6228
6443
  }
6229
6444
  }
6230
6445
  },
6231
6446
  {
6232
- key: "handleMidAdJoin",
6233
- value: function handleMidAdJoin(adBreak, nowMs) {
6447
+ key: "onVideoEnded",
6448
+ value: function onVideoEnded() {
6449
+ var _this = this;
6450
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
6451
+ return;
6452
+ }
6453
+ if (this.adPlayer.isAdPlaying() || this.inAdBreak) {
6454
+ return;
6455
+ }
6456
+ var durationMs = Number.isFinite(this.video.duration) ? Math.floor(this.video.duration * 1e3) : 0;
6457
+ var postroll = this.vmapBreaks.find(function(b) {
6458
+ return b.startTimeMs === -1 && !_this.consumedVmapBreakIds.has(_this.getAdBreakKey(b));
6459
+ });
6460
+ if (postroll) {
6461
+ void this.handleVmapAdBreak(postroll, durationMs).catch(function(error) {
6462
+ if (_this.config.debugAdTiming) {
6463
+ console.warn("[StormcloudVideoPlayer] VMAP post-roll failed gracefully:", error);
6464
+ }
6465
+ });
6466
+ }
6467
+ }
6468
+ },
6469
+ {
6470
+ key: "handleVmapAdBreak",
6471
+ value: function handleVmapAdBreak(adBreak, nowMs) {
6234
6472
  return _async_to_generator(function() {
6235
- var _adBreak_durationMs, _this_config_driftToleranceMs, key, breakStartMs, durationMs, endMs, tol, inWindow, remainingMs, tags, first, rest, error;
6473
+ var _adBreak_durationMs, key, breakStartMs, durationMs, endMs, inWindow, tags, first, rest, error;
6236
6474
  return _ts_generator(this, function(_state) {
6237
6475
  switch(_state.label){
6238
6476
  case 0:
@@ -6250,25 +6488,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6250
6488
  }
6251
6489
  durationMs = (_adBreak_durationMs = adBreak.durationMs) !== null && _adBreak_durationMs !== void 0 ? _adBreak_durationMs : 0;
6252
6490
  endMs = breakStartMs + durationMs;
6253
- tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6254
- inWindow = durationMs > 0 ? nowMs > breakStartMs && nowMs < endMs : nowMs + tol >= breakStartMs;
6491
+ inWindow = durationMs > 0 ? nowMs >= breakStartMs && nowMs < endMs : nowMs >= breakStartMs;
6255
6492
  if (!inWindow) return [
6256
6493
  3,
6257
6494
  4
6258
6495
  ];
6259
6496
  this.consumedVmapBreakIds.add(key);
6260
- remainingMs = durationMs > 0 ? Math.max(0, endMs - nowMs) : 0;
6261
- tags = this.selectVastTagsForBreak(adBreak) || (this.apiVastTagUrl ? [
6262
- this.apiVastTagUrl
6263
- ] : void 0);
6264
- if (!(tags && tags.length > 0)) return [
6265
- 3,
6266
- 4
6267
- ];
6497
+ tags = this.selectVastTagsForBreak(adBreak);
6498
+ if (!tags || tags.length === 0) {
6499
+ return [
6500
+ 2
6501
+ ];
6502
+ }
6268
6503
  first = tags[0];
6269
6504
  rest = tags.slice(1);
6270
6505
  this.adPodQueue = rest;
6271
6506
  this.adPlayer.updateOriginalMutedState(this.video.muted, this.video.volume);
6507
+ this.showAds = true;
6508
+ this.inAdBreak = true;
6509
+ this.currentAdBreakStartWallClockMs = Date.now();
6510
+ if (!this.video.paused) {
6511
+ this.video.pause();
6512
+ }
6272
6513
  _state.label = 1;
6273
6514
  case 1:
6274
6515
  _state.trys.push([
@@ -6283,10 +6524,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6283
6524
  ];
6284
6525
  case 2:
6285
6526
  _state.sent();
6286
- this.inAdBreak = true;
6287
- this.expectedAdBreakDurationMs = remainingMs;
6288
- this.currentAdBreakStartWallClockMs = Date.now();
6289
- this.scheduleAdStopCountdown(remainingMs);
6290
6527
  return [
6291
6528
  3,
6292
6529
  4
@@ -6294,8 +6531,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6294
6531
  case 3:
6295
6532
  error = _state.sent();
6296
6533
  this.adPodQueue = [];
6534
+ this.inAdBreak = false;
6535
+ this.showAds = false;
6297
6536
  if (this.config.debugAdTiming) {
6298
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP ad request failed:", error);
6537
+ console.warn("[StormcloudVideoPlayer] VMAP ad request failed:", error);
6299
6538
  }
6300
6539
  return [
6301
6540
  3,
@@ -7007,9 +7246,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7007
7246
  {
7008
7247
  key: "findBreakForTime",
7009
7248
  value: function findBreakForTime(nowMs) {
7010
- var _this_config_driftToleranceMs;
7011
7249
  var schedule = this.vmapBreaks;
7012
- var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
7013
7250
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
7014
7251
  try {
7015
7252
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
@@ -7021,9 +7258,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7021
7258
  if (breakStartMs == null) {
7022
7259
  continue;
7023
7260
  }
7024
- var end = breakStartMs + (b.durationMs || 0);
7025
- var effectiveTol = breakStartMs === 0 ? Math.max(tol, 3e4) : tol;
7026
- if (nowMs >= breakStartMs && (b.durationMs ? nowMs < end : nowMs <= breakStartMs + effectiveTol)) {
7261
+ if (b.durationMs) {
7262
+ var end = breakStartMs + b.durationMs;
7263
+ if (nowMs >= breakStartMs && nowMs < end) {
7264
+ return b;
7265
+ }
7266
+ continue;
7267
+ }
7268
+ if (nowMs >= breakStartMs) {
7027
7269
  return b;
7028
7270
  }
7029
7271
  }
@@ -7231,6 +7473,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7231
7473
  this.video.removeEventListener("timeupdate", this.timeUpdateHandler);
7232
7474
  delete this.timeUpdateHandler;
7233
7475
  }
7476
+ if (this.endedHandler) {
7477
+ this.video.removeEventListener("ended", this.endedHandler);
7478
+ delete this.endedHandler;
7479
+ }
7234
7480
  if (this.emptiedHandler) {
7235
7481
  this.video.removeEventListener("emptied", this.emptiedHandler);
7236
7482
  delete this.emptiedHandler;