stormcloud-video-player 0.8.73 → 0.8.75

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +10 -70
  2. package/dist/stormcloud-vp.min.js +1 -1
  3. package/lib/Player.d.cts +2 -1
  4. package/lib/StormcloudPlayer.cjs +988 -273
  5. package/lib/StormcloudPlayer.cjs.map +1 -1
  6. package/lib/StormcloudPlayer.d.cts +1 -0
  7. package/lib/index.cjs +999 -278
  8. package/lib/index.cjs.map +1 -1
  9. package/lib/index.d.cts +1 -0
  10. package/lib/index.d.ts +40 -3
  11. package/lib/index.js +992 -279
  12. package/lib/index.js.map +1 -1
  13. package/lib/player/AdBreakOrchestrator.cjs +767 -67
  14. package/lib/player/AdBreakOrchestrator.cjs.map +1 -1
  15. package/lib/player/AdBreakOrchestrator.d.cts +7 -9
  16. package/lib/player/AdConfigManager.cjs +315 -62
  17. package/lib/player/AdConfigManager.cjs.map +1 -1
  18. package/lib/player/AdConfigManager.d.cts +7 -12
  19. package/lib/player/AdTimingService.cjs +37 -1
  20. package/lib/player/AdTimingService.cjs.map +1 -1
  21. package/lib/player/AdTimingService.d.cts +8 -1
  22. package/lib/player/EdgePodRequest.d.cts +1 -0
  23. package/lib/player/FloorLadder.d.cts +1 -0
  24. package/lib/player/HlsEngine.d.cts +1 -0
  25. package/lib/player/OptimizedPodRequest.cjs +719 -0
  26. package/lib/player/OptimizedPodRequest.cjs.map +1 -0
  27. package/lib/player/OptimizedPodRequest.d.cts +101 -0
  28. package/lib/player/PlayerControls.d.cts +1 -0
  29. package/lib/player/Scte35CueManager.d.cts +1 -0
  30. package/lib/player/Scte35Parser.d.cts +1 -0
  31. package/lib/player/StormcloudVideoPlayer.cjs +988 -273
  32. package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
  33. package/lib/player/StormcloudVideoPlayer.d.cts +1 -0
  34. package/lib/player/playerTypes.d.cts +1 -0
  35. package/lib/players/HlsPlayer.cjs +988 -273
  36. package/lib/players/HlsPlayer.cjs.map +1 -1
  37. package/lib/players/HlsPlayer.d.cts +1 -0
  38. package/lib/players/index.cjs +988 -273
  39. package/lib/players/index.cjs.map +1 -1
  40. package/lib/props.d.cts +1 -0
  41. package/lib/sdk/hlsAdPlayer.cjs +316 -51
  42. package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
  43. package/lib/sdk/hlsAdPlayer.d.cts +3 -1
  44. package/lib/sdk/pal.cjs +108 -83
  45. package/lib/sdk/pal.cjs.map +1 -1
  46. package/lib/sdk/pal.d.cts +1 -0
  47. package/lib/types.d.cts +9 -2
  48. package/lib/ui/StormcloudVideoPlayer.cjs +991 -278
  49. package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
  50. package/lib/ui/StormcloudVideoPlayer.d.cts +1 -0
  51. package/lib/utils/ctvVastSignals.cjs +9 -7
  52. package/lib/utils/ctvVastSignals.cjs.map +1 -1
  53. package/lib/utils/tracking.cjs +17 -3
  54. package/lib/utils/tracking.cjs.map +1 -1
  55. package/lib/utils/tracking.d.cts +2 -1
  56. package/lib/utils/vastEnvironmentSignals.cjs +9 -7
  57. package/lib/utils/vastEnvironmentSignals.cjs.map +1 -1
  58. package/lib/utils/vastMacros.cjs +251 -10
  59. package/lib/utils/vastMacros.cjs.map +1 -1
  60. package/lib/utils/vastMacros.d.cts +13 -4
  61. package/package.json +5 -3
package/lib/index.cjs CHANGED
@@ -406,12 +406,18 @@ __export(index_exports, {
406
406
  DEFAULT_FLOOR_LADDER_BOUNDS: function DEFAULT_FLOOR_LADDER_BOUNDS1() {
407
407
  return DEFAULT_FLOOR_LADDER_BOUNDS;
408
408
  },
409
+ DEFAULT_REQUEST_SAFETY_MS: function DEFAULT_REQUEST_SAFETY_MS1() {
410
+ return DEFAULT_REQUEST_SAFETY_MS;
411
+ },
409
412
  DEFAULT_TRACKING_INGEST_CONFIG: function DEFAULT_TRACKING_INGEST_CONFIG1() {
410
413
  return DEFAULT_TRACKING_INGEST_CONFIG;
411
414
  },
412
415
  DEFAULT_WEB_FLOOR_LADDER_CONFIG: function DEFAULT_WEB_FLOOR_LADDER_CONFIG1() {
413
416
  return DEFAULT_WEB_FLOOR_LADDER_CONFIG;
414
417
  },
418
+ GAM_AD_OPPORTUNITY_DURATION_MS: function GAM_AD_OPPORTUNITY_DURATION_MS1() {
419
+ return GAM_AD_OPPORTUNITY_DURATION_MS;
420
+ },
415
421
  IS_BROWSER: function IS_BROWSER1() {
416
422
  return IS_BROWSER;
417
423
  },
@@ -577,21 +583,20 @@ var ANDROID_ID_TYPES = /* @__PURE__ */ new Set([
577
583
  "adid"
578
584
  ]);
579
585
  function resolveVastEnvironmentSignals(isCtv) {
580
- var _ref;
581
586
  var bridgeSignals = readNativeBridgeSignals();
582
587
  var platformDevice = readPlatformNativeDeviceId();
583
- var realDeviceId = bridgeSignals.deviceId || (isCtv ? readStoredDeviceId() : void 0) || platformDevice.deviceId;
588
+ var bridgeDeviceId = validDeviceId(bridgeSignals.deviceId);
589
+ var realDeviceId = bridgeDeviceId || (isCtv ? validDeviceId(readStoredDeviceId()) : void 0) || validDeviceId(platformDevice.deviceId);
584
590
  var deviceId = realDeviceId;
585
- var deviceIdType = bridgeSignals.deviceIdType || readStoredString("deviceIdType") || readStoredString("idtype") || platformDevice.deviceIdType || inferDeviceIdType();
586
- var platformLat = bridgeSignals.deviceId ? bridgeSignals.limitAdTracking : platformDevice.limitAdTracking;
587
- var limitAdTracking = deviceId != null ? (_ref = platformLat !== null && platformLat !== void 0 ? platformLat : readStoredLimitAdTracking()) !== null && _ref !== void 0 ? _ref : false : void 0;
591
+ var deviceIdType = (bridgeDeviceId ? bridgeSignals.deviceIdType : void 0) || readStoredString("deviceIdType") || readStoredString("idtype") || platformDevice.deviceIdType || inferDeviceIdType();
592
+ var platformLat = bridgeDeviceId ? bridgeSignals.limitAdTracking : platformDevice.limitAdTracking;
593
+ var limitAdTracking = deviceId != null ? platformLat !== null && platformLat !== void 0 ? platformLat : readStoredLimitAdTracking() : void 0;
588
594
  if (!deviceId && isCtv) {
589
595
  var dpid = getOrCreateStoredUuid(PLAYER_ID_STORAGE_KEY);
590
596
  if (dpid) {
591
- var _ref1;
592
597
  deviceId = dpid;
593
598
  deviceIdType = "dpid";
594
- limitAdTracking = (_ref1 = platformLat !== null && platformLat !== void 0 ? platformLat : readStoredLimitAdTracking()) !== null && _ref1 !== void 0 ? _ref1 : false;
599
+ limitAdTracking = platformLat !== null && platformLat !== void 0 ? platformLat : readStoredLimitAdTracking();
595
600
  }
596
601
  }
597
602
  var deviceTypeHint = resolveDeviceTypeHint(isCtv);
@@ -956,6 +961,9 @@ function isMacroPlaceholder(value) {
956
961
  var t = value.trim();
957
962
  return !t || /^(\[[^\]]*\]|\{[^}]*\}|%%[^%]*%%)$/.test(t) || /^(unknown|null|undefined|none|n\/a|\$\{[^}]+\})$/i.test(t) || ZEROED_AD_ID_PATTERNS.has(t.toLowerCase());
958
963
  }
964
+ function validDeviceId(value) {
965
+ return value && !isMacroPlaceholder(value) ? value : void 0;
966
+ }
959
967
  function isZeroedAdId(value) {
960
968
  return ZEROED_AD_ID_PATTERNS.has(value.trim().toLowerCase());
961
969
  }
@@ -1488,6 +1496,199 @@ function ensureVideoAdType(rawUrl) {
1488
1496
  return rawUrl;
1489
1497
  }
1490
1498
  }
1499
+ var SCVP_MACRO_DETECT = /\[SCVP-|%5BSCVP-|\(SCVP-|%28SCVP-/i;
1500
+ var SCVP_MACRO_PATTERN = /\[SCVP-([A-Z0-9-]+)\]|\(SCVP-([A-Z0-9-]+)\)/gi;
1501
+ var SCVP_WHOLE_VALUE_PATTERN = /^\s*(?:\[SCVP-([A-Z0-9-]+)\]|\(SCVP-([A-Z0-9-]+)\))\s*$/i;
1502
+ var NESTED_QUERY_PARAM_KEYS = /* @__PURE__ */ new Set([
1503
+ "cust_params"
1504
+ ]);
1505
+ var SCVP_POD_MACROS = /* @__PURE__ */ new Set([
1506
+ "PMND",
1507
+ "PMXD",
1508
+ "PMAD"
1509
+ ]);
1510
+ function hasScvpMacros(url) {
1511
+ return !!url && SCVP_MACRO_DETECT.test(url);
1512
+ }
1513
+ function safeDecode(value) {
1514
+ try {
1515
+ return decodeURIComponent(value.replace(/\+/g, " "));
1516
+ } catch (unused) {
1517
+ return value;
1518
+ }
1519
+ }
1520
+ function findScvpMacroNames(url) {
1521
+ if (!url) return [];
1522
+ var names = /* @__PURE__ */ new Set();
1523
+ var text = url;
1524
+ for(var pass = 0; pass < 3; pass++){
1525
+ text.replace(SCVP_MACRO_PATTERN, function(_m, bracketName, parenName) {
1526
+ names.add(String(bracketName || parenName).toUpperCase());
1527
+ return "";
1528
+ });
1529
+ var decoded = safeDecode(text);
1530
+ if (decoded === text) break;
1531
+ text = decoded;
1532
+ }
1533
+ return Array.from(names);
1534
+ }
1535
+ function resolveScvpMacroValues(ctx) {
1536
+ var _ctx_deviceId, _ctx_deviceIdType, _ctx_consent, _ctx_consent1, _ctx_consent2;
1537
+ var values = /* @__PURE__ */ new Map();
1538
+ var set = function set(name, value) {
1539
+ if (value == null) return;
1540
+ var str = String(value).trim();
1541
+ if (str) values.set(name, str);
1542
+ };
1543
+ var toFlag = function toFlag(value) {
1544
+ return value == null ? void 0 : value ? "1" : "0";
1545
+ };
1546
+ var deviceId = (_ctx_deviceId = ctx.deviceId) === null || _ctx_deviceId === void 0 ? void 0 : _ctx_deviceId.trim();
1547
+ var deviceIdType = deviceId ? ((_ctx_deviceIdType = ctx.deviceIdType) === null || _ctx_deviceIdType === void 0 ? void 0 : _ctx_deviceIdType.trim()) || inferDeviceIdType() : void 0;
1548
+ if (deviceId && deviceIdType) {
1549
+ var _toFlag;
1550
+ set("RDID", deviceId);
1551
+ set("IDTYPE", deviceIdType);
1552
+ set("IS-LAT", (_toFlag = toFlag(ctx.limitAdTracking)) !== null && _toFlag !== void 0 ? _toFlag : "0");
1553
+ }
1554
+ set("SID", ctx.sessionId);
1555
+ set("DTH", ctx.deviceTypeHint);
1556
+ set("GIVN", ctx.palNonce);
1557
+ set("CT-TI", ctx.programTitle);
1558
+ set("CT-CH", ctx.channelName);
1559
+ set("POD", ctx.pod);
1560
+ set("CORRELATOR", ctx.correlator);
1561
+ set("SCOR", ctx.streamCorrelator);
1562
+ set("VPMUTE", toFlag(ctx.adWillPlayMuted));
1563
+ if (ctx.adWillAutoPlay != null) {
1564
+ set("VPA", ctx.adWillAutoPlay ? "auto" : "click");
1565
+ }
1566
+ set("GDPR", (_ctx_consent = ctx.consent) === null || _ctx_consent === void 0 ? void 0 : _ctx_consent.gdpr);
1567
+ set("GDPR-CONSENT", (_ctx_consent1 = ctx.consent) === null || _ctx_consent1 === void 0 ? void 0 : _ctx_consent1.gdprConsent);
1568
+ set("US-PRIVACY", (_ctx_consent2 = ctx.consent) === null || _ctx_consent2 === void 0 ? void 0 : _ctx_consent2.usPrivacy);
1569
+ return values;
1570
+ }
1571
+ var keepNone = function keepNone() {
1572
+ return false;
1573
+ };
1574
+ function substituteScvpParams(params, values, unresolved, keep, nested) {
1575
+ var out = [];
1576
+ var replaceMacro = function replaceMacro(match, bracketName, parenName) {
1577
+ var name = String(bracketName || parenName).toUpperCase();
1578
+ var value = values.get(name);
1579
+ if (value != null) return value;
1580
+ if (keep(name)) return match;
1581
+ unresolved.add(name);
1582
+ return "";
1583
+ };
1584
+ params.forEach(function(value, key) {
1585
+ var whole = value.match(SCVP_WHOLE_VALUE_PATTERN);
1586
+ if (whole) {
1587
+ var name = String(whole[1] || whole[2]).toUpperCase();
1588
+ var resolved = values.get(name);
1589
+ if (resolved != null) {
1590
+ out.push([
1591
+ key,
1592
+ resolved
1593
+ ]);
1594
+ } else if (keep(name)) {
1595
+ out.push([
1596
+ key,
1597
+ value
1598
+ ]);
1599
+ } else {
1600
+ unresolved.add(name);
1601
+ }
1602
+ return;
1603
+ }
1604
+ if (!SCVP_MACRO_DETECT.test(value)) {
1605
+ out.push([
1606
+ key,
1607
+ value
1608
+ ]);
1609
+ return;
1610
+ }
1611
+ if (!nested && NESTED_QUERY_PARAM_KEYS.has(key)) {
1612
+ var inner = substituteScvpParams(new URLSearchParams(value), values, unresolved, keep, true);
1613
+ if (inner.length > 0) {
1614
+ out.push([
1615
+ key,
1616
+ inner.map(function(param) {
1617
+ var _param = _sliced_to_array(param, 2), k = _param[0], v = _param[1];
1618
+ return "".concat(encodeURIComponent(k), "=").concat(encodeURIComponent(v));
1619
+ }).join("&")
1620
+ ]);
1621
+ }
1622
+ return;
1623
+ }
1624
+ out.push([
1625
+ key,
1626
+ value.replace(SCVP_MACRO_PATTERN, replaceMacro)
1627
+ ]);
1628
+ });
1629
+ return out;
1630
+ }
1631
+ function substituteScvpMacros(baseUrl, values) {
1632
+ var keep = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : keepNone;
1633
+ var unresolved = /* @__PURE__ */ new Set();
1634
+ var url;
1635
+ try {
1636
+ url = new URL(normalizeVastTagUrl(baseUrl));
1637
+ } catch (unused) {
1638
+ var replaced = baseUrl.replace(SCVP_MACRO_PATTERN, function(match, bracketName, parenName) {
1639
+ var name = String(bracketName || parenName).toUpperCase();
1640
+ var value = values.get(name);
1641
+ if (value != null) return encodeURIComponent(value);
1642
+ if (keep(name)) return match;
1643
+ unresolved.add(name);
1644
+ return "";
1645
+ });
1646
+ return {
1647
+ url: replaced,
1648
+ unresolved: Array.from(unresolved)
1649
+ };
1650
+ }
1651
+ var entries = substituteScvpParams(url.searchParams, values, unresolved, keep, false);
1652
+ var search = new URLSearchParams();
1653
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1654
+ try {
1655
+ for(var _iterator = entries[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1656
+ var _step_value = _sliced_to_array(_step.value, 2), key = _step_value[0], value = _step_value[1];
1657
+ search.append(key, value);
1658
+ }
1659
+ } catch (err) {
1660
+ _didIteratorError = true;
1661
+ _iteratorError = err;
1662
+ } finally{
1663
+ try {
1664
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1665
+ _iterator.return();
1666
+ }
1667
+ } finally{
1668
+ if (_didIteratorError) {
1669
+ throw _iteratorError;
1670
+ }
1671
+ }
1672
+ }
1673
+ url.search = search.toString();
1674
+ return {
1675
+ url: url.toString(),
1676
+ unresolved: Array.from(unresolved)
1677
+ };
1678
+ }
1679
+ function applyScvpMacros(baseUrl, ctx) {
1680
+ var deferred = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : /* @__PURE__ */ new Set();
1681
+ return substituteScvpMacros(baseUrl, resolveScvpMacroValues(ctx), function(name) {
1682
+ return deferred.has(name);
1683
+ });
1684
+ }
1685
+ function stripScvpMacros(url) {
1686
+ if (findScvpMacroNames(url).length === 0) return {
1687
+ url: url,
1688
+ unresolved: []
1689
+ };
1690
+ return substituteScvpMacros(url, /* @__PURE__ */ new Map());
1691
+ }
1491
1692
  function applyVastMacros(baseUrl, ctx) {
1492
1693
  var expandedUrl = expandInlineMacroPlaceholders(baseUrl, ctx);
1493
1694
  var url;
@@ -1529,15 +1730,6 @@ function applyVastMacros(baseUrl, ctx) {
1529
1730
  }
1530
1731
  params.delete("ppos");
1531
1732
  params.delete("lip");
1532
- if (ctx.podMinDurationMs != null) {
1533
- params.set("pmnd", String(Math.max(0, Math.round(ctx.podMinDurationMs))));
1534
- }
1535
- if (ctx.podMaxDurationMs != null) {
1536
- params.set("pmxd", String(Math.max(0, Math.round(ctx.podMaxDurationMs))));
1537
- }
1538
- if (ctx.podMaxAds != null) {
1539
- params.set("pmad", String(Math.max(1, Math.round(ctx.podMaxAds))));
1540
- }
1541
1733
  var existingUrl = params.get("url") || "";
1542
1734
  if (EXAMPLE_COM_URL.test(existingUrl)) {
1543
1735
  params.delete("url");
@@ -2390,6 +2582,309 @@ function substituteVastTrackingMacros(url) {
2390
2582
  return KNOWN_VAST_MACROS.has(name) ? "" : match;
2391
2583
  });
2392
2584
  }
2585
+ // src/player/OptimizedPodRequest.ts
2586
+ var DEFAULT_REQUEST_SAFETY_MS = 1500;
2587
+ var GAM_AD_OPPORTUNITY_DURATION_MS = 3e4;
2588
+ var POD_PARAM_KEYS = [
2589
+ "pmnd",
2590
+ "pmxd",
2591
+ "pmad"
2592
+ ];
2593
+ var POSITIVE_INT = /^[1-9]\d*$/;
2594
+ var NON_NEGATIVE_INT = /^(0|[1-9]\d*)$/;
2595
+ function nonNegativeInt(value) {
2596
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : void 0;
2597
+ }
2598
+ function positiveInt(value) {
2599
+ return typeof value === "number" && Number.isFinite(value) && value >= 1 ? Math.floor(value) : void 0;
2600
+ }
2601
+ function resolveAdPodConfig(config) {
2602
+ var _config_adPodConfig, _nonNegativeInt, _nonNegativeInt1, _positiveInt;
2603
+ var pod = (_config_adPodConfig = config.adPodConfig) !== null && _config_adPodConfig !== void 0 ? _config_adPodConfig : {};
2604
+ return {
2605
+ requestSafetyMs: (_nonNegativeInt = nonNegativeInt(pod.requestSafetyMs)) !== null && _nonNegativeInt !== void 0 ? _nonNegativeInt : DEFAULT_REQUEST_SAFETY_MS,
2606
+ minPodDurationMs: (_nonNegativeInt1 = nonNegativeInt(pod.minPodDurationMs)) !== null && _nonNegativeInt1 !== void 0 ? _nonNegativeInt1 : 0,
2607
+ maxAdsPerBreak: pod.maxAdsPerBreak === void 0 ? positiveInt(config.podMaxAds) : positiveInt(pod.maxAdsPerBreak),
2608
+ maxPodDurationMs: (_positiveInt = positiveInt(pod.maxPodDurationMs)) !== null && _positiveInt !== void 0 ? _positiveInt : positiveInt(config.podMaxDurationMs),
2609
+ exactDuration: config.podExactDuration === true
2610
+ };
2611
+ }
2612
+ function measureBreakCapacity(timing, nowMonoMs) {
2613
+ var _timing_breakEndMonoMs;
2614
+ var scheduled = timing.scheduledBreakDurationMs;
2615
+ if (scheduled == null || !(scheduled > 0) || timing.breakStartMonoMs == null) {
2616
+ return void 0;
2617
+ }
2618
+ var endMonoMs = (_timing_breakEndMonoMs = timing.breakEndMonoMs) !== null && _timing_breakEndMonoMs !== void 0 ? _timing_breakEndMonoMs : timing.breakStartMonoMs + scheduled;
2619
+ var untilEnd = Math.min(scheduled, endMonoMs - nowMonoMs);
2620
+ var unplayed = scheduled - Math.max(0, timing.playedDurationMs);
2621
+ return {
2622
+ scheduledBreakDurationMs: scheduled,
2623
+ elapsedBeforeGamRequestMs: Math.max(0, nowMonoMs - timing.breakStartMonoMs),
2624
+ remainingAtGamDispatchMs: Math.max(0, Math.min(untilEnd, unplayed))
2625
+ };
2626
+ }
2627
+ function resolvePodParams(input) {
2628
+ var capacity = input.capacity, config = input.config;
2629
+ var pmxd;
2630
+ var source;
2631
+ if (capacity) {
2632
+ pmxd = Math.floor(capacity.remainingAtGamDispatchMs - config.requestSafetyMs);
2633
+ source = "break_remaining";
2634
+ } else if (config.maxPodDurationMs != null) {
2635
+ pmxd = config.maxPodDurationMs;
2636
+ source = "configured_cap";
2637
+ } else if (input.tagMaxDurationMs != null) {
2638
+ pmxd = input.tagMaxDurationMs;
2639
+ source = "tag_cap";
2640
+ } else {
2641
+ return {
2642
+ kind: "omit"
2643
+ };
2644
+ }
2645
+ var minUsable = Math.max(1, Math.floor(input.minUsablePmxdMs));
2646
+ if (!Number.isFinite(pmxd) || pmxd < minUsable) {
2647
+ return {
2648
+ kind: "abort",
2649
+ reason: capacity ? "insufficient_break_capacity" : "invalid_pod_cap",
2650
+ pmxdCandidateMs: Number.isFinite(pmxd) ? pmxd : 0
2651
+ };
2652
+ }
2653
+ var pmnd = config.exactDuration ? pmxd : Math.min(config.minPodDurationMs, pmxd);
2654
+ return {
2655
+ kind: "send",
2656
+ params: {
2657
+ pmnd: pmnd,
2658
+ pmxd: pmxd,
2659
+ pmad: config.maxAdsPerBreak
2660
+ },
2661
+ source: source
2662
+ };
2663
+ }
2664
+ function podRequestAborted(reason, message, diagnostics) {
2665
+ var error = new Error("Optimized pod request not sent (".concat(reason, "): ").concat(message));
2666
+ error.podRequestAborted = true;
2667
+ error.reason = reason;
2668
+ error.diagnostics = diagnostics;
2669
+ return error;
2670
+ }
2671
+ function isPodRequestAbortedError(error) {
2672
+ return !!error && error.podRequestAborted === true;
2673
+ }
2674
+ function firstPositiveIntParam(params, key) {
2675
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2676
+ try {
2677
+ for(var _iterator = params.getAll(key)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2678
+ var value = _step.value;
2679
+ if (POSITIVE_INT.test(value.trim())) return Number(value.trim());
2680
+ }
2681
+ } catch (err) {
2682
+ _didIteratorError = true;
2683
+ _iteratorError = err;
2684
+ } finally{
2685
+ try {
2686
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2687
+ _iterator.return();
2688
+ }
2689
+ } finally{
2690
+ if (_didIteratorError) {
2691
+ throw _iteratorError;
2692
+ }
2693
+ }
2694
+ }
2695
+ return void 0;
2696
+ }
2697
+ function isOptimizedPodUrl(url) {
2698
+ if (findScvpMacroNames(url).some(function(name) {
2699
+ return SCVP_POD_MACROS.has(name);
2700
+ })) return true;
2701
+ try {
2702
+ var params = new URL(url).searchParams;
2703
+ return POD_PARAM_KEYS.some(function(key) {
2704
+ return params.has(key);
2705
+ });
2706
+ } catch (unused) {
2707
+ return false;
2708
+ }
2709
+ }
2710
+ function finalizeGamRequestUrl(rawUrl, ctx) {
2711
+ var nowEpochMs = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : Date.now();
2712
+ var optimizedPod = isOptimizedPodUrl(rawUrl);
2713
+ var capacity = ctx.capacity;
2714
+ var base = {
2715
+ breakId: ctx.breakId,
2716
+ optimizedPod: optimizedPod,
2717
+ scteBreakDurationMs: capacity === null || capacity === void 0 ? void 0 : capacity.scheduledBreakDurationMs,
2718
+ elapsedBeforeGamRequestMs: capacity === null || capacity === void 0 ? void 0 : capacity.elapsedBeforeGamRequestMs,
2719
+ remainingAtGamDispatchMs: capacity === null || capacity === void 0 ? void 0 : capacity.remainingAtGamDispatchMs,
2720
+ safetyReserveMs: ctx.config.requestSafetyMs
2721
+ };
2722
+ var decision = {
2723
+ kind: "omit"
2724
+ };
2725
+ if (optimizedPod) {
2726
+ var tagMaxDurationMs;
2727
+ try {
2728
+ tagMaxDurationMs = firstPositiveIntParam(new URL(rawUrl).searchParams, "pmxd");
2729
+ } catch (unused) {}
2730
+ decision = resolvePodParams({
2731
+ capacity: capacity,
2732
+ config: ctx.config,
2733
+ minUsablePmxdMs: ctx.minUsablePmxdMs,
2734
+ tagMaxDurationMs: tagMaxDurationMs
2735
+ });
2736
+ if (decision.kind === "abort") {
2737
+ throw podRequestAborted(decision.reason, "pmxd would be ".concat(decision.pmxdCandidateMs, "ms (minimum ").concat(ctx.minUsablePmxdMs, "ms)"), base);
2738
+ }
2739
+ }
2740
+ var pod = decision.kind === "send" ? decision.params : void 0;
2741
+ var values = /* @__PURE__ */ new Map();
2742
+ if (pod) {
2743
+ values.set("PMND", String(pod.pmnd));
2744
+ values.set("PMXD", String(pod.pmxd));
2745
+ if (pod.pmad != null) values.set("PMAD", String(pod.pmad));
2746
+ }
2747
+ var substituted = substituteScvpMacros(rawUrl, values);
2748
+ var finalUrl;
2749
+ try {
2750
+ var url = new URL(normalizeVastTagUrl(substituted.url));
2751
+ if (pod) {
2752
+ url.searchParams.set("pmnd", String(pod.pmnd));
2753
+ url.searchParams.set("pmxd", String(pod.pmxd));
2754
+ if (pod.pmad != null) url.searchParams.set("pmad", String(pod.pmad));
2755
+ else url.searchParams.delete("pmad");
2756
+ } else {
2757
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2758
+ try {
2759
+ for(var _iterator = POD_PARAM_KEYS[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2760
+ var key = _step.value;
2761
+ url.searchParams.delete(key);
2762
+ }
2763
+ } catch (err) {
2764
+ _didIteratorError = true;
2765
+ _iteratorError = err;
2766
+ } finally{
2767
+ try {
2768
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2769
+ _iterator.return();
2770
+ }
2771
+ } finally{
2772
+ if (_didIteratorError) {
2773
+ throw _iteratorError;
2774
+ }
2775
+ }
2776
+ }
2777
+ }
2778
+ finalUrl = url.toString();
2779
+ } catch (unused) {
2780
+ throw podRequestAborted("invalid_url", "GAM request URL could not be parsed", base);
2781
+ }
2782
+ var problems = validateGamRequestUrl(finalUrl, {
2783
+ optimizedPod: !!pod,
2784
+ remainingMs: decision.kind === "send" && decision.source === "break_remaining" ? capacity === null || capacity === void 0 ? void 0 : capacity.remainingAtGamDispatchMs : void 0
2785
+ });
2786
+ if (problems.length > 0) {
2787
+ throw podRequestAborted("invalid_url", problems.join("; "), base);
2788
+ }
2789
+ var givn = null;
2790
+ try {
2791
+ givn = new URL(finalUrl).searchParams.get("givn");
2792
+ } catch (unused) {}
2793
+ return {
2794
+ url: finalUrl,
2795
+ diagnostics: {
2796
+ breakId: ctx.breakId,
2797
+ optimizedPod: !!pod,
2798
+ pmxdSource: decision.kind === "send" ? decision.source : void 0,
2799
+ scteBreakDurationMs: capacity === null || capacity === void 0 ? void 0 : capacity.scheduledBreakDurationMs,
2800
+ elapsedBeforeGamRequestMs: capacity === null || capacity === void 0 ? void 0 : capacity.elapsedBeforeGamRequestMs,
2801
+ remainingAtGamDispatchMs: capacity === null || capacity === void 0 ? void 0 : capacity.remainingAtGamDispatchMs,
2802
+ safetyReserveMs: ctx.config.requestSafetyMs,
2803
+ pmndSent: pod === null || pod === void 0 ? void 0 : pod.pmnd,
2804
+ pmxdSent: pod === null || pod === void 0 ? void 0 : pod.pmxd,
2805
+ pmadSent: pod === null || pod === void 0 ? void 0 : pod.pmad,
2806
+ palNoncePresent: !!givn,
2807
+ gamRequestDispatchTimestamp: new Date(nowEpochMs).toISOString(),
2808
+ strippedMacros: substituted.unresolved.filter(function(name) {
2809
+ return !SCVP_POD_MACROS.has(name);
2810
+ })
2811
+ }
2812
+ };
2813
+ }
2814
+ function validateGamRequestUrl(url, expect) {
2815
+ var problems = [];
2816
+ var leftover = findScvpMacroNames(url);
2817
+ if (leftover.length > 0) problems.push("unresolved SCVP macros: ".concat(leftover.join(", ")));
2818
+ var params;
2819
+ try {
2820
+ params = new URL(url).searchParams;
2821
+ } catch (unused) {
2822
+ return problems.concat("URL could not be parsed");
2823
+ }
2824
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2825
+ try {
2826
+ for(var _iterator = POD_PARAM_KEYS[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2827
+ var key = _step.value;
2828
+ if (params.getAll(key).length > 1) problems.push("duplicate ".concat(key));
2829
+ }
2830
+ } catch (err) {
2831
+ _didIteratorError = true;
2832
+ _iteratorError = err;
2833
+ } finally{
2834
+ try {
2835
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2836
+ _iterator.return();
2837
+ }
2838
+ } finally{
2839
+ if (_didIteratorError) {
2840
+ throw _iteratorError;
2841
+ }
2842
+ }
2843
+ }
2844
+ if (!expect.optimizedPod) {
2845
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
2846
+ try {
2847
+ for(var _iterator1 = POD_PARAM_KEYS[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
2848
+ var key1 = _step1.value;
2849
+ if (params.has(key1)) problems.push("".concat(key1, " present on a non-pod request"));
2850
+ }
2851
+ } catch (err) {
2852
+ _didIteratorError1 = true;
2853
+ _iteratorError1 = err;
2854
+ } finally{
2855
+ try {
2856
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
2857
+ _iterator1.return();
2858
+ }
2859
+ } finally{
2860
+ if (_didIteratorError1) {
2861
+ throw _iteratorError1;
2862
+ }
2863
+ }
2864
+ }
2865
+ return problems;
2866
+ }
2867
+ var pmxd = params.get("pmxd");
2868
+ var pmnd = params.get("pmnd");
2869
+ var pmad = params.get("pmad");
2870
+ if (pmxd == null || !POSITIVE_INT.test(pmxd)) problems.push("pmxd must be a positive integer (got ".concat(pmxd, ")"));
2871
+ if (pmnd == null || !NON_NEGATIVE_INT.test(pmnd)) problems.push("pmnd must be a non-negative integer (got ".concat(pmnd, ")"));
2872
+ if (pmxd != null && pmnd != null && Number(pmnd) > Number(pmxd)) problems.push("pmnd exceeds pmxd");
2873
+ if (pmad != null && !POSITIVE_INT.test(pmad)) problems.push("pmad must be a positive integer or absent (got ".concat(pmad, ")"));
2874
+ if (expect.remainingMs != null && pmxd != null && Number(pmxd) > expect.remainingMs) {
2875
+ problems.push("pmxd ".concat(pmxd, " exceeds remaining break ").concat(expect.remainingMs, "ms"));
2876
+ }
2877
+ return problems;
2878
+ }
2879
+ function computePodResponseDiagnostics(pmxdSent, vastAdCount, totalVastCreativeDurationMs) {
2880
+ var estimatedUnusedPodMs = Math.max(0, pmxdSent - totalVastCreativeDurationMs);
2881
+ return {
2882
+ vastAdCount: vastAdCount,
2883
+ totalVastCreativeDurationMs: totalVastCreativeDurationMs,
2884
+ estimatedUnusedPodMs: estimatedUnusedPodMs,
2885
+ estimatedUnmatchedCount: Math.floor(estimatedUnusedPodMs / GAM_AD_OPPORTUNITY_DURATION_MS)
2886
+ };
2887
+ }
2393
2888
  // src/sdk/hlsAdPlayer.ts
2394
2889
  var LINEAR_TRACKING_EVENTS = [
2395
2890
  "creativeView",
@@ -2470,6 +2965,7 @@ function toVastMediaErrorCode(error) {
2470
2965
  return VAST_ERROR_MEDIA_DISPLAY;
2471
2966
  }
2472
2967
  }
2968
+ var gamCredentialsMode = "include";
2473
2969
  function createHlsAdPlayer(contentVideo, options) {
2474
2970
  var _contentVideo_AD_VIDEO_PROP, _contentVideo_AD_CONTAINER_PROP, _ref;
2475
2971
  var adPlaying = false;
@@ -3341,9 +3837,9 @@ function createHlsAdPlayer(contentVideo, options) {
3341
3837
  }
3342
3838
  }
3343
3839
  function fetchVastXml(vastTagUrl) {
3344
- var credentials = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "include", kind = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : "gam";
3840
+ var credentials = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "include", kind = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : "gam", finalizeRequestUrl = arguments.length > 3 ? arguments[3] : void 0;
3345
3841
  return _async_to_generator(function() {
3346
- var controller, timeoutId, startedAt, attempt, requestVast, response, error, error1;
3842
+ var controller, timeoutId, startedAt, attempt, resolveDispatchUrl, requestVast, response, error, error1;
3347
3843
  return _ts_generator(this, function(_state) {
3348
3844
  switch(_state.label){
3349
3845
  case 0:
@@ -3357,13 +3853,32 @@ function createHlsAdPlayer(contentVideo, options) {
3357
3853
  }, VAST_REQUEST_TIMEOUT_MS) : void 0;
3358
3854
  startedAt = Date.now();
3359
3855
  attempt = 0;
3856
+ resolveDispatchUrl = function resolveDispatchUrl() {
3857
+ if (kind === "wrapper") return vastTagUrl;
3858
+ if (finalizeRequestUrl) return finalizeRequestUrl(vastTagUrl, attempt);
3859
+ var _stripScvpMacros = stripScvpMacros(vastTagUrl), url = _stripScvpMacros.url, unresolved = _stripScvpMacros.unresolved;
3860
+ if (unresolved.length > 0) {
3861
+ console.warn("[HlsAdPlayer] Removed unresolved SCVP macros before dispatch:", unresolved.join(", "));
3862
+ }
3863
+ return url;
3864
+ };
3360
3865
  requestVast = function requestVast(creds) {
3361
3866
  return _async_to_generator(function() {
3362
- var response;
3867
+ var pending, response;
3363
3868
  return _ts_generator(this, function(_state) {
3364
3869
  switch(_state.label){
3365
3870
  case 0:
3366
3871
  attempt++;
3872
+ pending = fetch(resolveDispatchUrl(), _object_spread({
3873
+ mode: "cors",
3874
+ credentials: creds,
3875
+ headers: {
3876
+ "Accept": "application/xml, text/xml, */*"
3877
+ },
3878
+ referrerPolicy: "no-referrer-when-downgrade"
3879
+ }, controller ? {
3880
+ signal: controller.signal
3881
+ } : {}));
3367
3882
  if (kind !== "wrapper") {
3368
3883
  logFunnel("".concat(kind, "_http_request_sent"), {
3369
3884
  attempt: attempt,
@@ -3372,16 +3887,7 @@ function createHlsAdPlayer(contentVideo, options) {
3372
3887
  }
3373
3888
  return [
3374
3889
  4,
3375
- fetch(vastTagUrl, _object_spread({
3376
- mode: "cors",
3377
- credentials: creds,
3378
- headers: {
3379
- "Accept": "application/xml, text/xml, */*"
3380
- },
3381
- referrerPolicy: "no-referrer-when-downgrade"
3382
- }, controller ? {
3383
- signal: controller.signal
3384
- } : {}))
3890
+ pending
3385
3891
  ];
3386
3892
  case 1:
3387
3893
  response = _state.sent();
@@ -3405,9 +3911,9 @@ function createHlsAdPlayer(contentVideo, options) {
3405
3911
  case 1:
3406
3912
  _state.trys.push([
3407
3913
  1,
3408
- 10,
3409
- 11,
3410
- 12
3914
+ 7,
3915
+ 8,
3916
+ 9
3411
3917
  ]);
3412
3918
  _state.label = 2;
3413
3919
  case 2:
@@ -3415,7 +3921,7 @@ function createHlsAdPlayer(contentVideo, options) {
3415
3921
  2,
3416
3922
  4,
3417
3923
  ,
3418
- 8
3924
+ 5
3419
3925
  ]);
3420
3926
  return [
3421
3927
  4,
@@ -3425,36 +3931,21 @@ function createHlsAdPlayer(contentVideo, options) {
3425
3931
  response = _state.sent();
3426
3932
  return [
3427
3933
  3,
3428
- 8
3934
+ 5
3429
3935
  ];
3430
3936
  case 4:
3431
3937
  error = _state.sent();
3432
- if (!(credentials !== "omit" && !(controller === null || controller === void 0 ? void 0 : controller.signal.aborted))) return [
3433
- 3,
3434
- 6
3435
- ];
3436
- console.warn('[HlsAdPlayer] VAST fetch failed with credentials="'.concat(credentials, '", retrying without credentials:'), error);
3437
- logFunnel("vast_credentials_retry", {
3438
- errorMessage: error === null || error === void 0 ? void 0 : error.message
3439
- });
3440
- return [
3441
- 4,
3442
- requestVast("omit")
3443
- ];
3444
- case 5:
3445
- response = _state.sent();
3446
- return [
3447
- 3,
3448
- 7
3449
- ];
3450
- case 6:
3938
+ if (kind === "gam" && !(controller === null || controller === void 0 ? void 0 : controller.signal.aborted) && !isPodRequestAbortedError(error)) {
3939
+ gamCredentialsMode = credentials === "include" ? "omit" : "include";
3940
+ console.warn('[HlsAdPlayer] GAM fetch failed with credentials="'.concat(credentials, '"; next GAM request will use credentials="').concat(gamCredentialsMode, '":'), error);
3941
+ logFunnel("gam_credentials_mode_changed", {
3942
+ from: credentials,
3943
+ to: gamCredentialsMode,
3944
+ errorMessage: error === null || error === void 0 ? void 0 : error.message
3945
+ });
3946
+ }
3451
3947
  throw error;
3452
- case 7:
3453
- return [
3454
- 3,
3455
- 8
3456
- ];
3457
- case 8:
3948
+ case 5:
3458
3949
  if (!response.ok) {
3459
3950
  throw new Error("Failed to fetch VAST: HTTP ".concat(response.status, " ").concat(response.statusText));
3460
3951
  }
@@ -3462,12 +3953,12 @@ function createHlsAdPlayer(contentVideo, options) {
3462
3953
  4,
3463
3954
  response.text()
3464
3955
  ];
3465
- case 9:
3956
+ case 6:
3466
3957
  return [
3467
3958
  2,
3468
3959
  _state.sent()
3469
3960
  ];
3470
- case 10:
3961
+ case 7:
3471
3962
  error1 = _state.sent();
3472
3963
  if (controller === null || controller === void 0 ? void 0 : controller.signal.aborted) {
3473
3964
  if (pendingRequestAbortReason) {
@@ -3476,13 +3967,13 @@ function createHlsAdPlayer(contentVideo, options) {
3476
3967
  throw new Error("VAST request timeout after ".concat(VAST_REQUEST_TIMEOUT_MS, "ms: ").concat(vastTagUrl));
3477
3968
  }
3478
3969
  throw error1;
3479
- case 11:
3970
+ case 8:
3480
3971
  if (timeoutId !== void 0) clearTimeout(timeoutId);
3481
3972
  if (controller) pendingVastRequests.delete(controller);
3482
3973
  return [
3483
3974
  7
3484
3975
  ];
3485
- case 12:
3976
+ case 9:
3486
3977
  return [
3487
3978
  2
3488
3979
  ];
@@ -3615,7 +4106,7 @@ function createHlsAdPlayer(contentVideo, options) {
3615
4106
  });
3616
4107
  }
3617
4108
  function fetchAndParsePod(vastTagUrl) {
3618
- var source = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "gam";
4109
+ var source = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "gam", finalizeRequestUrl = arguments.length > 2 ? arguments[2] : void 0;
3619
4110
  return _async_to_generator(function() {
3620
4111
  var _root_getAttribute, _root_getAttribute1, isEdge, vastXml, trimmedXml, xmlDoc, root, adElements, _root_getAttribute2, _empty_errorUrls, empty, _empty_errorCode, resolveAd, candidates, podElements, buffet, resolveAll, ads, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, ad, err, _iteratorNormalCompletion1, _didIteratorError1, _iteratorError1, _iterator1, _step1, ad1, err;
3621
4112
  return _ts_generator(this, function(_state) {
@@ -3625,7 +4116,7 @@ function createHlsAdPlayer(contentVideo, options) {
3625
4116
  isEdge = source === "edge";
3626
4117
  return [
3627
4118
  4,
3628
- fetchVastXml(vastTagUrl, isEdge ? "omit" : "include", source)
4119
+ fetchVastXml(vastTagUrl, isEdge ? "omit" : gamCredentialsMode, source, finalizeRequestUrl)
3629
4120
  ];
3630
4121
  case 1:
3631
4122
  vastXml = _state.sent();
@@ -4948,7 +5439,7 @@ function createHlsAdPlayer(contentVideo, options) {
4948
5439
  case 2:
4949
5440
  return [
4950
5441
  4,
4951
- fetchAndParsePod(vastTagUrl, source)
5442
+ fetchAndParsePod(vastTagUrl, source, requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.finalizeRequestUrl)
4952
5443
  ];
4953
5444
  case 3:
4954
5445
  ads = _state.sent();
@@ -5525,95 +6016,38 @@ function getOrCreateNonceLoader(allowStorage) {
5525
6016
  function createPalNonceManager() {
5526
6017
  var currentNonce = "";
5527
6018
  var currentNonceManager;
6019
+ var pendingNonce;
5528
6020
  return {
5529
6021
  generateNonce: function generateNonce() {
5530
- return _async_to_generator(function() {
5531
- var options, _options_allowStorage, _options_adWillAutoPlay, _options_adWillPlayMuted, _options_playerVolume, _options_continuousPlayback, loader, goog, request, manager, error;
5532
- var _arguments = arguments;
5533
- return _ts_generator(this, function(_state) {
5534
- switch(_state.label){
5535
- case 0:
5536
- options = _arguments.length > 0 && _arguments[0] !== void 0 ? _arguments[0] : {};
5537
- _state.label = 1;
5538
- case 1:
5539
- _state.trys.push([
5540
- 1,
5541
- 4,
5542
- ,
5543
- 5
5544
- ]);
5545
- return [
5546
- 4,
5547
- loadPalSdk()
5548
- ];
5549
- case 2:
5550
- _state.sent();
5551
- loader = getOrCreateNonceLoader((_options_allowStorage = options.allowStorage) !== null && _options_allowStorage !== void 0 ? _options_allowStorage : true);
5552
- goog = window.goog;
5553
- request = new goog.pal.NonceRequest();
5554
- request.adWillAutoPlay = (_options_adWillAutoPlay = options.adWillAutoPlay) !== null && _options_adWillAutoPlay !== void 0 ? _options_adWillAutoPlay : true;
5555
- request.adWillPlayMuted = (_options_adWillPlayMuted = options.adWillPlayMuted) !== null && _options_adWillPlayMuted !== void 0 ? _options_adWillPlayMuted : false;
5556
- request.playerVolume = (_options_playerVolume = options.playerVolume) !== null && _options_playerVolume !== void 0 ? _options_playerVolume : request.adWillPlayMuted ? 0 : 1;
5557
- request.continuousPlayback = (_options_continuousPlayback = options.continuousPlayback) !== null && _options_continuousPlayback !== void 0 ? _options_continuousPlayback : true;
5558
- request.descriptionUrl = toDevSafeUrl(options.descriptionUrl || (typeof window !== "undefined" ? window.location.href : ""));
5559
- request.iconsSupported = true;
5560
- request.playerType = "StormcloudVideoPlayer";
5561
- request.playerVersion = "1.0";
5562
- request.supportedApiFrameworks = "2,7,9";
5563
- request.url = toDevSafeUrl(options.descriptionUrl || (typeof window !== "undefined" ? window.location.href : ""));
5564
- request.videoWidth = options.videoWidth || 640;
5565
- request.videoHeight = options.videoHeight || 480;
5566
- if (options.ppid) request.ppid = options.ppid;
5567
- if (options.sessionId) request.sessionId = options.sessionId;
5568
- console.log("[PAL] NonceRequest before generateNonce:", JSON.stringify({
5569
- adWillAutoPlay: request.adWillAutoPlay,
5570
- adWillPlayMuted: request.adWillPlayMuted,
5571
- playerVolume: request.playerVolume,
5572
- continuousPlayback: request.continuousPlayback,
5573
- descriptionUrl: request.descriptionUrl,
5574
- iconsSupported: request.iconsSupported,
5575
- playerType: request.playerType,
5576
- playerVersion: request.playerVersion,
5577
- supportedApiFrameworks: request.supportedApiFrameworks,
5578
- url: request.url,
5579
- videoWidth: request.videoWidth,
5580
- videoHeight: request.videoHeight,
5581
- ppid: request.ppid,
5582
- sessionId: request.sessionId
5583
- }, null, 2));
5584
- return [
5585
- 4,
5586
- loader.loadNonceManager(request)
5587
- ];
5588
- case 3:
5589
- manager = _state.sent();
5590
- currentNonceManager = manager;
5591
- currentNonce = manager.getNonce();
5592
- console.log("[PAL] Nonce generated successfully");
5593
- return [
5594
- 2,
5595
- currentNonce
5596
- ];
5597
- case 4:
5598
- error = _state.sent();
5599
- console.warn("[PAL] Failed to generate nonce:", error);
5600
- currentNonce = "";
5601
- currentNonceManager = void 0;
5602
- return [
5603
- 2,
5604
- ""
5605
- ];
5606
- case 5:
5607
- return [
5608
- 2
5609
- ];
5610
- }
5611
- });
5612
- }).apply(this, arguments);
6022
+ var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
6023
+ var run = generate(options);
6024
+ pendingNonce = run;
6025
+ var settle = function settle() {
6026
+ if (pendingNonce === run) pendingNonce = void 0;
6027
+ };
6028
+ run.then(settle, settle);
6029
+ return run;
5613
6030
  },
5614
6031
  getCurrentNonce: function getCurrentNonce() {
5615
6032
  return currentNonce;
5616
6033
  },
6034
+ waitForNonce: function waitForNonce(maxWaitMs) {
6035
+ if (currentNonce) return Promise.resolve(currentNonce);
6036
+ var pending = pendingNonce;
6037
+ if (!pending || !(maxWaitMs > 0)) return Promise.resolve("");
6038
+ return new Promise(function(resolve) {
6039
+ var timer = setTimeout(function() {
6040
+ return resolve(currentNonce);
6041
+ }, maxWaitMs);
6042
+ pending.then(function(nonce) {
6043
+ clearTimeout(timer);
6044
+ resolve(nonce);
6045
+ }, function() {
6046
+ clearTimeout(timer);
6047
+ resolve("");
6048
+ });
6049
+ });
6050
+ },
5617
6051
  injectNonce: function injectNonce(vastTagUrl) {
5618
6052
  if (!currentNonce || !vastTagUrl) return vastTagUrl;
5619
6053
  try {
@@ -5650,8 +6084,90 @@ function createPalNonceManager() {
5650
6084
  reset: function reset() {
5651
6085
  currentNonce = "";
5652
6086
  currentNonceManager = void 0;
6087
+ pendingNonce = void 0;
5653
6088
  }
5654
6089
  };
6090
+ function generate(options) {
6091
+ return _async_to_generator(function() {
6092
+ var _options_allowStorage, _options_adWillAutoPlay, _options_adWillPlayMuted, _options_playerVolume, _options_continuousPlayback, loader, goog, request, manager, error;
6093
+ return _ts_generator(this, function(_state) {
6094
+ switch(_state.label){
6095
+ case 0:
6096
+ _state.trys.push([
6097
+ 0,
6098
+ 3,
6099
+ ,
6100
+ 4
6101
+ ]);
6102
+ return [
6103
+ 4,
6104
+ loadPalSdk()
6105
+ ];
6106
+ case 1:
6107
+ _state.sent();
6108
+ loader = getOrCreateNonceLoader((_options_allowStorage = options.allowStorage) !== null && _options_allowStorage !== void 0 ? _options_allowStorage : true);
6109
+ goog = window.goog;
6110
+ request = new goog.pal.NonceRequest();
6111
+ request.adWillAutoPlay = (_options_adWillAutoPlay = options.adWillAutoPlay) !== null && _options_adWillAutoPlay !== void 0 ? _options_adWillAutoPlay : true;
6112
+ request.adWillPlayMuted = (_options_adWillPlayMuted = options.adWillPlayMuted) !== null && _options_adWillPlayMuted !== void 0 ? _options_adWillPlayMuted : false;
6113
+ request.playerVolume = (_options_playerVolume = options.playerVolume) !== null && _options_playerVolume !== void 0 ? _options_playerVolume : request.adWillPlayMuted ? 0 : 1;
6114
+ request.continuousPlayback = (_options_continuousPlayback = options.continuousPlayback) !== null && _options_continuousPlayback !== void 0 ? _options_continuousPlayback : true;
6115
+ request.descriptionUrl = toDevSafeUrl(options.descriptionUrl || (typeof window !== "undefined" ? window.location.href : ""));
6116
+ request.iconsSupported = true;
6117
+ request.playerType = "StormcloudVideoPlayer";
6118
+ request.playerVersion = "1.0";
6119
+ request.supportedApiFrameworks = "2,7,9";
6120
+ request.url = toDevSafeUrl(options.descriptionUrl || (typeof window !== "undefined" ? window.location.href : ""));
6121
+ request.videoWidth = options.videoWidth || 640;
6122
+ request.videoHeight = options.videoHeight || 480;
6123
+ if (options.ppid) request.ppid = options.ppid;
6124
+ if (options.sessionId) request.sessionId = options.sessionId;
6125
+ console.log("[PAL] NonceRequest before generateNonce:", JSON.stringify({
6126
+ adWillAutoPlay: request.adWillAutoPlay,
6127
+ adWillPlayMuted: request.adWillPlayMuted,
6128
+ playerVolume: request.playerVolume,
6129
+ continuousPlayback: request.continuousPlayback,
6130
+ descriptionUrl: request.descriptionUrl,
6131
+ iconsSupported: request.iconsSupported,
6132
+ playerType: request.playerType,
6133
+ playerVersion: request.playerVersion,
6134
+ supportedApiFrameworks: request.supportedApiFrameworks,
6135
+ url: request.url,
6136
+ videoWidth: request.videoWidth,
6137
+ videoHeight: request.videoHeight,
6138
+ ppid: request.ppid,
6139
+ sessionId: request.sessionId
6140
+ }, null, 2));
6141
+ return [
6142
+ 4,
6143
+ loader.loadNonceManager(request)
6144
+ ];
6145
+ case 2:
6146
+ manager = _state.sent();
6147
+ currentNonceManager = manager;
6148
+ currentNonce = manager.getNonce();
6149
+ console.log("[PAL] Nonce generated successfully");
6150
+ return [
6151
+ 2,
6152
+ currentNonce
6153
+ ];
6154
+ case 3:
6155
+ error = _state.sent();
6156
+ console.warn("[PAL] Failed to generate nonce:", error);
6157
+ currentNonce = "";
6158
+ currentNonceManager = void 0;
6159
+ return [
6160
+ 2,
6161
+ ""
6162
+ ];
6163
+ case 4:
6164
+ return [
6165
+ 2
6166
+ ];
6167
+ }
6168
+ });
6169
+ })();
6170
+ }
5655
6171
  }
5656
6172
  // src/utils/trackingIngest.ts
5657
6173
  var DEFAULT_TRACKING_INGEST_CONFIG = {
@@ -5740,7 +6256,14 @@ function ingestPlayerTracking(licenseKey, channel, body) {
5740
6256
  // src/utils/tracking.ts
5741
6257
  var cachedBrowserId = null;
5742
6258
  function buildAnalyticsContext(config) {
6259
+ var _config_contentNetwork, _config_channelName, _config_programTitle;
5743
6260
  var context = {};
6261
+ var contentNetwork = (_config_contentNetwork = config.contentNetwork) === null || _config_contentNetwork === void 0 ? void 0 : _config_contentNetwork.trim();
6262
+ var contentChannel = (_config_channelName = config.channelName) === null || _config_channelName === void 0 ? void 0 : _config_channelName.trim();
6263
+ var contentTitle = (_config_programTitle = config.programTitle) === null || _config_programTitle === void 0 ? void 0 : _config_programTitle.trim();
6264
+ if (contentNetwork) context.contentNetwork = contentNetwork;
6265
+ if (contentChannel) context.contentChannel = contentChannel;
6266
+ if (contentTitle) context.contentTitle = contentTitle;
5744
6267
  if (config.debugAdTiming) {
5745
6268
  context.debugAdTiming = true;
5746
6269
  }
@@ -6231,12 +6754,19 @@ function sendAdImpressionTracking(_0, _1) {
6231
6754
  4,
6232
6755
  ingestPlayerTracking(licenseKey, "impressions", {
6233
6756
  events: [
6234
- {
6757
+ _object_spread({
6235
6758
  player_id: metricEvent.player_id,
6236
6759
  ad_played_count: 1,
6237
6760
  ad_url: adImpressionInfo.adUrl,
6238
- capture_at: adImpressionInfo.timestamp
6239
- }
6761
+ capture_at: adImpressionInfo.timestamp,
6762
+ source: "gam"
6763
+ }, context.contentNetwork ? {
6764
+ content_network: context.contentNetwork
6765
+ } : {}, context.contentChannel ? {
6766
+ content_channel: context.contentChannel
6767
+ } : {}, context.contentTitle ? {
6768
+ content_title: context.contentTitle
6769
+ } : {})
6240
6770
  ]
6241
6771
  })
6242
6772
  ];
@@ -7585,6 +8115,21 @@ var Scte35CueManager = /*#__PURE__*/ function() {
7585
8115
  return Scte35CueManager;
7586
8116
  }();
7587
8117
  // src/player/AdConfigManager.ts
8118
+ function withDeferredPodParams(rawUrl, deferNonce) {
8119
+ try {
8120
+ var url = new URL(rawUrl);
8121
+ url.searchParams.set("pmnd", "[SCVP-PMND]");
8122
+ url.searchParams.set("pmxd", "[SCVP-PMXD]");
8123
+ url.searchParams.set("pmad", "[SCVP-PMAD]");
8124
+ if (deferNonce && !url.searchParams.get("givn")) {
8125
+ url.searchParams.delete("paln");
8126
+ url.searchParams.set("givn", "[SCVP-GIVN]");
8127
+ }
8128
+ return url.toString();
8129
+ } catch (unused) {
8130
+ return rawUrl;
8131
+ }
8132
+ }
7588
8133
  var AdConfigManager = /*#__PURE__*/ function() {
7589
8134
  function AdConfigManager(config, video) {
7590
8135
  _class_call_check(this, AdConfigManager);
@@ -7595,8 +8140,8 @@ var AdConfigManager = /*#__PURE__*/ function() {
7595
8140
  this.podCounter = 0;
7596
8141
  this.podAssignedByPrefetch = false;
7597
8142
  this.lastHeartbeatTime = 0;
7598
- this.defaultPodMaxAds = 6;
7599
- this.defaultPodMaxDurationMs = 12e4;
8143
+ this.defaultEdgePodMaxAds = 6;
8144
+ this.palNonceDispatchWaitMs = 1500;
7600
8145
  this.config = config;
7601
8146
  this.video = video;
7602
8147
  }
@@ -7624,7 +8169,7 @@ var AdConfigManager = /*#__PURE__*/ function() {
7624
8169
  key: "fetchAdConfiguration",
7625
8170
  value: function fetchAdConfiguration() {
7626
8171
  return _async_to_generator(function() {
7627
- var _data_response_ima_publisherdeskima, _data_response_ima, _data_response, _data_response_options_vast_cue_tones, _data_response_options_vast, _data_response_options, _data_response1, vastMode, vastEndpoint, apiUrl, headers, response, data, imaPayload, decodedPayload, numberAds;
8172
+ var _data_response_ima_publisherdeskima, _data_response_ima, _data_response, _data_response_options_vast_cue_tones, _data_response_options_vast, _data_response_options, _data_response1, apiUrl, headers, response, data, imaPayload, decodedPayload, numberAds;
7628
8173
  return _ts_generator(this, function(_state) {
7629
8174
  switch(_state.label){
7630
8175
  case 0:
@@ -7645,28 +8190,6 @@ var AdConfigManager = /*#__PURE__*/ function() {
7645
8190
  2
7646
8191
  ];
7647
8192
  case 2:
7648
- vastMode = this.config.vastMode || "default";
7649
- if (this.debug) {
7650
- console.log("[StormcloudVideoPlayer] VAST mode:", vastMode);
7651
- }
7652
- if (vastMode === "adstorm") {
7653
- if (!this.config.licenseKey) {
7654
- if (this.debug) {
7655
- console.warn("[StormcloudVideoPlayer] AdStorm mode requires a license key");
7656
- }
7657
- return [
7658
- 2
7659
- ];
7660
- }
7661
- vastEndpoint = "https://adstorm.co/api-adstorm-dev/adstorm/vast/".concat(this.config.licenseKey);
7662
- this.apiVastTagUrl = vastEndpoint;
7663
- if (this.debug) {
7664
- console.log("[StormcloudVideoPlayer] Using AdStorm VAST endpoint (adstorm mode):", vastEndpoint);
7665
- }
7666
- return [
7667
- 2
7668
- ];
7669
- }
7670
8193
  if (this.config.vastTagUrl) {
7671
8194
  this.apiVastTagUrl = normalizeVastTagUrl(this.config.vastTagUrl);
7672
8195
  if (this.debug) {
@@ -7676,7 +8199,7 @@ var AdConfigManager = /*#__PURE__*/ function() {
7676
8199
  2
7677
8200
  ];
7678
8201
  }
7679
- apiUrl = "https://adstorm.co/api-adstorm-dev/adstorm/ads/web";
8202
+ apiUrl = "https://edge.stormcloudhub.com/api/v1/adstorm/ads/web";
7680
8203
  if (this.debug) {
7681
8204
  console.log("[StormcloudVideoPlayer] Fetching ad configuration from:", apiUrl);
7682
8205
  }
@@ -8023,16 +8546,16 @@ var AdConfigManager = /*#__PURE__*/ function() {
8023
8546
  }
8024
8547
  },
8025
8548
  {
8026
- key: "resolvePodParams",
8027
- value: function resolvePodParams(breakDurationMs) {
8028
- var maxDurationMs = breakDurationMs != null && breakDurationMs > 0 ? breakDurationMs : this.config.podMaxDurationMs != null && this.config.podMaxDurationMs > 0 ? this.config.podMaxDurationMs : this.defaultPodMaxDurationMs;
8029
- var maxAds = this.config.podMaxAds && this.config.podMaxAds > 0 ? this.config.podMaxAds : this.apiNumberAds && this.apiNumberAds > 0 ? this.apiNumberAds : this.defaultPodMaxAds;
8030
- var minDurationMs = this.config.podExactDuration && maxDurationMs != null ? maxDurationMs : 0;
8031
- return {
8032
- maxAds: maxAds,
8033
- minDurationMs: minDurationMs,
8034
- maxDurationMs: maxDurationMs
8035
- };
8549
+ key: "resolveAdPodConfig",
8550
+ value: function resolveAdPodConfig1() {
8551
+ return resolveAdPodConfig(this.config);
8552
+ }
8553
+ },
8554
+ {
8555
+ key: "resolveEdgeMaxAds",
8556
+ value: function resolveEdgeMaxAds() {
8557
+ var _this_resolveAdPodConfig_maxAdsPerBreak;
8558
+ return (_this_resolveAdPodConfig_maxAdsPerBreak = this.resolveAdPodConfig().maxAdsPerBreak) !== null && _this_resolveAdPodConfig_maxAdsPerBreak !== void 0 ? _this_resolveAdPodConfig_maxAdsPerBreak : this.apiNumberAds && this.apiNumberAds > 0 ? this.apiNumberAds : this.defaultEdgePodMaxAds;
8036
8559
  }
8037
8560
  },
8038
8561
  {
@@ -8049,17 +8572,13 @@ var AdConfigManager = /*#__PURE__*/ function() {
8049
8572
  },
8050
8573
  {
8051
8574
  key: "generatePodVastUrl",
8052
- value: function generatePodVastUrl(baseUrl, podParams, adPlayer, palNonce, inAdBreak) {
8053
- var _podParams_maxDurationMs;
8575
+ value: function generatePodVastUrl(baseUrl, adPlayer, palNonce, inAdBreak) {
8054
8576
  var adWillPlayMuted = inAdBreak ? adPlayer.getOriginalMutedState() : this.video.muted;
8055
8577
  var envSignals = resolveVastEnvironmentSignals(!!this.config.ctvAdRequest);
8056
- var urlWithMacros = applyVastMacros(baseUrl, _object_spread_props(_object_spread({
8578
+ var macroContext = _object_spread_props(_object_spread({
8057
8579
  correlator: this.viewCorrelator,
8058
8580
  streamCorrelator: this.streamCorrelator,
8059
8581
  pod: this.podCounter > 0 ? this.podCounter : void 0,
8060
- podMaxAds: podParams.maxAds,
8061
- podMinDurationMs: podParams.minDurationMs,
8062
- podMaxDurationMs: podParams.maxDurationMs,
8063
8582
  isCtv: envSignals.isCtv,
8064
8583
  pageUrl: !envSignals.isCtv && typeof window !== "undefined" ? toDevSafeUrl(window.location.href) : void 0,
8065
8584
  adWillPlayMuted: adWillPlayMuted,
@@ -8075,13 +8594,72 @@ var AdConfigManager = /*#__PURE__*/ function() {
8075
8594
  } : {}, this.config.channelName ? {
8076
8595
  channelName: this.config.channelName
8077
8596
  } : {}), {
8078
- consent: this.consentSignals
8079
- }));
8080
- var finalUrl = palNonce.injectNonce(ensureVideoAdType(urlWithMacros));
8081
- console.log("[StormcloudVideoPlayer] Resolved optimized-pod request URL (pod=".concat(this.podCounter, ", pmad=").concat(podParams.maxAds, ", pmnd=").concat(podParams.minDurationMs, ", pmxd=").concat((_podParams_maxDurationMs = podParams.maxDurationMs) !== null && _podParams_maxDurationMs !== void 0 ? _podParams_maxDurationMs : "?", "):"), finalUrl);
8597
+ consent: this.consentSignals,
8598
+ palNonce: palNonce.getCurrentNonce() || void 0
8599
+ });
8600
+ var nonceReady = !!macroContext.palNonce;
8601
+ var finalUrl;
8602
+ if (hasScvpMacros(baseUrl)) {
8603
+ var deferred = new Set(SCVP_POD_MACROS);
8604
+ if (!nonceReady) deferred.add("GIVN");
8605
+ var _applyScvpMacros = applyScvpMacros(baseUrl, macroContext, deferred), url = _applyScvpMacros.url, unresolved = _applyScvpMacros.unresolved;
8606
+ if (unresolved.length > 0) {
8607
+ console.warn("[StormcloudVideoPlayer] Unresolved SCVP macros (removed from request):", unresolved.join(", "));
8608
+ }
8609
+ finalUrl = ensureVideoAdType(url);
8610
+ } else {
8611
+ finalUrl = withDeferredPodParams(palNonce.injectNonce(ensureVideoAdType(applyVastMacros(baseUrl, macroContext))), !nonceReady);
8612
+ }
8613
+ console.log("[StormcloudVideoPlayer] Prepared optimized-pod request URL (pod=".concat(this.podCounter, "; pmnd/pmxd/pmad resolved at dispatch):"), finalUrl);
8082
8614
  return finalUrl;
8083
8615
  }
8084
8616
  },
8617
+ {
8618
+ key: "completeDeferredRequestSignals",
8619
+ value: function completeDeferredRequestSignals(url, palNonce) {
8620
+ return _async_to_generator(function() {
8621
+ var nonce, _tmp;
8622
+ return _ts_generator(this, function(_state) {
8623
+ switch(_state.label){
8624
+ case 0:
8625
+ if (findScvpMacroNames(url).indexOf("GIVN") === -1) return [
8626
+ 2,
8627
+ url
8628
+ ];
8629
+ _tmp = palNonce.getCurrentNonce();
8630
+ if (_tmp) return [
8631
+ 3,
8632
+ 2
8633
+ ];
8634
+ return [
8635
+ 4,
8636
+ palNonce.waitForNonce(this.palNonceDispatchWaitMs)
8637
+ ];
8638
+ case 1:
8639
+ _tmp = _state.sent();
8640
+ _state.label = 2;
8641
+ case 2:
8642
+ nonce = _tmp;
8643
+ if (!nonce) return [
8644
+ 2,
8645
+ url
8646
+ ];
8647
+ return [
8648
+ 2,
8649
+ substituteScvpMacros(url, /* @__PURE__ */ new Map([
8650
+ [
8651
+ "GIVN",
8652
+ nonce
8653
+ ]
8654
+ ]), function(name) {
8655
+ return name !== "GIVN";
8656
+ }).url
8657
+ ];
8658
+ }
8659
+ });
8660
+ }).call(this);
8661
+ }
8662
+ },
8085
8663
  {
8086
8664
  // --- Tracking ---
8087
8665
  key: "initializeTracking",
@@ -8129,6 +8707,9 @@ var AdConfigManager = /*#__PURE__*/ function() {
8129
8707
  return AdConfigManager;
8130
8708
  }();
8131
8709
  // src/player/AdTimingService.ts
8710
+ function monotonicNow() {
8711
+ return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
8712
+ }
8132
8713
  var AdTimingService = /*#__PURE__*/ function() {
8133
8714
  function AdTimingService(config, video, callbacks) {
8134
8715
  _class_call_check(this, AdTimingService);
@@ -8259,6 +8840,21 @@ var AdTimingService = /*#__PURE__*/ function() {
8259
8840
  },
8260
8841
  {
8261
8842
  // --- Duration boundary ---
8843
+ key: "beginBreakTiming",
8844
+ value: function beginBreakTiming(startWallClockMs) {
8845
+ this.currentAdBreakStartWallClockMs = startWallClockMs;
8846
+ this.breakStartMonoMs = monotonicNow() + (startWallClockMs - Date.now());
8847
+ this.breakEndMonoMs = void 0;
8848
+ }
8849
+ },
8850
+ {
8851
+ key: "markBreakEndedNow",
8852
+ value: function markBreakEndedNow() {
8853
+ this.scteAdBreakEndWallClockMs = Date.now();
8854
+ this.breakEndMonoMs = monotonicNow();
8855
+ }
8856
+ },
8857
+ {
8262
8858
  key: "setAdBreakDurationBoundary",
8263
8859
  value: function setAdBreakDurationBoundary(durationMs) {
8264
8860
  this.expectedAdBreakDurationMs = durationMs;
@@ -8267,6 +8863,18 @@ var AdTimingService = /*#__PURE__*/ function() {
8267
8863
  } else {
8268
8864
  this.scteAdBreakEndWallClockMs = void 0;
8269
8865
  }
8866
+ this.breakEndMonoMs = durationMs != null && this.breakStartMonoMs != null ? this.breakStartMonoMs + durationMs : void 0;
8867
+ }
8868
+ },
8869
+ {
8870
+ key: "getBreakTimingSnapshot",
8871
+ value: function getBreakTimingSnapshot() {
8872
+ return {
8873
+ scheduledBreakDurationMs: this.expectedAdBreakDurationMs,
8874
+ breakStartMonoMs: this.breakStartMonoMs,
8875
+ breakEndMonoMs: this.breakEndMonoMs,
8876
+ playedDurationMs: this.adBreakPlayedDurationMs
8877
+ };
8270
8878
  }
8271
8879
  },
8272
8880
  {
@@ -8680,6 +9288,8 @@ var AdTimingService = /*#__PURE__*/ function() {
8680
9288
  this.expectedAdBreakDurationMs = void 0;
8681
9289
  this.currentAdBreakStartWallClockMs = void 0;
8682
9290
  this.scteAdBreakEndWallClockMs = void 0;
9291
+ this.breakStartMonoMs = void 0;
9292
+ this.breakEndMonoMs = void 0;
8683
9293
  this.adBreakPlayedDurationMs = 0;
8684
9294
  this.currentAdIndex = 0;
8685
9295
  this.totalAdsInBreak = 0;
@@ -9693,9 +10303,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
9693
10303
  // ───────────────────────────────────────────────────────────────
9694
10304
  key: "nextAdRequestUrl",
9695
10305
  value: function nextAdRequestUrl(baseVastUrl) {
9696
- var remaining = Math.min(this.timing.getWallClockRemainingAdMs(), this.timing.getDurationBudgetRemainingMs());
9697
- var breakDurationMs = remaining > 0 ? remaining : void 0;
9698
- return this.host.generatePodVastUrl(baseVastUrl, breakDurationMs);
10306
+ return this.host.generatePodVastUrl(baseVastUrl);
9699
10307
  }
9700
10308
  },
9701
10309
  {
@@ -9958,7 +10566,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
9958
10566
  key: "handleAdStart",
9959
10567
  value: function handleAdStart(marker) {
9960
10568
  return _async_to_generator(function() {
9961
- var baseVastUrl, edgeConfigured, adBreakDurationMs, currentMuted, currentVolume, epoch, hasPrefetchedUrl, mode, edgeUrl, outcome, podPlayed;
10569
+ var baseVastUrl, edgeConfigured, adBreakDurationMs, currentMuted, currentVolume, epoch, mode, edgeUrl, outcome, podPlayed;
9962
10570
  return _ts_generator(this, function(_state) {
9963
10571
  switch(_state.label){
9964
10572
  case 0:
@@ -10010,8 +10618,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
10010
10618
  }
10011
10619
  this.noteOpportunity("scte35", this.cueManager.activeScte35BreakKey, "midroll");
10012
10620
  epoch = this.timing.adBreakEpoch;
10013
- hasPrefetchedUrl = !!(this.pendingAdBreak && this.pendingAdBreak.vastUrls.length > 0);
10014
- if (!(adBreakDurationMs == null && (!hasPrefetchedUrl || edgeConfigured))) return [
10621
+ if (!(adBreakDurationMs == null)) return [
10015
10622
  3,
10016
10623
  2
10017
10624
  ];
@@ -10067,7 +10674,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
10067
10674
  }
10068
10675
  return [
10069
10676
  4,
10070
- this.startOptimizedPod(baseVastUrl, adBreakDurationMs)
10677
+ this.startOptimizedPod(baseVastUrl)
10071
10678
  ];
10072
10679
  case 6:
10073
10680
  podPlayed = _state.sent();
@@ -10135,9 +10742,9 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
10135
10742
  value: // ───────────────────────────────────────────────────────────────
10136
10743
  // Optimized pod (single multi-ad request)
10137
10744
  // ───────────────────────────────────────────────────────────────
10138
- function startOptimizedPod(baseVastUrl, breakDurationMs) {
10745
+ function startOptimizedPod(baseVastUrl) {
10139
10746
  return _async_to_generator(function() {
10140
- var podUrl, prefetched, epoch, generation, adPlayer, requestToken, requestUrl, _ref, _adPlayer_getPodAdCount, podCount, error;
10747
+ var podUrl, prefetched, epoch, generation, adPlayer, requestToken, requestUrl, _ref, _this_currentVastUrl, _adPlayer_getPodAdCount, finalizeRequestUrl, podCount, error;
10141
10748
  return _ts_generator(this, function(_state) {
10142
10749
  switch(_state.label){
10143
10750
  case 0:
@@ -10146,7 +10753,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
10146
10753
  podUrl = this.pendingAdBreak.vastUrls[0];
10147
10754
  this.clearPendingAdBreak();
10148
10755
  } else {
10149
- podUrl = this.host.generatePodVastUrl(baseVastUrl, breakDurationMs);
10756
+ podUrl = this.host.generatePodVastUrl(baseVastUrl);
10150
10757
  }
10151
10758
  if (!podUrl) {
10152
10759
  return [
@@ -10170,9 +10777,9 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
10170
10777
  case 1:
10171
10778
  _state.trys.push([
10172
10779
  1,
10173
- 5,
10780
+ 9,
10174
10781
  ,
10175
- 6
10782
+ 10
10176
10783
  ]);
10177
10784
  return [
10178
10785
  4,
@@ -10184,15 +10791,46 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
10184
10791
  2,
10185
10792
  true
10186
10793
  ];
10794
+ return [
10795
+ 4,
10796
+ this.host.completeGamRequestSignals(requestUrl)
10797
+ ];
10798
+ case 3:
10799
+ requestUrl = _state.sent();
10800
+ if (this.isStale(epoch, generation)) return [
10801
+ 2,
10802
+ true
10803
+ ];
10187
10804
  this.timing.startAdRequestWatchdog(requestToken);
10805
+ finalizeRequestUrl = this.createGamDispatchFinalizer(requestToken);
10806
+ _state.label = 4;
10807
+ case 4:
10808
+ _state.trys.push([
10809
+ 4,
10810
+ ,
10811
+ 6,
10812
+ 7
10813
+ ]);
10188
10814
  return [
10189
10815
  4,
10190
10816
  this.callController(function() {
10191
- return adPlayer.requestAds(requestUrl);
10817
+ return adPlayer.requestAds(requestUrl, {
10818
+ finalizeRequestUrl: finalizeRequestUrl
10819
+ });
10192
10820
  })
10193
10821
  ];
10194
- case 3:
10822
+ case 5:
10195
10823
  _state.sent();
10824
+ return [
10825
+ 3,
10826
+ 7
10827
+ ];
10828
+ case 6:
10829
+ this.recordPodResponseDiagnostics(requestToken, adPlayer);
10830
+ return [
10831
+ 7
10832
+ ];
10833
+ case 7:
10196
10834
  this.timing.clearAdRequestWatchdog();
10197
10835
  if (this.isStale(epoch, generation)) {
10198
10836
  this.logOrchestratorFunnel("stale_request_result_ignored", {
@@ -10220,7 +10858,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
10220
10858
  }
10221
10859
  sendAdLoadedTracking(this.host.config.licenseKey, {
10222
10860
  source: "hls",
10223
- vastUrl: requestUrl,
10861
+ vastUrl: (_this_currentVastUrl = this.currentVastUrl) !== null && _this_currentVastUrl !== void 0 ? _this_currentVastUrl : requestUrl,
10224
10862
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
10225
10863
  }, this.analyticsContext).catch(function() {});
10226
10864
  this.timing.startAdFailsafeTimer(requestToken);
@@ -10230,7 +10868,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
10230
10868
  return adPlayer.play();
10231
10869
  })
10232
10870
  ];
10233
- case 4:
10871
+ case 8:
10234
10872
  _state.sent();
10235
10873
  if (this.isStale(epoch, generation)) return [
10236
10874
  2,
@@ -10244,7 +10882,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
10244
10882
  2,
10245
10883
  true
10246
10884
  ];
10247
- case 5:
10885
+ case 9:
10248
10886
  error = _state.sent();
10249
10887
  this.timing.clearAdRequestWatchdog();
10250
10888
  this.timing.clearAdFailsafeTimer();
@@ -10264,12 +10902,16 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
10264
10902
  if (this.debug) {
10265
10903
  console.warn("[POD] Optimized pod request/play failed:", error);
10266
10904
  }
10905
+ if (this.handlePodRequestNotSent(error)) return [
10906
+ 2,
10907
+ false
10908
+ ];
10267
10909
  this.recordRequestFailure(error, podUrl);
10268
10910
  return [
10269
10911
  2,
10270
10912
  false
10271
10913
  ];
10272
- case 6:
10914
+ case 10:
10273
10915
  return [
10274
10916
  2
10275
10917
  ];
@@ -10315,17 +10957,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
10315
10957
  }
10316
10958
  },
10317
10959
  {
10318
- /**
10319
- * Builds the next Edge request from the budget left right now, or marks Edge
10320
- * exhausted for this break. Synchronous on purpose: callers must reach the
10321
- * REQUESTING state in the same tick so a second completion event cannot race
10322
- * in a parallel request.
10323
- */ key: "prepareEdgePodRequest",
10960
+ key: "prepareEdgePodRequest",
10324
10961
  value: function prepareEdgePodRequest() {
10325
10962
  var baseUrl = this.host.getEdgePodBaseUrl();
10326
10963
  if (!baseUrl) return void 0;
10327
10964
  var remainingMs = this.timing.getRemainingAdMs();
10328
- var remainingAds = Math.min(EDGE_POD_MAX_ADS, this.adConfig.resolvePodParams().maxAds - this.timing.totalAdsInBreak);
10965
+ var remainingAds = Math.min(EDGE_POD_MAX_ADS, this.adConfig.resolveEdgeMaxAds() - this.timing.totalAdsInBreak);
10329
10966
  if (remainingAds < 1) {
10330
10967
  this.markEdgeExhausted("ad_capacity_reached", {
10331
10968
  adsInBreak: this.timing.totalAdsInBreak
@@ -10404,7 +11041,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
10404
11041
  ];
10405
11042
  }
10406
11043
  remainingMs = this.timing.getRemainingAdMs();
10407
- remainingAds = Math.max(1, Math.min(EDGE_POD_MAX_ADS, this.adConfig.resolvePodParams().maxAds - this.timing.totalAdsInBreak));
11044
+ remainingAds = Math.max(1, Math.min(EDGE_POD_MAX_ADS, this.adConfig.resolveEdgeMaxAds() - this.timing.totalAdsInBreak));
10408
11045
  overrunAllowanceMs = Math.max(0, (_this_host_config_maxAdBreakExtensionMs = this.host.config.maxAdBreakExtensionMs) !== null && _this_host_config_maxAdBreakExtensionMs !== void 0 ? _this_host_config_maxAdBreakExtensionMs : 0);
10409
11046
  podCount = adPlayer.limitPodToBudget ? adPlayer.limitPodToBudget(remainingMs + overrunAllowanceMs, remainingAds) : (_ref = (_adPlayer_getPodAdCount = adPlayer.getPodAdCount) === null || _adPlayer_getPodAdCount === void 0 ? void 0 : _adPlayer_getPodAdCount.call(adPlayer)) !== null && _ref !== void 0 ? _ref : 0;
10410
11047
  if (classifyEdgeVastResponse({
@@ -10751,7 +11388,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
10751
11388
  {
10752
11389
  key: "noteVastUrlGenerated",
10753
11390
  value: function noteVastUrlGenerated(url, source) {
10754
- var _ref, _ref1, _ref2, _ref3, _ref4;
11391
+ var _ref, _ref1;
10755
11392
  var params;
10756
11393
  try {
10757
11394
  params = new URL(url).searchParams;
@@ -10761,9 +11398,9 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
10761
11398
  requestId: void 0,
10762
11399
  source: source,
10763
11400
  pod: (_ref1 = params === null || params === void 0 ? void 0 : params.get("pod")) !== null && _ref1 !== void 0 ? _ref1 : void 0,
10764
- pmad: (_ref2 = params === null || params === void 0 ? void 0 : params.get("pmad")) !== null && _ref2 !== void 0 ? _ref2 : void 0,
10765
- pmnd: (_ref3 = params === null || params === void 0 ? void 0 : params.get("pmnd")) !== null && _ref3 !== void 0 ? _ref3 : void 0,
10766
- pmxd: (_ref4 = params === null || params === void 0 ? void 0 : params.get("pmxd")) !== null && _ref4 !== void 0 ? _ref4 : void 0,
11401
+ podParamsDeferredToDispatch: findScvpMacroNames(url).some(function(name) {
11402
+ return SCVP_POD_MACROS.has(name);
11403
+ }),
10767
11404
  adType: adType
10768
11405
  });
10769
11406
  if (adType === "audio" || adType === "audio_video") {
@@ -10804,10 +11441,13 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
10804
11441
  if (diag && !diag.failureReason) {
10805
11442
  diag.failureReason = "".concat(outcome, ": ").concat(message);
10806
11443
  }
11444
+ var failureKey = (diag === null || diag === void 0 ? void 0 : diag.dispatchedUrl) && findScvpMacroNames(vastTagUrl).some(function(name) {
11445
+ return SCVP_POD_MACROS.has(name);
11446
+ }) ? diag.dispatchedUrl : vastTagUrl;
10807
11447
  if (this.timing.isTemporaryAdError(error)) {
10808
- this.timing.temporaryFailureUrls.set(vastTagUrl, Date.now());
11448
+ this.timing.temporaryFailureUrls.set(failureKey, Date.now());
10809
11449
  } else if (outcome !== "discarded_budget") {
10810
- this.timing.failedVastUrls.add(vastTagUrl);
11450
+ this.timing.failedVastUrls.add(failureKey);
10811
11451
  }
10812
11452
  this.countFunnelStage("request_outcome:".concat(outcome));
10813
11453
  this.logOrchestratorFunnel("request_outcome", _object_spread({
@@ -10833,6 +11473,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
10833
11473
  switch(payload.stage){
10834
11474
  case "gam_http_request_sent":
10835
11475
  diag.gamRequestSent++;
11476
+ this.logPodDispatch(diag);
10836
11477
  break;
10837
11478
  case "edge_http_request_sent":
10838
11479
  diag.edgeRequestSent++;
@@ -10884,8 +11525,10 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
10884
11525
  if (gamReturnedAdWithoutImpression) {
10885
11526
  this.countFunnelStage("gam_ad_without_impression");
10886
11527
  }
10887
- var startedAt = diag.startedAt, fields = _object_without_properties(diag, [
10888
- "startedAt"
11528
+ var startedAt = diag.startedAt, _dispatchedUrl = diag.dispatchedUrl, _logged = diag.podDispatchLogged, fields = _object_without_properties(diag, [
11529
+ "startedAt",
11530
+ "dispatchedUrl",
11531
+ "podDispatchLogged"
10889
11532
  ]);
10890
11533
  console.log("[AdBreak][REQUEST] summary", _object_spread_props(_object_spread({}, fields), {
10891
11534
  durationMs: Date.now() - startedAt,
@@ -10897,24 +11540,71 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
10897
11540
  // ───────────────────────────────────────────────────────────────
10898
11541
  // Single ad playback
10899
11542
  // ───────────────────────────────────────────────────────────────
10900
- key: "withCurrentPodBudget",
10901
- value: function withCurrentPodBudget(rawVastTagUrl) {
10902
- var vastTagUrl = ensureVideoAdType(rawVastTagUrl);
10903
- var remaining = Math.min(this.timing.getWallClockRemainingAdMs(), this.timing.getDurationBudgetRemainingMs());
10904
- if (!(remaining > 0)) return vastTagUrl;
10905
- try {
10906
- var url = new URL(vastTagUrl);
10907
- if (!url.searchParams.has("pmxd")) return vastTagUrl;
10908
- var maxMs = Math.round(remaining);
10909
- url.searchParams.set("pmxd", String(maxMs));
10910
- var minMs = Number(url.searchParams.get("pmnd"));
10911
- if (Number.isFinite(minMs) && minMs > maxMs) {
10912
- url.searchParams.set("pmnd", String(maxMs));
10913
- }
10914
- return url.toString();
10915
- } catch (unused) {
10916
- return vastTagUrl;
10917
- }
11543
+ key: "createGamDispatchFinalizer",
11544
+ value: function createGamDispatchFinalizer(requestToken) {
11545
+ var _this = this;
11546
+ var breakId = this.timing.adBreakEpoch;
11547
+ var config = this.adConfig.resolveAdPodConfig();
11548
+ var minUsablePmxdMs = this.timing.getMinRemainingMsToStartAd();
11549
+ return function(url) {
11550
+ var capacity = measureBreakCapacity(_this.timing.getBreakTimingSnapshot(), monotonicNow());
11551
+ var diag = _this.requestDiagnostics.get(requestToken);
11552
+ try {
11553
+ var result = finalizeGamRequestUrl(url, {
11554
+ breakId: breakId,
11555
+ capacity: capacity,
11556
+ config: config,
11557
+ minUsablePmxdMs: minUsablePmxdMs
11558
+ });
11559
+ if (diag) {
11560
+ diag.pod = result.diagnostics;
11561
+ diag.dispatchedUrl = result.url;
11562
+ diag.podDispatchLogged = false;
11563
+ }
11564
+ _this.currentVastUrl = result.url;
11565
+ return result.url;
11566
+ } catch (error) {
11567
+ if (diag && isPodRequestAbortedError(error)) {
11568
+ diag.failureReason = "pod_request_not_sent:".concat(error.reason);
11569
+ }
11570
+ throw error;
11571
+ }
11572
+ };
11573
+ }
11574
+ },
11575
+ {
11576
+ key: "logPodDispatch",
11577
+ value: function logPodDispatch(diag) {
11578
+ if (!diag.pod || diag.podDispatchLogged) return;
11579
+ diag.podDispatchLogged = true;
11580
+ this.logOrchestratorFunnel(diag.pod.optimizedPod ? "optimized_pod_request_dispatched" : "gam_request_dispatched", _object_spread({}, diag.pod));
11581
+ }
11582
+ },
11583
+ {
11584
+ key: "recordPodResponseDiagnostics",
11585
+ value: function recordPodResponseDiagnostics(requestToken, adPlayer) {
11586
+ var _diag_vastAdCount, _ref;
11587
+ var _adPlayer_getPodTotalDurationMs;
11588
+ var diag = this.requestDiagnostics.get(requestToken);
11589
+ if (!(diag === null || diag === void 0 ? void 0 : diag.pod) || diag.pod.pmxdSent == null || diag.podResponse) return;
11590
+ if (diag.gamRequestSent === 0 && diag.vastHttpStatus == null) return;
11591
+ diag.podResponse = computePodResponseDiagnostics(diag.pod.pmxdSent, (_diag_vastAdCount = diag.vastAdCount) !== null && _diag_vastAdCount !== void 0 ? _diag_vastAdCount : 0, (_ref = (_adPlayer_getPodTotalDurationMs = adPlayer.getPodTotalDurationMs) === null || _adPlayer_getPodTotalDurationMs === void 0 ? void 0 : _adPlayer_getPodTotalDurationMs.call(adPlayer)) !== null && _ref !== void 0 ? _ref : 0);
11592
+ this.logOrchestratorFunnel("optimized_pod_response", _object_spread({
11593
+ pmxdSent: diag.pod.pmxdSent
11594
+ }, diag.podResponse));
11595
+ }
11596
+ },
11597
+ {
11598
+ key: "handlePodRequestNotSent",
11599
+ value: function handlePodRequestNotSent(error) {
11600
+ if (!isPodRequestAbortedError(error) || error.reason === "invalid_url") return false;
11601
+ var aborted = error;
11602
+ this.countFunnelStage("request_outcome:pod_request_not_sent");
11603
+ this.logOrchestratorFunnel("pod_request_not_sent", _object_spread({
11604
+ reason: aborted.reason,
11605
+ errorMessage: aborted.message
11606
+ }, aborted.diagnostics));
11607
+ return true;
10918
11608
  }
10919
11609
  },
10920
11610
  {
@@ -11134,7 +11824,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
11134
11824
  value: function playSingleAd(vastTagUrl) {
11135
11825
  var trigger = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "vmap";
11136
11826
  return _async_to_generator(function() {
11137
- var epoch, generation, requestToken, ap, budgetedUrl, requestUrl, _ap_getLoadedAdDuration, adDurationS, remainingMs, error;
11827
+ var epoch, generation, requestToken, ap, requestUrl, _this_currentVastUrl, finalizeRequestUrl, _ap_getLoadedAdDuration, adDurationS, remainingMs, error;
11138
11828
  return _ts_generator(this, function(_state) {
11139
11829
  switch(_state.label){
11140
11830
  case 0:
@@ -11172,19 +11862,18 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
11172
11862
  requestToken = ++this.timing.adRequestTokenCounter;
11173
11863
  this.timing.activeAdRequestToken = requestToken;
11174
11864
  ap = this.host.getAdPlayer();
11175
- budgetedUrl = this.withCurrentPodBudget(vastTagUrl);
11176
11865
  this.currentPodSource = "gam";
11177
11866
  this.setSlotState("REQUESTING", trigger);
11178
11867
  this.beginFunnelRequest(ap, requestToken, trigger);
11179
- requestUrl = this.applyOpportunityFloor(budgetedUrl);
11868
+ requestUrl = this.applyOpportunityFloor(ensureVideoAdType(vastTagUrl));
11180
11869
  this.currentVastUrl = requestUrl;
11181
11870
  _state.label = 1;
11182
11871
  case 1:
11183
11872
  _state.trys.push([
11184
11873
  1,
11185
- 5,
11874
+ 9,
11186
11875
  ,
11187
- 6
11876
+ 10
11188
11877
  ]);
11189
11878
  return [
11190
11879
  4,
@@ -11195,15 +11884,45 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
11195
11884
  if (this.isStale(epoch, generation)) return [
11196
11885
  2
11197
11886
  ];
11887
+ return [
11888
+ 4,
11889
+ this.host.completeGamRequestSignals(requestUrl)
11890
+ ];
11891
+ case 3:
11892
+ requestUrl = _state.sent();
11893
+ if (this.isStale(epoch, generation)) return [
11894
+ 2
11895
+ ];
11198
11896
  this.timing.startAdRequestWatchdog(requestToken);
11897
+ finalizeRequestUrl = this.createGamDispatchFinalizer(requestToken);
11898
+ _state.label = 4;
11899
+ case 4:
11900
+ _state.trys.push([
11901
+ 4,
11902
+ ,
11903
+ 6,
11904
+ 7
11905
+ ]);
11199
11906
  return [
11200
11907
  4,
11201
11908
  this.callController(function() {
11202
- return ap.requestAds(requestUrl);
11909
+ return ap.requestAds(requestUrl, {
11910
+ finalizeRequestUrl: finalizeRequestUrl
11911
+ });
11203
11912
  })
11204
11913
  ];
11205
- case 3:
11914
+ case 5:
11206
11915
  _state.sent();
11916
+ return [
11917
+ 3,
11918
+ 7
11919
+ ];
11920
+ case 6:
11921
+ this.recordPodResponseDiagnostics(requestToken, ap);
11922
+ return [
11923
+ 7
11924
+ ];
11925
+ case 7:
11207
11926
  this.timing.clearAdRequestWatchdog();
11208
11927
  if (this.isStale(epoch, generation)) {
11209
11928
  this.logOrchestratorFunnel("stale_request_result_ignored", {
@@ -11215,7 +11934,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
11215
11934
  }
11216
11935
  sendAdLoadedTracking(this.host.config.licenseKey, {
11217
11936
  source: "hls",
11218
- vastUrl: requestUrl,
11937
+ vastUrl: (_this_currentVastUrl = this.currentVastUrl) !== null && _this_currentVastUrl !== void 0 ? _this_currentVastUrl : requestUrl,
11219
11938
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
11220
11939
  }, this.analyticsContext).catch(function() {});
11221
11940
  if (!this.timing.ensureLoadedAdFitsBudget(ap)) {
@@ -11236,7 +11955,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
11236
11955
  return ap.play();
11237
11956
  })
11238
11957
  ];
11239
- case 4:
11958
+ case 8:
11240
11959
  _state.sent();
11241
11960
  if (this.isStale(epoch, generation)) return [
11242
11961
  2
@@ -11248,9 +11967,9 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
11248
11967
  this.timing.temporaryFailureUrls.delete(vastTagUrl);
11249
11968
  return [
11250
11969
  3,
11251
- 6
11970
+ 10
11252
11971
  ];
11253
- case 5:
11972
+ case 9:
11254
11973
  error = _state.sent();
11255
11974
  this.timing.clearAdRequestWatchdog();
11256
11975
  this.timing.clearAdFailsafeTimer();
@@ -11267,12 +11986,13 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
11267
11986
  ];
11268
11987
  }
11269
11988
  if (this.debug) console.error("[AD-ERROR] Ad request failed:", error === null || error === void 0 ? void 0 : error.message);
11989
+ if (this.handlePodRequestNotSent(error)) throw error;
11270
11990
  this.recordRequestFailure(error, vastTagUrl);
11271
11991
  if ((error === null || error === void 0 ? void 0 : error.message) === "ad_duration_exceeds_budget") {
11272
11992
  this.recreateAdController("discarded_budget");
11273
11993
  }
11274
11994
  throw error;
11275
- case 6:
11995
+ case 10:
11276
11996
  return [
11277
11997
  2
11278
11998
  ];
@@ -11334,7 +12054,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
11334
12054
  playbackFailedAfterFill: count("request_outcome:playback_failed"),
11335
12055
  requestFailed: count("request_failed"),
11336
12056
  requestAbortedTimeout: count("request_aborted_timeout"),
11337
- credentialsRetries: count("vast_credentials_retry"),
12057
+ credentialsModeChanges: count("gam_credentials_mode_changed"),
11338
12058
  wrapperFailures: count("wrapper_fetch:failure"),
11339
12059
  noSupportedMedia: count("vast_no_supported_media"),
11340
12060
  vpaidOnly: count("vast_no_supported_media:vpaid"),
@@ -11870,8 +12590,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
11870
12590
  requiresMediaPipelineResetAfterAds: function requiresMediaPipelineResetAfterAds1() {
11871
12591
  return requiresMediaPipelineResetAfterAds();
11872
12592
  },
11873
- generatePodVastUrl: function generatePodVastUrl(base, breakDurationMs) {
11874
- return _this.generatePodVastUrl(base, breakDurationMs);
12593
+ generatePodVastUrl: function generatePodVastUrl(base) {
12594
+ return _this.generatePodVastUrl(base);
12595
+ },
12596
+ completeGamRequestSignals: function completeGamRequestSignals(url) {
12597
+ return _this.adConfig.completeDeferredRequestSignals(url, _this.palNonce);
11875
12598
  },
11876
12599
  getEdgePodBaseUrl: function getEdgePodBaseUrl() {
11877
12600
  return _this.edgePodBaseUrl;
@@ -11995,9 +12718,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
11995
12718
  },
11996
12719
  {
11997
12720
  key: "generatePodVastUrl",
11998
- value: function generatePodVastUrl(baseUrl, breakDurationMs) {
11999
- var podParams = this.adConfig.resolvePodParams(breakDurationMs);
12000
- return this.adConfig.generatePodVastUrl(baseUrl, podParams, this.adPlayer, this.palNonce, this.adBreak.inAdBreak);
12721
+ value: function generatePodVastUrl(baseUrl) {
12722
+ return this.adConfig.generatePodVastUrl(baseUrl, this.adPlayer, this.palNonce, this.adBreak.inAdBreak);
12001
12723
  }
12002
12724
  },
12003
12725
  {
@@ -12351,7 +13073,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
12351
13073
  activeAdRequest: this.timing.activeAdRequestToken !== null
12352
13074
  });
12353
13075
  }
12354
- this.timing.scteAdBreakEndWallClockMs = Date.now();
13076
+ this.timing.markBreakEndedNow();
12355
13077
  this.timing.clearAdStartTimer();
12356
13078
  this.timing.clearAdStopTimer();
12357
13079
  if (adPlaying) {
@@ -12378,7 +13100,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
12378
13100
  this.adBreak.inAdBreak = true;
12379
13101
  this.cueManager.activeScte35BreakKey = cueKey !== null && cueKey !== void 0 ? cueKey : this.cueManager.pendingScte35CueKey;
12380
13102
  this.cueManager.scheduledScte35BreakKey = void 0;
12381
- this.timing.currentAdBreakStartWallClockMs = this.timing.resolveScteBreakStartWallClockMs(marker);
13103
+ this.timing.beginBreakTiming(this.timing.resolveScteBreakStartWallClockMs(marker));
12382
13104
  this.timing.setAdBreakDurationBoundary(durationMs);
12383
13105
  this.adBreak.handleAdStart(marker);
12384
13106
  this.timing.scheduleAdStopAtBreakBoundary();
@@ -12424,9 +13146,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
12424
13146
  }
12425
13147
  this.adConfig.beginNewAdPod();
12426
13148
  this.adConfig.podAssignedByPrefetch = true;
12427
- var breakDurationMs = marker.durationSeconds != null ? marker.durationSeconds * 1e3 : void 0;
12428
13149
  var generatedUrls = [
12429
- this.generatePodVastUrl(baseVastUrl, breakDurationMs)
13150
+ this.generatePodVastUrl(baseVastUrl)
12430
13151
  ];
12431
13152
  this.adBreak.pendingAdBreak = _object_spread_props(_object_spread({
12432
13153
  marker: marker
@@ -12525,7 +13246,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
12525
13246
  this.adPlayer.updateOriginalMutedState(this.video.muted, this.video.volume);
12526
13247
  this.adBreak.showAds = true;
12527
13248
  this.adBreak.inAdBreak = true;
12528
- this.timing.currentAdBreakStartWallClockMs = Date.now();
13249
+ this.timing.beginBreakTiming(Date.now());
12529
13250
  if (durationMs > 0) {
12530
13251
  this.timing.setAdBreakDurationBoundary(durationMs);
12531
13252
  }
@@ -12797,7 +13518,6 @@ var CRITICAL_PROPS = [
12797
13518
  "vmapUrl",
12798
13519
  "lowLatencyMode",
12799
13520
  "driftToleranceMs",
12800
- "vastMode",
12801
13521
  "ctvAdRequest",
12802
13522
  "adFloorMinCents",
12803
13523
  "adFloorMaxCents",
@@ -12806,7 +13526,7 @@ var CRITICAL_PROPS = [
12806
13526
  var CONTROLS_HIDE_DELAY = 3e3;
12807
13527
  var DEFAULT_PLAYER_ASPECT_RATIO = 16 / 9;
12808
13528
  var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
12809
- var src = props.src, autoplay = props.autoplay, muted = props.muted, lowLatencyMode = props.lowLatencyMode, allowNativeHls = props.allowNativeHls, isLiveStream = props.isLiveStream, driftToleranceMs = props.driftToleranceMs, immediateManifestAds = props.immediateManifestAds, debugAdTiming = props.debugAdTiming, showCustomControls = props.showCustomControls, hideLoadingIndicator = props.hideLoadingIndicator, onVolumeToggle = props.onVolumeToggle, onFullscreenToggle = props.onFullscreenToggle, onControlClick = props.onControlClick, onReady = props.onReady, wrapperClassName = props.wrapperClassName, wrapperStyle = props.wrapperStyle, className = props.className, style = props.style, controls = props.controls, playsInline = props.playsInline, preload = props.preload, poster = props.poster, children = props.children, licenseKey = props.licenseKey, vastMode = props.vastMode, vastTagUrl = props.vastTagUrl, isVmap = props.isVmap, vmapUrl = props.vmapUrl, minSegmentsBeforePlay = props.minSegmentsBeforePlay, ctvAdRequest = props.ctvAdRequest, programTitle = props.programTitle, channelName = props.channelName, minRemainingMsToStartAd = props.minRemainingMsToStartAd, minRemainingMsToRequestAd = props.minRemainingMsToRequestAd, maxNoFillsPerBreak = props.maxNoFillsPerBreak, maxAdBreakExtensionMs = props.maxAdBreakExtensionMs, adFloorLadderEnabled = props.adFloorLadderEnabled, adFloorLadder = props.adFloorLadder, adFloorMinCents = props.adFloorMinCents, adFloorMaxCents = props.adFloorMaxCents, adFloorStepCents = props.adFloorStepCents, enableEdgePodRequest = props.enableEdgePodRequest, edgePodUrl = props.edgePodUrl, restVideoAttrs = _object_without_properties(props, [
13529
+ var src = props.src, autoplay = props.autoplay, muted = props.muted, lowLatencyMode = props.lowLatencyMode, allowNativeHls = props.allowNativeHls, isLiveStream = props.isLiveStream, driftToleranceMs = props.driftToleranceMs, immediateManifestAds = props.immediateManifestAds, debugAdTiming = props.debugAdTiming, showCustomControls = props.showCustomControls, hideLoadingIndicator = props.hideLoadingIndicator, onVolumeToggle = props.onVolumeToggle, onFullscreenToggle = props.onFullscreenToggle, onControlClick = props.onControlClick, onReady = props.onReady, wrapperClassName = props.wrapperClassName, wrapperStyle = props.wrapperStyle, className = props.className, style = props.style, controls = props.controls, playsInline = props.playsInline, preload = props.preload, poster = props.poster, children = props.children, licenseKey = props.licenseKey, vastTagUrl = props.vastTagUrl, isVmap = props.isVmap, vmapUrl = props.vmapUrl, minSegmentsBeforePlay = props.minSegmentsBeforePlay, ctvAdRequest = props.ctvAdRequest, programTitle = props.programTitle, channelName = props.channelName, contentNetwork = props.contentNetwork, minRemainingMsToStartAd = props.minRemainingMsToStartAd, minRemainingMsToRequestAd = props.minRemainingMsToRequestAd, maxNoFillsPerBreak = props.maxNoFillsPerBreak, maxAdBreakExtensionMs = props.maxAdBreakExtensionMs, adFloorLadderEnabled = props.adFloorLadderEnabled, adFloorLadder = props.adFloorLadder, adFloorMinCents = props.adFloorMinCents, adFloorMaxCents = props.adFloorMaxCents, adFloorStepCents = props.adFloorStepCents, enableEdgePodRequest = props.enableEdgePodRequest, edgePodUrl = props.edgePodUrl, restVideoAttrs = _object_without_properties(props, [
12810
13530
  "src",
12811
13531
  "autoplay",
12812
13532
  "muted",
@@ -12832,7 +13552,6 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
12832
13552
  "poster",
12833
13553
  "children",
12834
13554
  "licenseKey",
12835
- "vastMode",
12836
13555
  "vastTagUrl",
12837
13556
  "isVmap",
12838
13557
  "vmapUrl",
@@ -12840,6 +13559,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
12840
13559
  "ctvAdRequest",
12841
13560
  "programTitle",
12842
13561
  "channelName",
13562
+ "contentNetwork",
12843
13563
  "minRemainingMsToStartAd",
12844
13564
  "minRemainingMsToRequestAd",
12845
13565
  "maxNoFillsPerBreak",
@@ -12998,7 +13718,6 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
12998
13718
  vmapUrl,
12999
13719
  lowLatencyMode,
13000
13720
  driftToleranceMs,
13001
- vastMode,
13002
13721
  adFloorMinCents,
13003
13722
  adFloorMaxCents,
13004
13723
  adFloorStepCents
@@ -13040,7 +13759,6 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
13040
13759
  if (onFullscreenToggle !== void 0) cfg.onFullscreenToggle = onFullscreenToggle;
13041
13760
  if (onControlClick !== void 0) cfg.onControlClick = onControlClick;
13042
13761
  if (licenseKey !== void 0) cfg.licenseKey = licenseKey;
13043
- if (vastMode !== void 0) cfg.vastMode = vastMode;
13044
13762
  if (vastTagUrl !== void 0) cfg.vastTagUrl = vastTagUrl;
13045
13763
  if (isVmap !== void 0) cfg.isVmap = isVmap;
13046
13764
  if (vmapUrl !== void 0) cfg.vmapUrl = vmapUrl;
@@ -13048,6 +13766,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
13048
13766
  if (ctvAdRequest !== void 0) cfg.ctvAdRequest = ctvAdRequest;
13049
13767
  if (programTitle !== void 0) cfg.programTitle = programTitle;
13050
13768
  if (channelName !== void 0) cfg.channelName = channelName;
13769
+ if (contentNetwork !== void 0) cfg.contentNetwork = contentNetwork;
13051
13770
  if (minRemainingMsToStartAd !== void 0) cfg.minRemainingMsToStartAd = minRemainingMsToStartAd;
13052
13771
  if (minRemainingMsToRequestAd !== void 0) cfg.minRemainingMsToRequestAd = minRemainingMsToRequestAd;
13053
13772
  if (maxNoFillsPerBreak !== void 0) cfg.maxNoFillsPerBreak = maxNoFillsPerBreak;
@@ -15380,8 +16099,10 @@ var StormcloudPlayer_default = StormcloudPlayer;
15380
16099
  // Annotate the CommonJS export names for ESM import in node:
15381
16100
  0 && (module.exports = {
15382
16101
  DEFAULT_FLOOR_LADDER_BOUNDS: DEFAULT_FLOOR_LADDER_BOUNDS,
16102
+ DEFAULT_REQUEST_SAFETY_MS: DEFAULT_REQUEST_SAFETY_MS,
15383
16103
  DEFAULT_TRACKING_INGEST_CONFIG: DEFAULT_TRACKING_INGEST_CONFIG,
15384
16104
  DEFAULT_WEB_FLOOR_LADDER_CONFIG: DEFAULT_WEB_FLOOR_LADDER_CONFIG,
16105
+ GAM_AD_OPPORTUNITY_DURATION_MS: GAM_AD_OPPORTUNITY_DURATION_MS,
15385
16106
  IS_BROWSER: IS_BROWSER,
15386
16107
  IS_GLOBAL: IS_GLOBAL,
15387
16108
  IS_IOS: IS_IOS,