stormcloud-video-player 0.8.72 → 0.8.74

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 +1 -0
  4. package/lib/StormcloudPlayer.cjs +992 -276
  5. package/lib/StormcloudPlayer.cjs.map +1 -1
  6. package/lib/StormcloudPlayer.d.cts +1 -0
  7. package/lib/index.cjs +1005 -281
  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 +998 -282
  12. package/lib/index.js.map +1 -1
  13. package/lib/player/AdBreakOrchestrator.cjs +772 -70
  14. package/lib/player/AdBreakOrchestrator.cjs.map +1 -1
  15. package/lib/player/AdBreakOrchestrator.d.cts +7 -9
  16. package/lib/player/AdConfigManager.cjs +314 -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 +992 -276
  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 +992 -276
  36. package/lib/players/HlsPlayer.cjs.map +1 -1
  37. package/lib/players/HlsPlayer.d.cts +1 -0
  38. package/lib/players/index.cjs +992 -276
  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 +997 -281
  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 +250 -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
@@ -1,4 +1,15 @@
1
1
  "use strict";
2
+ function _array_like_to_array(arr, len) {
3
+ if (len == null || len > arr.length) len = arr.length;
4
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
5
+ return arr2;
6
+ }
7
+ function _array_with_holes(arr) {
8
+ if (Array.isArray(arr)) return arr;
9
+ }
10
+ function _array_without_holes(arr) {
11
+ if (Array.isArray(arr)) return _array_like_to_array(arr);
12
+ }
2
13
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
3
14
  try {
4
15
  var info = gen[key](arg);
@@ -53,6 +64,41 @@ function _define_property(obj, key, value) {
53
64
  } else obj[key] = value;
54
65
  return obj;
55
66
  }
67
+ function _iterable_to_array(iter) {
68
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) {
69
+ return Array.from(iter);
70
+ }
71
+ }
72
+ function _iterable_to_array_limit(arr, i) {
73
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
74
+ if (_i == null) return;
75
+ var _arr = [];
76
+ var _n = true;
77
+ var _d = false;
78
+ var _s, _e;
79
+ try {
80
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
81
+ _arr.push(_s.value);
82
+ if (i && _arr.length === i) break;
83
+ }
84
+ } catch (err) {
85
+ _d = true;
86
+ _e = err;
87
+ } finally{
88
+ try {
89
+ if (!_n && _i["return"] != null) _i["return"]();
90
+ } finally{
91
+ if (_d) throw _e;
92
+ }
93
+ }
94
+ return _arr;
95
+ }
96
+ function _non_iterable_rest() {
97
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
98
+ }
99
+ function _non_iterable_spread() {
100
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
101
+ }
56
102
  function _object_spread(target) {
57
103
  for(var i = 1; i < arguments.length; i++){
58
104
  var source = arguments[i] != null ? arguments[i] : {};
@@ -127,6 +173,12 @@ function _object_without_properties_loose(source, excluded) {
127
173
  }
128
174
  return target;
129
175
  }
176
+ function _sliced_to_array(arr, i) {
177
+ return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
178
+ }
179
+ function _to_consumable_array(arr) {
180
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
181
+ }
130
182
  function _ts_generator(thisArg, body) {
131
183
  var f, y, t, _ = {
132
184
  label: 0,
@@ -230,6 +282,14 @@ function _type_of(obj) {
230
282
  "@swc/helpers - typeof";
231
283
  return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
232
284
  }
285
+ function _unsupported_iterable_to_array(o, minLen) {
286
+ if (!o) return;
287
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
288
+ var n = Object.prototype.toString.call(o).slice(8, -1);
289
+ if (n === "Object" && o.constructor) n = o.constructor.name;
290
+ if (n === "Map" || n === "Set") return Array.from(n);
291
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
292
+ }
233
293
  var __defProp = Object.defineProperty;
234
294
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
235
295
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -730,6 +790,92 @@ function normalizeBoolean(value) {
730
790
  return void 0;
731
791
  }
732
792
  // src/utils/vastMacros.ts
793
+ var INVALID_VAST_PARAM_KEY = /^\s|\s$/;
794
+ function removeBrokenAppNameOrphans(params, appName) {
795
+ var toDelete = [];
796
+ params.forEach(function(_value, key) {
797
+ if (!key || INVALID_VAST_PARAM_KEY.test(key)) {
798
+ toDelete.push(key);
799
+ }
800
+ });
801
+ if (appName && appName.includes("&")) {
802
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
803
+ try {
804
+ for(var _iterator = appName.split("&").slice(1)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
805
+ var suffix = _step.value;
806
+ var trimmed = suffix.replace(/^\s+/, "");
807
+ if (!trimmed) continue;
808
+ toDelete.push(suffix, " ".concat(trimmed), trimmed);
809
+ }
810
+ } catch (err) {
811
+ _didIteratorError = true;
812
+ _iteratorError = err;
813
+ } finally{
814
+ try {
815
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
816
+ _iterator.return();
817
+ }
818
+ } finally{
819
+ if (_didIteratorError) {
820
+ throw _iteratorError;
821
+ }
822
+ }
823
+ }
824
+ }
825
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
826
+ try {
827
+ for(var _iterator1 = new Set(toDelete)[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
828
+ var key = _step1.value;
829
+ if (key) params.delete(key);
830
+ }
831
+ } catch (err) {
832
+ _didIteratorError1 = true;
833
+ _iteratorError1 = err;
834
+ } finally{
835
+ try {
836
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
837
+ _iterator1.return();
838
+ }
839
+ } finally{
840
+ if (_didIteratorError1) {
841
+ throw _iteratorError1;
842
+ }
843
+ }
844
+ }
845
+ }
846
+ function normalizeVastTagUrl(raw) {
847
+ if (!raw) return raw;
848
+ try {
849
+ var url = new URL(raw);
850
+ var anValue = url.searchParams.get("an");
851
+ if (anValue !== null) {
852
+ var orphanFragments = [];
853
+ url.searchParams.forEach(function(_value, key) {
854
+ if (key && INVALID_VAST_PARAM_KEY.test(key)) {
855
+ orphanFragments.push(key.trim());
856
+ }
857
+ });
858
+ if (orphanFragments.length > 0) {
859
+ var reconstructed = [
860
+ anValue.replace(/\s+$/, "")
861
+ ].concat(_to_consumable_array(orphanFragments)).filter(Boolean).join(" & ");
862
+ url.searchParams.forEach(function(_value, key) {
863
+ if (key && INVALID_VAST_PARAM_KEY.test(key)) {
864
+ url.searchParams.delete(key);
865
+ }
866
+ });
867
+ url.searchParams.set("an", reconstructed);
868
+ return url.toString().replace(/([?&]an=)([^&]*)/, function(_match, prefix, val) {
869
+ return prefix + val.replace(/\+/g, "%20");
870
+ });
871
+ }
872
+ }
873
+ removeBrokenAppNameOrphans(url.searchParams);
874
+ return url.toString();
875
+ } catch (unused) {
876
+ return raw;
877
+ }
878
+ }
733
879
  var GAM_AD_HOSTS = /* @__PURE__ */ new Set([
734
880
  "pubads.g.doubleclick.net",
735
881
  "securepubads.g.doubleclick.net"
@@ -745,6 +891,147 @@ function ensureVideoAdType(rawUrl) {
745
891
  return rawUrl;
746
892
  }
747
893
  }
894
+ var SCVP_MACRO_DETECT = /\[SCVP-|%5BSCVP-|\(SCVP-|%28SCVP-/i;
895
+ var SCVP_MACRO_PATTERN = /\[SCVP-([A-Z0-9-]+)\]|\(SCVP-([A-Z0-9-]+)\)/gi;
896
+ var SCVP_WHOLE_VALUE_PATTERN = /^\s*(?:\[SCVP-([A-Z0-9-]+)\]|\(SCVP-([A-Z0-9-]+)\))\s*$/i;
897
+ var NESTED_QUERY_PARAM_KEYS = /* @__PURE__ */ new Set([
898
+ "cust_params"
899
+ ]);
900
+ var SCVP_POD_MACROS = /* @__PURE__ */ new Set([
901
+ "PMND",
902
+ "PMXD",
903
+ "PMAD"
904
+ ]);
905
+ function safeDecode(value) {
906
+ try {
907
+ return decodeURIComponent(value.replace(/\+/g, " "));
908
+ } catch (unused) {
909
+ return value;
910
+ }
911
+ }
912
+ function findScvpMacroNames(url) {
913
+ if (!url) return [];
914
+ var names = /* @__PURE__ */ new Set();
915
+ var text = url;
916
+ for(var pass = 0; pass < 3; pass++){
917
+ text.replace(SCVP_MACRO_PATTERN, function(_m, bracketName, parenName) {
918
+ names.add(String(bracketName || parenName).toUpperCase());
919
+ return "";
920
+ });
921
+ var decoded = safeDecode(text);
922
+ if (decoded === text) break;
923
+ text = decoded;
924
+ }
925
+ return Array.from(names);
926
+ }
927
+ var keepNone = function keepNone() {
928
+ return false;
929
+ };
930
+ function substituteScvpParams(params, values, unresolved, keep, nested) {
931
+ var out = [];
932
+ var replaceMacro = function replaceMacro(match, bracketName, parenName) {
933
+ var name = String(bracketName || parenName).toUpperCase();
934
+ var value = values.get(name);
935
+ if (value != null) return value;
936
+ if (keep(name)) return match;
937
+ unresolved.add(name);
938
+ return "";
939
+ };
940
+ params.forEach(function(value, key) {
941
+ var whole = value.match(SCVP_WHOLE_VALUE_PATTERN);
942
+ if (whole) {
943
+ var name = String(whole[1] || whole[2]).toUpperCase();
944
+ var resolved = values.get(name);
945
+ if (resolved != null) {
946
+ out.push([
947
+ key,
948
+ resolved
949
+ ]);
950
+ } else if (keep(name)) {
951
+ out.push([
952
+ key,
953
+ value
954
+ ]);
955
+ } else {
956
+ unresolved.add(name);
957
+ }
958
+ return;
959
+ }
960
+ if (!SCVP_MACRO_DETECT.test(value)) {
961
+ out.push([
962
+ key,
963
+ value
964
+ ]);
965
+ return;
966
+ }
967
+ if (!nested && NESTED_QUERY_PARAM_KEYS.has(key)) {
968
+ var inner = substituteScvpParams(new URLSearchParams(value), values, unresolved, keep, true);
969
+ if (inner.length > 0) {
970
+ out.push([
971
+ key,
972
+ inner.map(function(param) {
973
+ var _param = _sliced_to_array(param, 2), k = _param[0], v = _param[1];
974
+ return "".concat(encodeURIComponent(k), "=").concat(encodeURIComponent(v));
975
+ }).join("&")
976
+ ]);
977
+ }
978
+ return;
979
+ }
980
+ out.push([
981
+ key,
982
+ value.replace(SCVP_MACRO_PATTERN, replaceMacro)
983
+ ]);
984
+ });
985
+ return out;
986
+ }
987
+ function substituteScvpMacros(baseUrl, values) {
988
+ var keep = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : keepNone;
989
+ var unresolved = /* @__PURE__ */ new Set();
990
+ var url;
991
+ try {
992
+ url = new URL(normalizeVastTagUrl(baseUrl));
993
+ } catch (unused) {
994
+ var replaced = baseUrl.replace(SCVP_MACRO_PATTERN, function(match, bracketName, parenName) {
995
+ var name = String(bracketName || parenName).toUpperCase();
996
+ var value = values.get(name);
997
+ if (value != null) return encodeURIComponent(value);
998
+ if (keep(name)) return match;
999
+ unresolved.add(name);
1000
+ return "";
1001
+ });
1002
+ return {
1003
+ url: replaced,
1004
+ unresolved: Array.from(unresolved)
1005
+ };
1006
+ }
1007
+ var entries = substituteScvpParams(url.searchParams, values, unresolved, keep, false);
1008
+ var search = new URLSearchParams();
1009
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1010
+ try {
1011
+ for(var _iterator = entries[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1012
+ var _step_value = _sliced_to_array(_step.value, 2), key = _step_value[0], value = _step_value[1];
1013
+ search.append(key, value);
1014
+ }
1015
+ } catch (err) {
1016
+ _didIteratorError = true;
1017
+ _iteratorError = err;
1018
+ } finally{
1019
+ try {
1020
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1021
+ _iterator.return();
1022
+ }
1023
+ } finally{
1024
+ if (_didIteratorError) {
1025
+ throw _iteratorError;
1026
+ }
1027
+ }
1028
+ }
1029
+ url.search = search.toString();
1030
+ return {
1031
+ url: url.toString(),
1032
+ unresolved: Array.from(unresolved)
1033
+ };
1034
+ }
748
1035
  // src/player/FloorLadder.ts
749
1036
  var DEFAULT_WEB_FLOOR_LADDER_CONFIG = Object.freeze({
750
1037
  enabled: false,
@@ -985,7 +1272,14 @@ function ingestPlayerTracking(licenseKey, channel, body) {
985
1272
  // src/utils/tracking.ts
986
1273
  var cachedBrowserId = null;
987
1274
  function buildAnalyticsContext(config) {
1275
+ var _config_contentNetwork, _config_channelName, _config_programTitle;
988
1276
  var context = {};
1277
+ var contentNetwork = (_config_contentNetwork = config.contentNetwork) === null || _config_contentNetwork === void 0 ? void 0 : _config_contentNetwork.trim();
1278
+ var contentChannel = (_config_channelName = config.channelName) === null || _config_channelName === void 0 ? void 0 : _config_channelName.trim();
1279
+ var contentTitle = (_config_programTitle = config.programTitle) === null || _config_programTitle === void 0 ? void 0 : _config_programTitle.trim();
1280
+ if (contentNetwork) context.contentNetwork = contentNetwork;
1281
+ if (contentChannel) context.contentChannel = contentChannel;
1282
+ if (contentTitle) context.contentTitle = contentTitle;
989
1283
  if (config.debugAdTiming) {
990
1284
  context.debugAdTiming = true;
991
1285
  }
@@ -1375,12 +1669,19 @@ function sendAdImpressionTracking(_0, _1) {
1375
1669
  4,
1376
1670
  ingestPlayerTracking(licenseKey, "impressions", {
1377
1671
  events: [
1378
- {
1672
+ _object_spread({
1379
1673
  player_id: metricEvent.player_id,
1380
1674
  ad_played_count: 1,
1381
1675
  ad_url: adImpressionInfo.adUrl,
1382
- capture_at: adImpressionInfo.timestamp
1383
- }
1676
+ capture_at: adImpressionInfo.timestamp,
1677
+ source: "gam"
1678
+ }, context.contentNetwork ? {
1679
+ content_network: context.contentNetwork
1680
+ } : {}, context.contentChannel ? {
1681
+ content_channel: context.contentChannel
1682
+ } : {}, context.contentTitle ? {
1683
+ content_title: context.contentTitle
1684
+ } : {})
1384
1685
  ]
1385
1686
  })
1386
1687
  ];
@@ -1463,6 +1764,295 @@ function sendHeartbeat(_0) {
1463
1764
  function getAdAudioVolume(adPlayer) {
1464
1765
  return adPlayer.getOriginalMutedState() ? 0 : adPlayer.getOriginalVolume();
1465
1766
  }
1767
+ // src/player/OptimizedPodRequest.ts
1768
+ var GAM_AD_OPPORTUNITY_DURATION_MS = 3e4;
1769
+ var POD_PARAM_KEYS = [
1770
+ "pmnd",
1771
+ "pmxd",
1772
+ "pmad"
1773
+ ];
1774
+ var POSITIVE_INT = /^[1-9]\d*$/;
1775
+ var NON_NEGATIVE_INT = /^(0|[1-9]\d*)$/;
1776
+ function measureBreakCapacity(timing, nowMonoMs) {
1777
+ var _timing_breakEndMonoMs;
1778
+ var scheduled = timing.scheduledBreakDurationMs;
1779
+ if (scheduled == null || !(scheduled > 0) || timing.breakStartMonoMs == null) {
1780
+ return void 0;
1781
+ }
1782
+ var endMonoMs = (_timing_breakEndMonoMs = timing.breakEndMonoMs) !== null && _timing_breakEndMonoMs !== void 0 ? _timing_breakEndMonoMs : timing.breakStartMonoMs + scheduled;
1783
+ var untilEnd = Math.min(scheduled, endMonoMs - nowMonoMs);
1784
+ var unplayed = scheduled - Math.max(0, timing.playedDurationMs);
1785
+ return {
1786
+ scheduledBreakDurationMs: scheduled,
1787
+ elapsedBeforeGamRequestMs: Math.max(0, nowMonoMs - timing.breakStartMonoMs),
1788
+ remainingAtGamDispatchMs: Math.max(0, Math.min(untilEnd, unplayed))
1789
+ };
1790
+ }
1791
+ function resolvePodParams(input) {
1792
+ var capacity = input.capacity, config = input.config;
1793
+ var pmxd;
1794
+ var source;
1795
+ if (capacity) {
1796
+ pmxd = Math.floor(capacity.remainingAtGamDispatchMs - config.requestSafetyMs);
1797
+ source = "break_remaining";
1798
+ } else if (config.maxPodDurationMs != null) {
1799
+ pmxd = config.maxPodDurationMs;
1800
+ source = "configured_cap";
1801
+ } else if (input.tagMaxDurationMs != null) {
1802
+ pmxd = input.tagMaxDurationMs;
1803
+ source = "tag_cap";
1804
+ } else {
1805
+ return {
1806
+ kind: "omit"
1807
+ };
1808
+ }
1809
+ var minUsable = Math.max(1, Math.floor(input.minUsablePmxdMs));
1810
+ if (!Number.isFinite(pmxd) || pmxd < minUsable) {
1811
+ return {
1812
+ kind: "abort",
1813
+ reason: capacity ? "insufficient_break_capacity" : "invalid_pod_cap",
1814
+ pmxdCandidateMs: Number.isFinite(pmxd) ? pmxd : 0
1815
+ };
1816
+ }
1817
+ var pmnd = config.exactDuration ? pmxd : Math.min(config.minPodDurationMs, pmxd);
1818
+ return {
1819
+ kind: "send",
1820
+ params: {
1821
+ pmnd: pmnd,
1822
+ pmxd: pmxd,
1823
+ pmad: config.maxAdsPerBreak
1824
+ },
1825
+ source: source
1826
+ };
1827
+ }
1828
+ function podRequestAborted(reason, message, diagnostics) {
1829
+ var error = new Error("Optimized pod request not sent (".concat(reason, "): ").concat(message));
1830
+ error.podRequestAborted = true;
1831
+ error.reason = reason;
1832
+ error.diagnostics = diagnostics;
1833
+ return error;
1834
+ }
1835
+ function isPodRequestAbortedError(error) {
1836
+ return !!error && error.podRequestAborted === true;
1837
+ }
1838
+ function firstPositiveIntParam(params, key) {
1839
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1840
+ try {
1841
+ for(var _iterator = params.getAll(key)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1842
+ var value = _step.value;
1843
+ if (POSITIVE_INT.test(value.trim())) return Number(value.trim());
1844
+ }
1845
+ } catch (err) {
1846
+ _didIteratorError = true;
1847
+ _iteratorError = err;
1848
+ } finally{
1849
+ try {
1850
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1851
+ _iterator.return();
1852
+ }
1853
+ } finally{
1854
+ if (_didIteratorError) {
1855
+ throw _iteratorError;
1856
+ }
1857
+ }
1858
+ }
1859
+ return void 0;
1860
+ }
1861
+ function isOptimizedPodUrl(url) {
1862
+ if (findScvpMacroNames(url).some(function(name) {
1863
+ return SCVP_POD_MACROS.has(name);
1864
+ })) return true;
1865
+ try {
1866
+ var params = new URL(url).searchParams;
1867
+ return POD_PARAM_KEYS.some(function(key) {
1868
+ return params.has(key);
1869
+ });
1870
+ } catch (unused) {
1871
+ return false;
1872
+ }
1873
+ }
1874
+ function finalizeGamRequestUrl(rawUrl, ctx) {
1875
+ var nowEpochMs = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : Date.now();
1876
+ var optimizedPod = isOptimizedPodUrl(rawUrl);
1877
+ var capacity = ctx.capacity;
1878
+ var base = {
1879
+ breakId: ctx.breakId,
1880
+ optimizedPod: optimizedPod,
1881
+ scteBreakDurationMs: capacity === null || capacity === void 0 ? void 0 : capacity.scheduledBreakDurationMs,
1882
+ elapsedBeforeGamRequestMs: capacity === null || capacity === void 0 ? void 0 : capacity.elapsedBeforeGamRequestMs,
1883
+ remainingAtGamDispatchMs: capacity === null || capacity === void 0 ? void 0 : capacity.remainingAtGamDispatchMs,
1884
+ safetyReserveMs: ctx.config.requestSafetyMs
1885
+ };
1886
+ var decision = {
1887
+ kind: "omit"
1888
+ };
1889
+ if (optimizedPod) {
1890
+ var tagMaxDurationMs;
1891
+ try {
1892
+ tagMaxDurationMs = firstPositiveIntParam(new URL(rawUrl).searchParams, "pmxd");
1893
+ } catch (unused) {}
1894
+ decision = resolvePodParams({
1895
+ capacity: capacity,
1896
+ config: ctx.config,
1897
+ minUsablePmxdMs: ctx.minUsablePmxdMs,
1898
+ tagMaxDurationMs: tagMaxDurationMs
1899
+ });
1900
+ if (decision.kind === "abort") {
1901
+ throw podRequestAborted(decision.reason, "pmxd would be ".concat(decision.pmxdCandidateMs, "ms (minimum ").concat(ctx.minUsablePmxdMs, "ms)"), base);
1902
+ }
1903
+ }
1904
+ var pod = decision.kind === "send" ? decision.params : void 0;
1905
+ var values = /* @__PURE__ */ new Map();
1906
+ if (pod) {
1907
+ values.set("PMND", String(pod.pmnd));
1908
+ values.set("PMXD", String(pod.pmxd));
1909
+ if (pod.pmad != null) values.set("PMAD", String(pod.pmad));
1910
+ }
1911
+ var substituted = substituteScvpMacros(rawUrl, values);
1912
+ var finalUrl;
1913
+ try {
1914
+ var url = new URL(normalizeVastTagUrl(substituted.url));
1915
+ if (pod) {
1916
+ url.searchParams.set("pmnd", String(pod.pmnd));
1917
+ url.searchParams.set("pmxd", String(pod.pmxd));
1918
+ if (pod.pmad != null) url.searchParams.set("pmad", String(pod.pmad));
1919
+ else url.searchParams.delete("pmad");
1920
+ } else {
1921
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1922
+ try {
1923
+ for(var _iterator = POD_PARAM_KEYS[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1924
+ var key = _step.value;
1925
+ url.searchParams.delete(key);
1926
+ }
1927
+ } catch (err) {
1928
+ _didIteratorError = true;
1929
+ _iteratorError = err;
1930
+ } finally{
1931
+ try {
1932
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1933
+ _iterator.return();
1934
+ }
1935
+ } finally{
1936
+ if (_didIteratorError) {
1937
+ throw _iteratorError;
1938
+ }
1939
+ }
1940
+ }
1941
+ }
1942
+ finalUrl = url.toString();
1943
+ } catch (unused) {
1944
+ throw podRequestAborted("invalid_url", "GAM request URL could not be parsed", base);
1945
+ }
1946
+ var problems = validateGamRequestUrl(finalUrl, {
1947
+ optimizedPod: !!pod,
1948
+ remainingMs: decision.kind === "send" && decision.source === "break_remaining" ? capacity === null || capacity === void 0 ? void 0 : capacity.remainingAtGamDispatchMs : void 0
1949
+ });
1950
+ if (problems.length > 0) {
1951
+ throw podRequestAborted("invalid_url", problems.join("; "), base);
1952
+ }
1953
+ var givn = null;
1954
+ try {
1955
+ givn = new URL(finalUrl).searchParams.get("givn");
1956
+ } catch (unused) {}
1957
+ return {
1958
+ url: finalUrl,
1959
+ diagnostics: {
1960
+ breakId: ctx.breakId,
1961
+ optimizedPod: !!pod,
1962
+ pmxdSource: decision.kind === "send" ? decision.source : void 0,
1963
+ scteBreakDurationMs: capacity === null || capacity === void 0 ? void 0 : capacity.scheduledBreakDurationMs,
1964
+ elapsedBeforeGamRequestMs: capacity === null || capacity === void 0 ? void 0 : capacity.elapsedBeforeGamRequestMs,
1965
+ remainingAtGamDispatchMs: capacity === null || capacity === void 0 ? void 0 : capacity.remainingAtGamDispatchMs,
1966
+ safetyReserveMs: ctx.config.requestSafetyMs,
1967
+ pmndSent: pod === null || pod === void 0 ? void 0 : pod.pmnd,
1968
+ pmxdSent: pod === null || pod === void 0 ? void 0 : pod.pmxd,
1969
+ pmadSent: pod === null || pod === void 0 ? void 0 : pod.pmad,
1970
+ palNoncePresent: !!givn,
1971
+ gamRequestDispatchTimestamp: new Date(nowEpochMs).toISOString(),
1972
+ strippedMacros: substituted.unresolved.filter(function(name) {
1973
+ return !SCVP_POD_MACROS.has(name);
1974
+ })
1975
+ }
1976
+ };
1977
+ }
1978
+ function validateGamRequestUrl(url, expect) {
1979
+ var problems = [];
1980
+ var leftover = findScvpMacroNames(url);
1981
+ if (leftover.length > 0) problems.push("unresolved SCVP macros: ".concat(leftover.join(", ")));
1982
+ var params;
1983
+ try {
1984
+ params = new URL(url).searchParams;
1985
+ } catch (unused) {
1986
+ return problems.concat("URL could not be parsed");
1987
+ }
1988
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1989
+ try {
1990
+ for(var _iterator = POD_PARAM_KEYS[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1991
+ var key = _step.value;
1992
+ if (params.getAll(key).length > 1) problems.push("duplicate ".concat(key));
1993
+ }
1994
+ } catch (err) {
1995
+ _didIteratorError = true;
1996
+ _iteratorError = err;
1997
+ } finally{
1998
+ try {
1999
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2000
+ _iterator.return();
2001
+ }
2002
+ } finally{
2003
+ if (_didIteratorError) {
2004
+ throw _iteratorError;
2005
+ }
2006
+ }
2007
+ }
2008
+ if (!expect.optimizedPod) {
2009
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
2010
+ try {
2011
+ for(var _iterator1 = POD_PARAM_KEYS[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
2012
+ var key1 = _step1.value;
2013
+ if (params.has(key1)) problems.push("".concat(key1, " present on a non-pod request"));
2014
+ }
2015
+ } catch (err) {
2016
+ _didIteratorError1 = true;
2017
+ _iteratorError1 = err;
2018
+ } finally{
2019
+ try {
2020
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
2021
+ _iterator1.return();
2022
+ }
2023
+ } finally{
2024
+ if (_didIteratorError1) {
2025
+ throw _iteratorError1;
2026
+ }
2027
+ }
2028
+ }
2029
+ return problems;
2030
+ }
2031
+ var pmxd = params.get("pmxd");
2032
+ var pmnd = params.get("pmnd");
2033
+ var pmad = params.get("pmad");
2034
+ if (pmxd == null || !POSITIVE_INT.test(pmxd)) problems.push("pmxd must be a positive integer (got ".concat(pmxd, ")"));
2035
+ if (pmnd == null || !NON_NEGATIVE_INT.test(pmnd)) problems.push("pmnd must be a non-negative integer (got ".concat(pmnd, ")"));
2036
+ if (pmxd != null && pmnd != null && Number(pmnd) > Number(pmxd)) problems.push("pmnd exceeds pmxd");
2037
+ if (pmad != null && !POSITIVE_INT.test(pmad)) problems.push("pmad must be a positive integer or absent (got ".concat(pmad, ")"));
2038
+ if (expect.remainingMs != null && pmxd != null && Number(pmxd) > expect.remainingMs) {
2039
+ problems.push("pmxd ".concat(pmxd, " exceeds remaining break ").concat(expect.remainingMs, "ms"));
2040
+ }
2041
+ return problems;
2042
+ }
2043
+ function computePodResponseDiagnostics(pmxdSent, vastAdCount, totalVastCreativeDurationMs) {
2044
+ var estimatedUnusedPodMs = Math.max(0, pmxdSent - totalVastCreativeDurationMs);
2045
+ return {
2046
+ vastAdCount: vastAdCount,
2047
+ totalVastCreativeDurationMs: totalVastCreativeDurationMs,
2048
+ estimatedUnusedPodMs: estimatedUnusedPodMs,
2049
+ estimatedUnmatchedCount: Math.floor(estimatedUnusedPodMs / GAM_AD_OPPORTUNITY_DURATION_MS)
2050
+ };
2051
+ }
2052
+ // src/player/AdTimingService.ts
2053
+ function monotonicNow() {
2054
+ return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
2055
+ }
1466
2056
  // src/player/AdBreakOrchestrator.ts
1467
2057
  var REQUEST_FAILURE_STAGES = /* @__PURE__ */ new Set([
1468
2058
  "no_fill",
@@ -1524,9 +2114,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
1524
2114
  // ───────────────────────────────────────────────────────────────
1525
2115
  key: "nextAdRequestUrl",
1526
2116
  value: function nextAdRequestUrl(baseVastUrl) {
1527
- var remaining = Math.min(this.timing.getWallClockRemainingAdMs(), this.timing.getDurationBudgetRemainingMs());
1528
- var breakDurationMs = remaining > 0 ? remaining : void 0;
1529
- return this.host.generatePodVastUrl(baseVastUrl, breakDurationMs);
2117
+ return this.host.generatePodVastUrl(baseVastUrl);
1530
2118
  }
1531
2119
  },
1532
2120
  {
@@ -1789,7 +2377,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
1789
2377
  key: "handleAdStart",
1790
2378
  value: function handleAdStart(marker) {
1791
2379
  return _async_to_generator(function() {
1792
- var baseVastUrl, edgeConfigured, adBreakDurationMs, currentMuted, currentVolume, epoch, hasPrefetchedUrl, mode, edgeUrl, outcome, podPlayed;
2380
+ var baseVastUrl, edgeConfigured, adBreakDurationMs, currentMuted, currentVolume, epoch, mode, edgeUrl, outcome, podPlayed;
1793
2381
  return _ts_generator(this, function(_state) {
1794
2382
  switch(_state.label){
1795
2383
  case 0:
@@ -1841,8 +2429,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
1841
2429
  }
1842
2430
  this.noteOpportunity("scte35", this.cueManager.activeScte35BreakKey, "midroll");
1843
2431
  epoch = this.timing.adBreakEpoch;
1844
- hasPrefetchedUrl = !!(this.pendingAdBreak && this.pendingAdBreak.vastUrls.length > 0);
1845
- if (!(adBreakDurationMs == null && (!hasPrefetchedUrl || edgeConfigured))) return [
2432
+ if (!(adBreakDurationMs == null)) return [
1846
2433
  3,
1847
2434
  2
1848
2435
  ];
@@ -1898,7 +2485,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
1898
2485
  }
1899
2486
  return [
1900
2487
  4,
1901
- this.startOptimizedPod(baseVastUrl, adBreakDurationMs)
2488
+ this.startOptimizedPod(baseVastUrl)
1902
2489
  ];
1903
2490
  case 6:
1904
2491
  podPlayed = _state.sent();
@@ -1966,9 +2553,9 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
1966
2553
  value: // ───────────────────────────────────────────────────────────────
1967
2554
  // Optimized pod (single multi-ad request)
1968
2555
  // ───────────────────────────────────────────────────────────────
1969
- function startOptimizedPod(baseVastUrl, breakDurationMs) {
2556
+ function startOptimizedPod(baseVastUrl) {
1970
2557
  return _async_to_generator(function() {
1971
- var podUrl, prefetched, epoch, generation, adPlayer, requestToken, requestUrl, _ref, _adPlayer_getPodAdCount, podCount, error;
2558
+ var podUrl, prefetched, epoch, generation, adPlayer, requestToken, requestUrl, _ref, _this_currentVastUrl, _adPlayer_getPodAdCount, finalizeRequestUrl, podCount, error;
1972
2559
  return _ts_generator(this, function(_state) {
1973
2560
  switch(_state.label){
1974
2561
  case 0:
@@ -1977,7 +2564,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
1977
2564
  podUrl = this.pendingAdBreak.vastUrls[0];
1978
2565
  this.clearPendingAdBreak();
1979
2566
  } else {
1980
- podUrl = this.host.generatePodVastUrl(baseVastUrl, breakDurationMs);
2567
+ podUrl = this.host.generatePodVastUrl(baseVastUrl);
1981
2568
  }
1982
2569
  if (!podUrl) {
1983
2570
  return [
@@ -2001,9 +2588,9 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
2001
2588
  case 1:
2002
2589
  _state.trys.push([
2003
2590
  1,
2004
- 5,
2591
+ 9,
2005
2592
  ,
2006
- 6
2593
+ 10
2007
2594
  ]);
2008
2595
  return [
2009
2596
  4,
@@ -2015,15 +2602,46 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
2015
2602
  2,
2016
2603
  true
2017
2604
  ];
2605
+ return [
2606
+ 4,
2607
+ this.host.completeGamRequestSignals(requestUrl)
2608
+ ];
2609
+ case 3:
2610
+ requestUrl = _state.sent();
2611
+ if (this.isStale(epoch, generation)) return [
2612
+ 2,
2613
+ true
2614
+ ];
2018
2615
  this.timing.startAdRequestWatchdog(requestToken);
2616
+ finalizeRequestUrl = this.createGamDispatchFinalizer(requestToken);
2617
+ _state.label = 4;
2618
+ case 4:
2619
+ _state.trys.push([
2620
+ 4,
2621
+ ,
2622
+ 6,
2623
+ 7
2624
+ ]);
2019
2625
  return [
2020
2626
  4,
2021
2627
  this.callController(function() {
2022
- return adPlayer.requestAds(requestUrl);
2628
+ return adPlayer.requestAds(requestUrl, {
2629
+ finalizeRequestUrl: finalizeRequestUrl
2630
+ });
2023
2631
  })
2024
2632
  ];
2025
- case 3:
2633
+ case 5:
2026
2634
  _state.sent();
2635
+ return [
2636
+ 3,
2637
+ 7
2638
+ ];
2639
+ case 6:
2640
+ this.recordPodResponseDiagnostics(requestToken, adPlayer);
2641
+ return [
2642
+ 7
2643
+ ];
2644
+ case 7:
2027
2645
  this.timing.clearAdRequestWatchdog();
2028
2646
  if (this.isStale(epoch, generation)) {
2029
2647
  this.logOrchestratorFunnel("stale_request_result_ignored", {
@@ -2051,7 +2669,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
2051
2669
  }
2052
2670
  sendAdLoadedTracking(this.host.config.licenseKey, {
2053
2671
  source: "hls",
2054
- vastUrl: requestUrl,
2672
+ vastUrl: (_this_currentVastUrl = this.currentVastUrl) !== null && _this_currentVastUrl !== void 0 ? _this_currentVastUrl : requestUrl,
2055
2673
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
2056
2674
  }, this.analyticsContext).catch(function() {});
2057
2675
  this.timing.startAdFailsafeTimer(requestToken);
@@ -2061,7 +2679,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
2061
2679
  return adPlayer.play();
2062
2680
  })
2063
2681
  ];
2064
- case 4:
2682
+ case 8:
2065
2683
  _state.sent();
2066
2684
  if (this.isStale(epoch, generation)) return [
2067
2685
  2,
@@ -2075,7 +2693,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
2075
2693
  2,
2076
2694
  true
2077
2695
  ];
2078
- case 5:
2696
+ case 9:
2079
2697
  error = _state.sent();
2080
2698
  this.timing.clearAdRequestWatchdog();
2081
2699
  this.timing.clearAdFailsafeTimer();
@@ -2095,12 +2713,16 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
2095
2713
  if (this.debug) {
2096
2714
  console.warn("[POD] Optimized pod request/play failed:", error);
2097
2715
  }
2716
+ if (this.handlePodRequestNotSent(error)) return [
2717
+ 2,
2718
+ false
2719
+ ];
2098
2720
  this.recordRequestFailure(error, podUrl);
2099
2721
  return [
2100
2722
  2,
2101
2723
  false
2102
2724
  ];
2103
- case 6:
2725
+ case 10:
2104
2726
  return [
2105
2727
  2
2106
2728
  ];
@@ -2146,17 +2768,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
2146
2768
  }
2147
2769
  },
2148
2770
  {
2149
- /**
2150
- * Builds the next Edge request from the budget left right now, or marks Edge
2151
- * exhausted for this break. Synchronous on purpose: callers must reach the
2152
- * REQUESTING state in the same tick so a second completion event cannot race
2153
- * in a parallel request.
2154
- */ key: "prepareEdgePodRequest",
2771
+ key: "prepareEdgePodRequest",
2155
2772
  value: function prepareEdgePodRequest() {
2156
2773
  var baseUrl = this.host.getEdgePodBaseUrl();
2157
2774
  if (!baseUrl) return void 0;
2158
2775
  var remainingMs = this.timing.getRemainingAdMs();
2159
- var remainingAds = Math.min(EDGE_POD_MAX_ADS, this.adConfig.resolvePodParams().maxAds - this.timing.totalAdsInBreak);
2776
+ var remainingAds = Math.min(EDGE_POD_MAX_ADS, this.adConfig.resolveEdgeMaxAds() - this.timing.totalAdsInBreak);
2160
2777
  if (remainingAds < 1) {
2161
2778
  this.markEdgeExhausted("ad_capacity_reached", {
2162
2779
  adsInBreak: this.timing.totalAdsInBreak
@@ -2181,7 +2798,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
2181
2798
  key: "runEdgePod",
2182
2799
  value: function runEdgePod(requestUrl, trigger) {
2183
2800
  return _async_to_generator(function() {
2184
- var _params_get, _params_get1, epoch, generation, adPlayer, requestToken, params, _ref, _adPlayer_getPodAdCount, _adPlayer_getPodTotalDurationMs, remainingMs, remainingAds, podCount, error, errorMessage, classification, diag;
2801
+ var _params_get, _params_get1, epoch, generation, adPlayer, requestToken, params, _this_host_config_maxAdBreakExtensionMs, _ref, _adPlayer_getPodAdCount, _adPlayer_getPodTotalDurationMs, remainingMs, remainingAds, overrunAllowanceMs, podCount, error, errorMessage, classification, diag;
2185
2802
  return _ts_generator(this, function(_state) {
2186
2803
  switch(_state.label){
2187
2804
  case 0:
@@ -2235,8 +2852,9 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
2235
2852
  ];
2236
2853
  }
2237
2854
  remainingMs = this.timing.getRemainingAdMs();
2238
- remainingAds = Math.max(1, Math.min(EDGE_POD_MAX_ADS, this.adConfig.resolvePodParams().maxAds - this.timing.totalAdsInBreak));
2239
- podCount = adPlayer.limitPodToBudget ? adPlayer.limitPodToBudget(remainingMs, remainingAds) : (_ref = (_adPlayer_getPodAdCount = adPlayer.getPodAdCount) === null || _adPlayer_getPodAdCount === void 0 ? void 0 : _adPlayer_getPodAdCount.call(adPlayer)) !== null && _ref !== void 0 ? _ref : 0;
2855
+ remainingAds = Math.max(1, Math.min(EDGE_POD_MAX_ADS, this.adConfig.resolveEdgeMaxAds() - this.timing.totalAdsInBreak));
2856
+ overrunAllowanceMs = Math.max(0, (_this_host_config_maxAdBreakExtensionMs = this.host.config.maxAdBreakExtensionMs) !== null && _this_host_config_maxAdBreakExtensionMs !== void 0 ? _this_host_config_maxAdBreakExtensionMs : 0);
2857
+ 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;
2240
2858
  if (classifyEdgeVastResponse({
2241
2859
  podAdCount: podCount
2242
2860
  }) !== "fill") {
@@ -2246,7 +2864,8 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
2246
2864
  this.logOrchestratorFunnel("edge_fill", {
2247
2865
  podAdCount: podCount,
2248
2866
  podDurationMs: (_adPlayer_getPodTotalDurationMs = adPlayer.getPodTotalDurationMs) === null || _adPlayer_getPodTotalDurationMs === void 0 ? void 0 : _adPlayer_getPodTotalDurationMs.call(adPlayer),
2249
- remainingMs: remainingMs
2867
+ remainingMs: remainingMs,
2868
+ overrunAllowanceMs: overrunAllowanceMs
2250
2869
  });
2251
2870
  sendAdLoadedTracking(this.host.config.licenseKey, {
2252
2871
  source: "hls",
@@ -2580,7 +3199,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
2580
3199
  {
2581
3200
  key: "noteVastUrlGenerated",
2582
3201
  value: function noteVastUrlGenerated(url, source) {
2583
- var _ref, _ref1, _ref2, _ref3, _ref4;
3202
+ var _ref, _ref1;
2584
3203
  var params;
2585
3204
  try {
2586
3205
  params = new URL(url).searchParams;
@@ -2590,9 +3209,9 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
2590
3209
  requestId: void 0,
2591
3210
  source: source,
2592
3211
  pod: (_ref1 = params === null || params === void 0 ? void 0 : params.get("pod")) !== null && _ref1 !== void 0 ? _ref1 : void 0,
2593
- pmad: (_ref2 = params === null || params === void 0 ? void 0 : params.get("pmad")) !== null && _ref2 !== void 0 ? _ref2 : void 0,
2594
- pmnd: (_ref3 = params === null || params === void 0 ? void 0 : params.get("pmnd")) !== null && _ref3 !== void 0 ? _ref3 : void 0,
2595
- pmxd: (_ref4 = params === null || params === void 0 ? void 0 : params.get("pmxd")) !== null && _ref4 !== void 0 ? _ref4 : void 0,
3212
+ podParamsDeferredToDispatch: findScvpMacroNames(url).some(function(name) {
3213
+ return SCVP_POD_MACROS.has(name);
3214
+ }),
2596
3215
  adType: adType
2597
3216
  });
2598
3217
  if (adType === "audio" || adType === "audio_video") {
@@ -2633,10 +3252,13 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
2633
3252
  if (diag && !diag.failureReason) {
2634
3253
  diag.failureReason = "".concat(outcome, ": ").concat(message);
2635
3254
  }
3255
+ var failureKey = (diag === null || diag === void 0 ? void 0 : diag.dispatchedUrl) && findScvpMacroNames(vastTagUrl).some(function(name) {
3256
+ return SCVP_POD_MACROS.has(name);
3257
+ }) ? diag.dispatchedUrl : vastTagUrl;
2636
3258
  if (this.timing.isTemporaryAdError(error)) {
2637
- this.timing.temporaryFailureUrls.set(vastTagUrl, Date.now());
3259
+ this.timing.temporaryFailureUrls.set(failureKey, Date.now());
2638
3260
  } else if (outcome !== "discarded_budget") {
2639
- this.timing.failedVastUrls.add(vastTagUrl);
3261
+ this.timing.failedVastUrls.add(failureKey);
2640
3262
  }
2641
3263
  this.countFunnelStage("request_outcome:".concat(outcome));
2642
3264
  this.logOrchestratorFunnel("request_outcome", _object_spread({
@@ -2662,6 +3284,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
2662
3284
  switch(payload.stage){
2663
3285
  case "gam_http_request_sent":
2664
3286
  diag.gamRequestSent++;
3287
+ this.logPodDispatch(diag);
2665
3288
  break;
2666
3289
  case "edge_http_request_sent":
2667
3290
  diag.edgeRequestSent++;
@@ -2713,8 +3336,10 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
2713
3336
  if (gamReturnedAdWithoutImpression) {
2714
3337
  this.countFunnelStage("gam_ad_without_impression");
2715
3338
  }
2716
- var startedAt = diag.startedAt, fields = _object_without_properties(diag, [
2717
- "startedAt"
3339
+ var startedAt = diag.startedAt, _dispatchedUrl = diag.dispatchedUrl, _logged = diag.podDispatchLogged, fields = _object_without_properties(diag, [
3340
+ "startedAt",
3341
+ "dispatchedUrl",
3342
+ "podDispatchLogged"
2718
3343
  ]);
2719
3344
  console.log("[AdBreak][REQUEST] summary", _object_spread_props(_object_spread({}, fields), {
2720
3345
  durationMs: Date.now() - startedAt,
@@ -2726,24 +3351,71 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
2726
3351
  // ───────────────────────────────────────────────────────────────
2727
3352
  // Single ad playback
2728
3353
  // ───────────────────────────────────────────────────────────────
2729
- key: "withCurrentPodBudget",
2730
- value: function withCurrentPodBudget(rawVastTagUrl) {
2731
- var vastTagUrl = ensureVideoAdType(rawVastTagUrl);
2732
- var remaining = Math.min(this.timing.getWallClockRemainingAdMs(), this.timing.getDurationBudgetRemainingMs());
2733
- if (!(remaining > 0)) return vastTagUrl;
2734
- try {
2735
- var url = new URL(vastTagUrl);
2736
- if (!url.searchParams.has("pmxd")) return vastTagUrl;
2737
- var maxMs = Math.round(remaining);
2738
- url.searchParams.set("pmxd", String(maxMs));
2739
- var minMs = Number(url.searchParams.get("pmnd"));
2740
- if (Number.isFinite(minMs) && minMs > maxMs) {
2741
- url.searchParams.set("pmnd", String(maxMs));
3354
+ key: "createGamDispatchFinalizer",
3355
+ value: function createGamDispatchFinalizer(requestToken) {
3356
+ var _this = this;
3357
+ var breakId = this.timing.adBreakEpoch;
3358
+ var config = this.adConfig.resolveAdPodConfig();
3359
+ var minUsablePmxdMs = this.timing.getMinRemainingMsToStartAd();
3360
+ return function(url) {
3361
+ var capacity = measureBreakCapacity(_this.timing.getBreakTimingSnapshot(), monotonicNow());
3362
+ var diag = _this.requestDiagnostics.get(requestToken);
3363
+ try {
3364
+ var result = finalizeGamRequestUrl(url, {
3365
+ breakId: breakId,
3366
+ capacity: capacity,
3367
+ config: config,
3368
+ minUsablePmxdMs: minUsablePmxdMs
3369
+ });
3370
+ if (diag) {
3371
+ diag.pod = result.diagnostics;
3372
+ diag.dispatchedUrl = result.url;
3373
+ diag.podDispatchLogged = false;
3374
+ }
3375
+ _this.currentVastUrl = result.url;
3376
+ return result.url;
3377
+ } catch (error) {
3378
+ if (diag && isPodRequestAbortedError(error)) {
3379
+ diag.failureReason = "pod_request_not_sent:".concat(error.reason);
3380
+ }
3381
+ throw error;
2742
3382
  }
2743
- return url.toString();
2744
- } catch (unused) {
2745
- return vastTagUrl;
2746
- }
3383
+ };
3384
+ }
3385
+ },
3386
+ {
3387
+ key: "logPodDispatch",
3388
+ value: function logPodDispatch(diag) {
3389
+ if (!diag.pod || diag.podDispatchLogged) return;
3390
+ diag.podDispatchLogged = true;
3391
+ this.logOrchestratorFunnel(diag.pod.optimizedPod ? "optimized_pod_request_dispatched" : "gam_request_dispatched", _object_spread({}, diag.pod));
3392
+ }
3393
+ },
3394
+ {
3395
+ key: "recordPodResponseDiagnostics",
3396
+ value: function recordPodResponseDiagnostics(requestToken, adPlayer) {
3397
+ var _diag_vastAdCount, _ref;
3398
+ var _adPlayer_getPodTotalDurationMs;
3399
+ var diag = this.requestDiagnostics.get(requestToken);
3400
+ if (!(diag === null || diag === void 0 ? void 0 : diag.pod) || diag.pod.pmxdSent == null || diag.podResponse) return;
3401
+ if (diag.gamRequestSent === 0 && diag.vastHttpStatus == null) return;
3402
+ 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);
3403
+ this.logOrchestratorFunnel("optimized_pod_response", _object_spread({
3404
+ pmxdSent: diag.pod.pmxdSent
3405
+ }, diag.podResponse));
3406
+ }
3407
+ },
3408
+ {
3409
+ key: "handlePodRequestNotSent",
3410
+ value: function handlePodRequestNotSent(error) {
3411
+ if (!isPodRequestAbortedError(error) || error.reason === "invalid_url") return false;
3412
+ var aborted = error;
3413
+ this.countFunnelStage("request_outcome:pod_request_not_sent");
3414
+ this.logOrchestratorFunnel("pod_request_not_sent", _object_spread({
3415
+ reason: aborted.reason,
3416
+ errorMessage: aborted.message
3417
+ }, aborted.diagnostics));
3418
+ return true;
2747
3419
  }
2748
3420
  },
2749
3421
  {
@@ -2963,7 +3635,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
2963
3635
  value: function playSingleAd(vastTagUrl) {
2964
3636
  var trigger = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "vmap";
2965
3637
  return _async_to_generator(function() {
2966
- var epoch, generation, requestToken, ap, budgetedUrl, requestUrl, _ap_getLoadedAdDuration, adDurationS, remainingMs, error;
3638
+ var epoch, generation, requestToken, ap, requestUrl, _this_currentVastUrl, finalizeRequestUrl, _ap_getLoadedAdDuration, adDurationS, remainingMs, error;
2967
3639
  return _ts_generator(this, function(_state) {
2968
3640
  switch(_state.label){
2969
3641
  case 0:
@@ -3001,19 +3673,18 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
3001
3673
  requestToken = ++this.timing.adRequestTokenCounter;
3002
3674
  this.timing.activeAdRequestToken = requestToken;
3003
3675
  ap = this.host.getAdPlayer();
3004
- budgetedUrl = this.withCurrentPodBudget(vastTagUrl);
3005
3676
  this.currentPodSource = "gam";
3006
3677
  this.setSlotState("REQUESTING", trigger);
3007
3678
  this.beginFunnelRequest(ap, requestToken, trigger);
3008
- requestUrl = this.applyOpportunityFloor(budgetedUrl);
3679
+ requestUrl = this.applyOpportunityFloor(ensureVideoAdType(vastTagUrl));
3009
3680
  this.currentVastUrl = requestUrl;
3010
3681
  _state.label = 1;
3011
3682
  case 1:
3012
3683
  _state.trys.push([
3013
3684
  1,
3014
- 5,
3685
+ 9,
3015
3686
  ,
3016
- 6
3687
+ 10
3017
3688
  ]);
3018
3689
  return [
3019
3690
  4,
@@ -3024,15 +3695,45 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
3024
3695
  if (this.isStale(epoch, generation)) return [
3025
3696
  2
3026
3697
  ];
3698
+ return [
3699
+ 4,
3700
+ this.host.completeGamRequestSignals(requestUrl)
3701
+ ];
3702
+ case 3:
3703
+ requestUrl = _state.sent();
3704
+ if (this.isStale(epoch, generation)) return [
3705
+ 2
3706
+ ];
3027
3707
  this.timing.startAdRequestWatchdog(requestToken);
3708
+ finalizeRequestUrl = this.createGamDispatchFinalizer(requestToken);
3709
+ _state.label = 4;
3710
+ case 4:
3711
+ _state.trys.push([
3712
+ 4,
3713
+ ,
3714
+ 6,
3715
+ 7
3716
+ ]);
3028
3717
  return [
3029
3718
  4,
3030
3719
  this.callController(function() {
3031
- return ap.requestAds(requestUrl);
3720
+ return ap.requestAds(requestUrl, {
3721
+ finalizeRequestUrl: finalizeRequestUrl
3722
+ });
3032
3723
  })
3033
3724
  ];
3034
- case 3:
3725
+ case 5:
3035
3726
  _state.sent();
3727
+ return [
3728
+ 3,
3729
+ 7
3730
+ ];
3731
+ case 6:
3732
+ this.recordPodResponseDiagnostics(requestToken, ap);
3733
+ return [
3734
+ 7
3735
+ ];
3736
+ case 7:
3036
3737
  this.timing.clearAdRequestWatchdog();
3037
3738
  if (this.isStale(epoch, generation)) {
3038
3739
  this.logOrchestratorFunnel("stale_request_result_ignored", {
@@ -3044,7 +3745,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
3044
3745
  }
3045
3746
  sendAdLoadedTracking(this.host.config.licenseKey, {
3046
3747
  source: "hls",
3047
- vastUrl: requestUrl,
3748
+ vastUrl: (_this_currentVastUrl = this.currentVastUrl) !== null && _this_currentVastUrl !== void 0 ? _this_currentVastUrl : requestUrl,
3048
3749
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
3049
3750
  }, this.analyticsContext).catch(function() {});
3050
3751
  if (!this.timing.ensureLoadedAdFitsBudget(ap)) {
@@ -3065,7 +3766,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
3065
3766
  return ap.play();
3066
3767
  })
3067
3768
  ];
3068
- case 4:
3769
+ case 8:
3069
3770
  _state.sent();
3070
3771
  if (this.isStale(epoch, generation)) return [
3071
3772
  2
@@ -3077,9 +3778,9 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
3077
3778
  this.timing.temporaryFailureUrls.delete(vastTagUrl);
3078
3779
  return [
3079
3780
  3,
3080
- 6
3781
+ 10
3081
3782
  ];
3082
- case 5:
3783
+ case 9:
3083
3784
  error = _state.sent();
3084
3785
  this.timing.clearAdRequestWatchdog();
3085
3786
  this.timing.clearAdFailsafeTimer();
@@ -3096,12 +3797,13 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
3096
3797
  ];
3097
3798
  }
3098
3799
  if (this.debug) console.error("[AD-ERROR] Ad request failed:", error === null || error === void 0 ? void 0 : error.message);
3800
+ if (this.handlePodRequestNotSent(error)) throw error;
3099
3801
  this.recordRequestFailure(error, vastTagUrl);
3100
3802
  if ((error === null || error === void 0 ? void 0 : error.message) === "ad_duration_exceeds_budget") {
3101
3803
  this.recreateAdController("discarded_budget");
3102
3804
  }
3103
3805
  throw error;
3104
- case 6:
3806
+ case 10:
3105
3807
  return [
3106
3808
  2
3107
3809
  ];
@@ -3163,7 +3865,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
3163
3865
  playbackFailedAfterFill: count("request_outcome:playback_failed"),
3164
3866
  requestFailed: count("request_failed"),
3165
3867
  requestAbortedTimeout: count("request_aborted_timeout"),
3166
- credentialsRetries: count("vast_credentials_retry"),
3868
+ credentialsModeChanges: count("gam_credentials_mode_changed"),
3167
3869
  wrapperFailures: count("wrapper_fetch:failure"),
3168
3870
  noSupportedMedia: count("vast_no_supported_media"),
3169
3871
  vpaidOnly: count("vast_no_supported_media:vpaid"),