@svta/cml-cmcd 2.5.0 → 2.6.1

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.
package/dist/index.js CHANGED
@@ -522,6 +522,26 @@ function isValid(value) {
522
522
  return value != null && value !== "" && value !== false;
523
523
  }
524
524
 
525
+ //#endregion
526
+ //#region src/toTokenString.ts
527
+ /**
528
+ * Resolve the text of a token value.
529
+ *
530
+ * A token may be a plain string, a registry `Symbol`, an `SfToken`, or an
531
+ * `SfItem` that wraps one of those.
532
+ *
533
+ * @param value - The value to resolve.
534
+ *
535
+ * @returns The token text, or `undefined` when the value is not a token.
536
+ *
537
+ * @internal
538
+ */
539
+ function toTokenString(value) {
540
+ if (value instanceof SfItem) return toTokenString(value.value);
541
+ if (typeof value === "string") return value;
542
+ if (typeof value === "symbol" || value instanceof SfToken) return symbolToStr(value);
543
+ }
544
+
525
545
  //#endregion
526
546
  //#region src/prepareCmcdData.ts
527
547
  const filterMap = {
@@ -534,7 +554,8 @@ const filterMap = {
534
554
  function unwrapValue(value, ot) {
535
555
  if (Array.isArray(value)) {
536
556
  let item;
537
- if (ot) item = value.find((item$1) => item$1.params?.ot === ot);
557
+ const otText = toTokenString(ot);
558
+ if (otText) item = value.find((item$1) => toTokenString(item$1.params?.ot) === otText);
538
559
  if (!item) item = value[0];
539
560
  return unwrapValue(item);
540
561
  }
@@ -582,15 +603,15 @@ function prepareCmcdData(obj, options = {}) {
582
603
  const version = options.version || obj["v"] || CMCD_V2;
583
604
  const reportingMode = options.reportingMode || CMCD_REQUEST_MODE;
584
605
  const data = version === 1 ? downConvertToV1(obj) : obj;
606
+ const eventType = toTokenString(data["e"]);
585
607
  const keyFilter = version === 1 ? isCmcdV1Key : filterMap[reportingMode];
586
608
  let keys = Object.keys(data).filter(keyFilter);
587
- if (data["e"] && data["e"] !== CMCD_EVENT_RESPONSE_RECEIVED) keys = keys.filter((key) => !isCmcdResponseReceivedKey(key));
609
+ if (data["e"] && eventType !== CMCD_EVENT_RESPONSE_RECEIVED) keys = keys.filter((key) => !isCmcdResponseReceivedKey(key));
588
610
  const filter = options.filter;
589
611
  if (typeof filter === "function") keys = keys.filter(filter);
590
612
  const isEventMode = reportingMode === CMCD_EVENT_MODE;
591
613
  if (isEventMode) {
592
- const eventType = data["e"];
593
- if (!keys.includes("e") && eventType != null) keys.push("e");
614
+ if (!keys.includes("e") && data["e"] != null) keys.push("e");
594
615
  if (!keys.includes("ts")) keys.push("ts");
595
616
  if (!keys.includes("cen") && data["cen"] != null && eventType === CMCD_EVENT_CUSTOM_EVENT) keys.push("cen");
596
617
  if (!keys.includes("ec") && data["ec"] != null && eventType === CMCD_EVENT_ERROR) keys.push("ec");
@@ -612,11 +633,14 @@ function prepareCmcdData(obj, options = {}) {
612
633
  if (typeof formatter === "function") value = formatter(value, formatterOptions);
613
634
  if (key === "v") if (version === 1) continue;
614
635
  else value = version;
615
- if (key === "pr" && value === 1 && !(isEventMode && data["e"] === CMCD_EVENT_PLAYBACK_RATE)) continue;
636
+ if (key === "pr" && value === 1 && !(isEventMode && eventType === CMCD_EVENT_PLAYBACK_RATE)) continue;
616
637
  if (isEventMode && key === "ts" && !Number.isFinite(value)) value = Date.now();
617
- const isBgFalseTransition = isEventMode && value === false && key === "bg" && data["e"] === CMCD_EVENT_BACKGROUNDED_MODE;
638
+ const isBgFalseTransition = isEventMode && value === false && key === "bg" && eventType === CMCD_EVENT_BACKGROUNDED_MODE;
618
639
  if (!isValid(value) && !isBgFalseTransition) continue;
619
- if (isTokenField(key) && typeof value === "string") value = new SfToken(value);
640
+ if (isTokenField(key)) {
641
+ if (typeof value === "string") value = new SfToken(value);
642
+ else if (value instanceof SfItem && typeof value.value === "string") value = new SfItem(new SfToken(value.value), value.params);
643
+ }
620
644
  results[key] = value;
621
645
  }
622
646
  return results;
@@ -970,6 +994,33 @@ const CMCD_KEYS = /* @__PURE__ */ [
970
994
  */
971
995
  const CMCD_MIME_TYPE = "application/cmcd";
972
996
 
997
+ //#endregion
998
+ //#region src/CMCD_REQUEST_PROVENANCE.ts
999
+ /**
1000
+ * The `customData` key under which `CmcdReporter.createRequestReport()`
1001
+ * stamps session provenance on every request it returns.
1002
+ *
1003
+ * The value is a frozen `CmcdRequestProvenance` record: `sid` names the
1004
+ * session that issued the request, `cid` is the content id in effect when
1005
+ * the request was issued, and `data` carries the request's per-call data
1006
+ * as an encoded CMCD string. `CmcdReporter.recordResponseReceived()` reads
1007
+ * the record to attribute a late response to its session and to rebuild
1008
+ * the request-time report keys.
1009
+ * Spread and `Object.assign` carry the record through ordinary request
1010
+ * clones, but `JSON.stringify` and structured clone drop symbol-keyed
1011
+ * properties: read the value before such a boundary and restore it
1012
+ * afterward. The record itself survives JSON, and attribution is by the
1013
+ * `sid` value rather than object identity, so a revived plain-object copy
1014
+ * attributes exactly. A record naming a `sid` the reporter does not retain
1015
+ * drops the response rather than relabeling it.
1016
+ *
1017
+ * Backed by the symbol registry so duplicated copies of this library in
1018
+ * one bundle interoperate. The registry key is stable across versions.
1019
+ *
1020
+ * @public
1021
+ */
1022
+ const CMCD_REQUEST_PROVENANCE = /* @__PURE__ */ Symbol.for("@svta/cml-cmcd/request-provenance");
1023
+
973
1024
  //#endregion
974
1025
  //#region src/CMCD_V1.ts
975
1026
  /**
@@ -1473,6 +1524,50 @@ const CmcdTransmissionMode = {
1473
1524
  HEADERS: CMCD_HEADERS
1474
1525
  };
1475
1526
 
1527
+ //#endregion
1528
+ //#region src/upConvertToV2.ts
1529
+ /**
1530
+ * Up-convert V1 CMCD data to V2 format.
1531
+ *
1532
+ * - Wraps plain scalar values in arrays for inner-list keys.
1533
+ * - Wraps `nor` string in an array.
1534
+ *
1535
+ * If the data is already V2 (has `v: 2`), it is returned unchanged.
1536
+ *
1537
+ * @internal
1538
+ */
1539
+ function upConvertToV2(obj) {
1540
+ if (obj["v"] === CMCD_V2) return obj;
1541
+ const result = {};
1542
+ for (const [key, value] of Object.entries(obj)) {
1543
+ if (value == null) {
1544
+ result[key] = value;
1545
+ continue;
1546
+ }
1547
+ if (CMCD_INNER_LIST_KEYS.has(key) && !Array.isArray(value)) result[key] = [value];
1548
+ else if (key === "nor" && typeof value === "string") result[key] = [value];
1549
+ else result[key] = value;
1550
+ }
1551
+ return result;
1552
+ }
1553
+
1554
+ //#endregion
1555
+ //#region src/decodeCmcd.ts
1556
+ function reduceValue(value, useSymbol) {
1557
+ if (Array.isArray(value)) return value.map((item) => reduceValue(item, useSymbol));
1558
+ if (typeof value === "symbol") return useSymbol === void 0 ? symbolToStr(value) : value;
1559
+ if (value instanceof SfItem) return value.params ? new SfItem(reduceValue(value.value, useSymbol), value.params) : reduceValue(value.value, useSymbol);
1560
+ return value;
1561
+ }
1562
+ function decodeCmcd(cmcd, options) {
1563
+ if (!cmcd) return {};
1564
+ const sfDict = decodeSfDict(cmcd, options);
1565
+ const result = {};
1566
+ for (const [key, item] of Object.entries(sfDict)) result[key] = reduceValue(item, options?.useSymbol);
1567
+ if (options?.convertToLatest) return upConvertToV2(result);
1568
+ return result;
1569
+ }
1570
+
1476
1571
  //#endregion
1477
1572
  //#region src/CmcdReporter.ts
1478
1573
  function createEncodingOptions(reportingMode, config, baseUrl) {
@@ -1579,8 +1674,10 @@ function copyItemValue(value) {
1579
1674
  *
1580
1675
  * Complete for the CMCD value space rather than best-effort: `CmcdValue` and
1581
1676
  * `CmcdCustomValue` admit only primitives, `SfItem<primitive>`, and arrays of
1582
- * those, and `SfItem.params` is a flat record. Only called where a transform
1583
- * is configured.
1677
+ * those, and `SfItem.params` is a flat record. Called where a transform is
1678
+ * configured, on the ended session's store at archival (detaching the frozen
1679
+ * snapshot from caller-held references), and on the request's stored
1680
+ * player-facing view.
1584
1681
  */
1585
1682
  function copyReportValues(data) {
1586
1683
  const record = data;
@@ -1594,17 +1691,51 @@ function copyReportValues(data) {
1594
1691
  }
1595
1692
  return data;
1596
1693
  }
1694
+ /**
1695
+ * Decodes the per-call data snapshot a provenance record carries into
1696
+ * fresh, encodable report data: tokens revive as `SfToken` and
1697
+ * params-bearing items as `SfItem` (`useSymbol: false`), so every value
1698
+ * keeps its wire type through re-encoding. Only called in
1699
+ * `recordResponseReceived()`. Returns an empty object when the record is
1700
+ * absent, carries no snapshot, or the snapshot does not parse (a value
1701
+ * this reporter did not write); the response then reports its derived keys
1702
+ * over the session's data alone.
1703
+ */
1704
+ function decodeSnapshot(provenance) {
1705
+ const encoded = provenance !== null && typeof provenance === "object" ? provenance.data : void 0;
1706
+ if (typeof encoded !== "string" || !encoded) return {};
1707
+ try {
1708
+ return decodeCmcd(encoded, { useSymbol: false });
1709
+ } catch {
1710
+ return {};
1711
+ }
1712
+ }
1713
+ /**
1714
+ * Mints a session's frozen base provenance record: the issuing `sid`, and
1715
+ * the `cid` in effect at mint time. `update()` re-mints on every `cid`
1716
+ * change, so requests issued before a mid-session content change keep the
1717
+ * `cid` they were issued under while later requests carry the new one.
1718
+ */
1719
+ function mintProvenance(sid, cid) {
1720
+ return Object.freeze(typeof cid === "string" && cid ? {
1721
+ sid,
1722
+ cid
1723
+ } : { sid });
1724
+ }
1597
1725
  function defaultRequester(request) {
1598
1726
  const { url,...init } = request;
1599
1727
  return fetch(url, init);
1600
1728
  }
1601
1729
  function createCmcdReporterConfig(config) {
1602
1730
  const { version = CMCD_V2, eventTargets = [], sid = uuid(), transmissionMode = CMCD_QUERY,...rest } = config;
1731
+ const retention = config.sessionRetention;
1732
+ const sessionRetention = typeof retention === "number" ? Math.floor(retention) : NaN;
1603
1733
  return {
1604
1734
  ...rest,
1605
1735
  version,
1606
1736
  transmissionMode,
1607
1737
  sid,
1738
+ sessionRetention: sessionRetention >= 0 ? sessionRetention : 2,
1608
1739
  eventTargets: eventTargets.reduce((acc, target) => {
1609
1740
  if (target?.url && target.events?.length) acc.push({
1610
1741
  version: target.version || CMCD_V2,
@@ -1645,27 +1776,41 @@ var CmcdReporter = class {
1645
1776
  */
1646
1777
  constructor(config, requester = defaultRequester) {
1647
1778
  this.timeOrigin = performance.timeOrigin || performance.timing?.fetchStart || Date.now() - performance.now();
1648
- this.data = {};
1649
- this.msd = NaN;
1650
- this.eventTargets = /* @__PURE__ */ new Map();
1651
- this.lastEmitted = {};
1652
- this.requestTarget = {
1653
- sn: 0,
1654
- msdSent: false
1655
- };
1779
+ this.sessions = /* @__PURE__ */ new Map();
1780
+ this.intervals = /* @__PURE__ */ new Map();
1781
+ this.started = false;
1656
1782
  this.config = createCmcdReporterConfig(config);
1657
- this.data = {
1783
+ this.session = this.createSession(this.config.sid, {
1658
1784
  cid: this.config.cid,
1659
- sid: this.config.sid,
1660
1785
  v: this.config.version
1661
- };
1786
+ });
1787
+ this.sessions.set(this.session.sid, this.session);
1662
1788
  this.requester = requester;
1663
- for (const target of this.config.eventTargets) this.eventTargets.set(target, {
1664
- intervalId: void 0,
1789
+ }
1790
+ /**
1791
+ * Creates the state for a new session: fresh counters, gates, queues and
1792
+ * dedup baseline for every configured target.
1793
+ */
1794
+ createSession(sid, data) {
1795
+ const eventTargets = /* @__PURE__ */ new Map();
1796
+ for (const target of this.config.eventTargets) eventTargets.set(target, {
1665
1797
  sn: 0,
1666
1798
  msdSent: false,
1667
- queue: []
1799
+ queue: [],
1800
+ disposed: false
1668
1801
  });
1802
+ return {
1803
+ sid,
1804
+ provenance: mintProvenance(sid, data.cid),
1805
+ data,
1806
+ msd: NaN,
1807
+ lastEmitted: {},
1808
+ eventTargets,
1809
+ requestTarget: {
1810
+ sn: 0,
1811
+ msdSent: false
1812
+ }
1813
+ };
1669
1814
  }
1670
1815
  /**
1671
1816
  * Starts the CMCD reporter. Called by the player when the reporter is enabled.
@@ -1675,17 +1820,15 @@ var CmcdReporter = class {
1675
1820
  * populated before calling start().
1676
1821
  */
1677
1822
  start() {
1823
+ this.started = true;
1678
1824
  let failure;
1679
- this.eventTargets.forEach((target, config) => {
1680
- this.disarmInterval(target);
1681
- if (config.interval === 0 || !config.events.includes(CMCD_EVENT_TIME_INTERVAL)) return;
1682
- const timeIntervalEvent = () => {
1683
- this.recordTargetEvent(target, config, CMCD_EVENT_TIME_INTERVAL);
1684
- this.processEventTargets();
1685
- };
1686
- target.intervalId = setInterval(timeIntervalEvent, config.interval * 1e3);
1825
+ const session = this.session;
1826
+ session.eventTargets.forEach((target, config) => {
1827
+ this.disarmInterval(config);
1828
+ if (target.disposed || !this.armInterval(config)) return;
1687
1829
  try {
1688
- timeIntervalEvent();
1830
+ this.recordTargetEvent(session, target, config, CMCD_EVENT_TIME_INTERVAL);
1831
+ this.processEventTargets();
1689
1832
  } catch (error) {
1690
1833
  failure ??= { error };
1691
1834
  }
@@ -1693,15 +1836,31 @@ var CmcdReporter = class {
1693
1836
  if (failure) throw failure.error;
1694
1837
  }
1695
1838
  /**
1839
+ * Arms the time-interval timer for an event target when its config calls
1840
+ * for one. Returns whether a timer was armed. The callback reports into
1841
+ * whichever session is current when it fires.
1842
+ */
1843
+ armInterval(config) {
1844
+ if (config.interval === 0 || !config.events.includes(CMCD_EVENT_TIME_INTERVAL)) return false;
1845
+ this.intervals.set(config, setInterval(() => {
1846
+ const session = this.session;
1847
+ const target = session.eventTargets.get(config);
1848
+ if (target) {
1849
+ this.recordTargetEvent(session, target, config, CMCD_EVENT_TIME_INTERVAL);
1850
+ this.processEventTargets();
1851
+ }
1852
+ }, config.interval * 1e3));
1853
+ return true;
1854
+ }
1855
+ /**
1696
1856
  * Stops the CMCD reporter. Called by the player when the reporter is disabled.
1697
1857
  *
1698
1858
  * @param flush - Whether to flush the event targets.
1699
1859
  */
1700
1860
  stop(flush = false) {
1861
+ this.started = false;
1701
1862
  if (flush) this.flush();
1702
- this.eventTargets.forEach((target) => {
1703
- this.disarmInterval(target);
1704
- });
1863
+ for (const config of this.config.eventTargets) this.disarmInterval(config);
1705
1864
  }
1706
1865
  /**
1707
1866
  * Forces the sending of all event reports, regardless of the batch size or interval.
@@ -1739,17 +1898,63 @@ var CmcdReporter = class {
1739
1898
  *
1740
1899
  * A `sid` change resets the dedup baseline.
1741
1900
  *
1901
+ * `sid` and `msd` are session-owned: the reporter tracks them itself and
1902
+ * stamps them onto every outgoing report, so this method is the only way
1903
+ * to change them. A per-call value on {@link CmcdReporter.recordEvent},
1904
+ * {@link CmcdReporter.createRequestReport}, or
1905
+ * {@link CmcdReporter.recordResponseReceived} has no effect; response
1906
+ * attribution is by the provenance record alone.
1907
+ * `msd` must be a finite number of milliseconds between `0` and
1908
+ * `999_999_999_999_999` (the RFC 8941 integer maximum); it is rounded to
1909
+ * the nearest integer, and invalid values are ignored.
1910
+ *
1742
1911
  * @param data - The data to update.
1743
1912
  */
1744
1913
  update(data) {
1745
- if (data.sid && data.sid !== this.data.sid) this.resetSession();
1746
- if (data.msd && !isNaN(data.msd)) this.msd = data.msd;
1747
- this.data = {
1748
- ...this.data,
1914
+ if (data.sid && data.sid !== this.session.sid) this.startSession(data.sid);
1915
+ const session = this.session;
1916
+ const { msd } = data;
1917
+ if (typeof msd === "number" && Number.isFinite(msd) && msd >= 0) {
1918
+ const rounded = Math.round(msd);
1919
+ if (rounded <= 999999999999999) session.msd = rounded;
1920
+ }
1921
+ session.data = {
1922
+ ...session.data,
1749
1923
  ...data,
1924
+ sid: void 0,
1750
1925
  msd: void 0
1751
1926
  };
1752
- for (const entry of STATE_FIELDS) if (entry.field in data && !entry.equal(this.data[entry.field], this.lastEmitted[entry.field])) this.recordEvent(entry.event);
1927
+ if (session.data.cid !== session.provenance.cid) session.provenance = mintProvenance(session.sid, session.data.cid);
1928
+ for (const entry of STATE_FIELDS) if (entry.field in data && !entry.equal(session.data[entry.field], session.lastEmitted[entry.field])) this.recordEvent(entry.event);
1929
+ }
1930
+ /**
1931
+ * Starts a new session: the current one is archived in place for stale
1932
+ * attribution, a fresh one takes over, ended sessions are drained, and
1933
+ * the oldest are evicted beyond the configured retention.
1934
+ *
1935
+ * The data store is carried over, and the archived snapshot is frozen:
1936
+ * the ended session's value graph is detached first, so nested values
1937
+ * the caller handed to `update()` can no longer mutate it, and the new
1938
+ * session starts from a shallow copy of the detached graph, so `cid`,
1939
+ * `br`, custom keys and the rest survive a `sid` change as they always
1940
+ * have. Sessions are keyed by `sid`, which CTA-5004-B expects to be
1941
+ * unique per playback session: reusing one replaces the retained
1942
+ * namesake, whose remaining state dies as if evicted and whose late
1943
+ * responses relabel onto the replacement.
1944
+ */
1945
+ startSession(sid) {
1946
+ this.session.data = copyReportValues({ ...this.session.data });
1947
+ this.session = this.createSession(sid, { ...this.session.data });
1948
+ this.sessions.delete(sid);
1949
+ this.sessions.set(sid, this.session);
1950
+ this.processEventTargets();
1951
+ for (const key of this.sessions.keys()) {
1952
+ if (this.sessions.size <= this.config.sessionRetention + 1) break;
1953
+ this.sessions.delete(key);
1954
+ }
1955
+ if (this.started) {
1956
+ for (const config of this.config.eventTargets) if (!this.intervals.has(config)) this.armInterval(config);
1957
+ }
1753
1958
  }
1754
1959
  /**
1755
1960
  * Records an event. Called by the player when an event occurs.
@@ -1784,15 +1989,21 @@ var CmcdReporter = class {
1784
1989
  * @param data - Additional data to record with the event. This data
1785
1990
  * only applies to this event report, except for the dedup
1786
1991
  * field of a state-change event, which is also persisted
1787
- * into the reporter's data store.
1992
+ * into the reporter's data store. Session-owned keys
1993
+ * (`sid`, `msd`) supplied here are ignored; the reporter
1994
+ * stamps its own values.
1788
1995
  */
1789
1996
  recordEvent(type, data = {}) {
1790
- this.emitEvent(type, data);
1997
+ this.emitEvent(this.session, type, data);
1791
1998
  }
1792
1999
  /**
1793
- * Records an event across every configured target, applying
2000
+ * Records an event across every configured target of a session, applying
1794
2001
  * state-change dedup once before per-target fan-out.
1795
2002
  *
2003
+ * @param session - The session the event belongs to. Everything the event
2004
+ * touches (data store, dedup baseline, counters, queues)
2005
+ * is that session's; only `recordResponseReceived()` ever
2006
+ * passes an archived one.
1796
2007
  * @param type - The type of event to record.
1797
2008
  * @param data - Additional data to record with the event.
1798
2009
  * @param request - The media request that triggered the event, when
@@ -1800,21 +2011,21 @@ var CmcdReporter = class {
1800
2011
  * populates this; it is threaded through to each
1801
2012
  * target's `transform`.
1802
2013
  */
1803
- emitEvent(type, data, request) {
2014
+ emitEvent(session, type, data, request) {
1804
2015
  const entry = STATE_FIELDS_BY_EVENT.get(type);
1805
2016
  if (entry) {
1806
2017
  const field = entry.field;
1807
2018
  const incoming = data[field];
1808
- if (incoming !== void 0) Object.assign(this.data, { [field]: incoming });
1809
- const current = this.data[field];
2019
+ if (incoming !== void 0) Object.assign(session.data, { [field]: incoming });
2020
+ const current = session.data[field];
1810
2021
  if (current === void 0) return;
1811
- if (entry.equal(current, this.lastEmitted[field])) return;
1812
- Object.assign(this.lastEmitted, { [field]: entry.snapshot(current) });
2022
+ if (entry.equal(current, session.lastEmitted[field])) return;
2023
+ Object.assign(session.lastEmitted, { [field]: entry.snapshot(current) });
1813
2024
  }
1814
2025
  let failure;
1815
- this.eventTargets.forEach((target, config) => {
2026
+ session.eventTargets.forEach((target, config) => {
1816
2027
  try {
1817
- this.recordTargetEvent(target, config, type, data, request);
2028
+ this.recordTargetEvent(session, target, config, type, data, request);
1818
2029
  } catch (error) {
1819
2030
  failure ??= { error };
1820
2031
  }
@@ -1834,17 +2045,18 @@ var CmcdReporter = class {
1834
2045
  * @param request - The media request that triggered the event, when
1835
2046
  * one exists. Passed to the target's `transform`.
1836
2047
  */
1837
- recordTargetEvent(target, config, type, data = {}, request) {
1838
- if (!config.events.includes(type)) return;
2048
+ recordTargetEvent(session, target, config, type, data = {}, request) {
2049
+ if (target.disposed || !config.events.includes(type)) return;
1839
2050
  const item = {
1840
- ...this.data,
2051
+ ...session.data,
1841
2052
  ...data,
2053
+ sid: session.sid,
1842
2054
  e: type,
1843
2055
  ts: data.ts ?? Date.now()
1844
2056
  };
1845
2057
  const { transform } = config;
1846
2058
  if (!transform) {
1847
- this.queueTargetEvent(target, item, type);
2059
+ this.queueTargetEvent(session, target, config, item, type);
1848
2060
  return;
1849
2061
  }
1850
2062
  copyReportValues(item);
@@ -1855,27 +2067,33 @@ var CmcdReporter = class {
1855
2067
  if (report == null) return;
1856
2068
  if (!isUsableRequiredValue(report.ts)) report.ts = ts;
1857
2069
  if (requiredKey && isUsableRequiredValue(requiredValue) && !isUsableRequiredValue(report[requiredKey])) Object.assign(report, { [requiredKey]: requiredValue });
1858
- this.queueTargetEvent(target, report, type);
2070
+ this.queueTargetEvent(session, target, config, report, type);
1859
2071
  }
1860
2072
  /**
1861
- * Stamps the reporter-owned fields on a finished event report and pushes it
1862
- * to the target's queue.
2073
+ * Stamps the reporter-owned fields on a finished event report, encodes it,
2074
+ * and pushes the wire line to the target's queue.
1863
2075
  *
1864
2076
  * Called after any transform has run, so a transform cannot bypass the
1865
- * target's `events` filter via `e` or break `sn` continuity.
2077
+ * target's `events` filter via `e`, break `sn` continuity, or substitute
2078
+ * the session identity carried by `sid` and `msd`. Encoding here means a
2079
+ * report that cannot serialize throws inside the recording call that
2080
+ * produced it, instead of rejecting the batch send and re-queueing
2081
+ * forever.
1866
2082
  *
1867
2083
  * @param target - The target to queue the report for.
2084
+ * @param config - The configuration for the target.
1868
2085
  * @param report - The finished report data.
1869
2086
  * @param type - The type of event being reported.
1870
2087
  */
1871
- queueTargetEvent(target, report, type) {
2088
+ queueTargetEvent(session, target, config, report, type) {
1872
2089
  report.e = type;
1873
2090
  report.sn = target.sn++;
1874
- if (!isNaN(this.msd) && !target.msdSent) {
1875
- report.msd = this.msd;
2091
+ report.sid = session.sid;
2092
+ if (!isNaN(session.msd) && !target.msdSent && config.enabledKeys?.includes("msd")) {
2093
+ report.msd = session.msd;
1876
2094
  target.msdSent = true;
1877
- }
1878
- target.queue.push(report);
2095
+ } else delete report.msd;
2096
+ target.queue.push(encodeCmcd(report, createEncodingOptions(CMCD_EVENT_MODE, config)));
1879
2097
  }
1880
2098
  /**
1881
2099
  * Records a response-received event. Called by the player when a media
@@ -1894,26 +2112,55 @@ var CmcdReporter = class {
1894
2112
  *
1895
2113
  * The request's `customData` is generic, so a player can pass a request
1896
2114
  * carrying its own taxonomy (e.g. `{ requestType: 'segment' }`) without a
1897
- * cast. The reporter only reads the optional `cmcd` key that
1898
- * {@link CmcdReporter.createRequestReport} writes there; every other key is
1899
- * left untouched and stays visible to an event target's `transform` via
1900
- * its `request` argument.
2115
+ * cast. The reporter reads only the provenance record that
2116
+ * {@link CmcdReporter.createRequestReport} writes there; every other key
2117
+ * is left untouched and stays visible to an event target's `transform`
2118
+ * via its `request` argument.
1901
2119
  *
1902
2120
  * A reporter given a concrete `C` requires the request to satisfy it, so a
1903
2121
  * request the configured transforms could not read is rejected here rather
1904
2122
  * than reaching them; see {@link CmcdReporterCustomData}.
1905
2123
  *
2124
+ * The event is attributed to the session that issued the request, and to
2125
+ * nothing else: the provenance record that
2126
+ * {@link CmcdReporter.createRequestReport} stored on the request's
2127
+ * `customData` (under {@link CMCD_REQUEST_PROVENANCE}) selects the
2128
+ * session by its `sid`, or the response is dropped rather than
2129
+ * relabeled. There is no other key: a record lost to a serialization
2130
+ * boundary (and not restored; see the bridge notes on
2131
+ * {@link CMCD_REQUEST_PROVENANCE}) and a session no longer retained
2132
+ * (see `CmcdReporterConfig.sessionRetention`) both drop, and a per-call
2133
+ * `data.sid` cannot substitute. The record is honored wherever its
2134
+ * `sid` resolves: a request decorated by another reporter configured
2135
+ * with the same session attributes here, as does a hand-built record.
2136
+ * A response that completes after a `sid` change reports under its own
2137
+ * retained session, with that session's data snapshot and sequence
2138
+ * numbers.
2139
+ *
2140
+ * Request-time report keys come from the record's encoded per-call
2141
+ * `data` snapshot, decoded fresh per response, and the record's `cid`
2142
+ * reports in place of the session's current one, so a response that
2143
+ * completes after a mid-session content change keeps the meaning it
2144
+ * had when its request was issued.
2145
+ *
1906
2146
  * @typeParam RD - The `customData` this request carries. Defaults to the
1907
2147
  * reporter's own `C`.
1908
2148
  *
1909
2149
  * @param response - The HTTP response received.
1910
2150
  * @param data - Additional CMCD data to include with the event.
1911
2151
  * Values provided here override any auto-derived values.
2152
+ * Session-owned keys (`sid`, `msd`) supplied here are
2153
+ * ignored; attribution is by the provenance record alone.
1912
2154
  */
1913
2155
  recordResponseReceived(response, data = {}) {
1914
2156
  const { request } = response;
1915
2157
  const url = data.url ?? request?.url;
1916
2158
  if (!url) return;
2159
+ const provenance = request.customData?.[CMCD_REQUEST_PROVENANCE];
2160
+ const session = this.resolveSession(provenance);
2161
+ if (!session) return;
2162
+ const cmcd = decodeSnapshot(provenance);
2163
+ const { cid } = provenance;
1917
2164
  const urlObj = new URL(url);
1918
2165
  urlObj.searchParams.delete(CMCD_PARAM);
1919
2166
  const derived = {
@@ -1928,14 +2175,28 @@ var CmcdReporter = class {
1928
2175
  }
1929
2176
  if (timing.duration != null) derived.ttlb = Math.round(timing.duration);
1930
2177
  }
1931
- const cmcd = request.customData?.cmcd ?? {};
1932
- this.emitEvent(CMCD_EVENT_RESPONSE_RECEIVED, {
2178
+ this.emitEvent(session, CMCD_EVENT_RESPONSE_RECEIVED, {
2179
+ ...typeof cid === "string" && cid ? { cid } : void 0,
1933
2180
  ...cmcd,
1934
2181
  ...derived,
1935
2182
  ...data
1936
2183
  }, request);
1937
2184
  }
1938
2185
  /**
2186
+ * Resolves the session a response belongs to: the provenance record's
2187
+ * `sid` names one of this reporter's retained sessions, or the response
2188
+ * is dropped. There is no other key — a record that was lost, or that
2189
+ * names an evicted or never-seen `sid`, resolves nothing, and
2190
+ * attributing it anywhere else would relabel it. The `sid` is read
2191
+ * structurally, so a JSON-revived copy of a record attributes exactly,
2192
+ * and a hand-built record naming a retained session is honored.
2193
+ */
2194
+ resolveSession(provenance) {
2195
+ if (provenance === null || typeof provenance !== "object") return;
2196
+ const { sid } = provenance;
2197
+ return typeof sid === "string" ? this.sessions.get(sid) : void 0;
2198
+ }
2199
+ /**
1939
2200
  * Applies the CMCD request report data to the request. Called by the player
1940
2201
  * before sending the request.
1941
2202
  *
@@ -1956,6 +2217,34 @@ var CmcdReporter = class {
1956
2217
  return !!this.config.enabledKeys?.length;
1957
2218
  }
1958
2219
  /**
2220
+ * The provenance record to stamp on a returned request: the session's
2221
+ * frozen base record, extended with the caller's per-call data encoded
2222
+ * as a CMCD string when there is any. Requests without per-call data
2223
+ * share the base record, so decoration stays a single property write.
2224
+ * The snapshot never contains reporter-stamped fields, and a value that
2225
+ * cannot encode contributes no snapshot rather than failing the
2226
+ * request; its response still attributes and reports derived keys over
2227
+ * session data, matching `decodeSnapshot()`'s tolerance on the read
2228
+ * side.
2229
+ */
2230
+ createRequestProvenance(data, baseUrl) {
2231
+ const base = this.session.provenance;
2232
+ if (!data) return base;
2233
+ try {
2234
+ const encoded = encodeCmcd(data, {
2235
+ version: this.config.version,
2236
+ reportingMode: CMCD_REQUEST_MODE,
2237
+ baseUrl
2238
+ });
2239
+ return encoded ? Object.freeze({
2240
+ ...base,
2241
+ data: encoded
2242
+ }) : base;
2243
+ } catch {
2244
+ return base;
2245
+ }
2246
+ }
2247
+ /**
1959
2248
  * Creates a new request with the CMCD request report data applied. Called by the player
1960
2249
  * before sending the request.
1961
2250
  *
@@ -1980,13 +2269,16 @@ var CmcdReporter = class {
1980
2269
  headers: { ...headers },
1981
2270
  customData: {
1982
2271
  ...customData,
1983
- cmcd: {}
2272
+ cmcd: {},
2273
+ [CMCD_REQUEST_PROVENANCE]: this.createRequestProvenance(data, request.url)
1984
2274
  }
1985
2275
  };
1986
2276
  if (!this.config.enabledKeys?.length || !report.url) return report;
2277
+ const session = this.session;
1987
2278
  const merged = {
1988
- ...this.data,
1989
- ...data
2279
+ ...session.data,
2280
+ ...data,
2281
+ sid: session.sid
1990
2282
  };
1991
2283
  const { transform } = this.config;
1992
2284
  let cmcdData = merged;
@@ -1995,19 +2287,20 @@ var CmcdReporter = class {
1995
2287
  cmcdData = transform(merged, request);
1996
2288
  if (cmcdData == null) return report;
1997
2289
  }
1998
- cmcdData.sn = this.requestTarget.sn++;
1999
- if (!isNaN(this.msd) && !this.requestTarget.msdSent) {
2000
- cmcdData.msd = this.msd;
2001
- this.requestTarget.msdSent = true;
2002
- }
2290
+ cmcdData.sn = session.requestTarget.sn++;
2291
+ cmcdData.sid = session.sid;
2292
+ const sendMsd = !isNaN(session.msd) && !session.requestTarget.msdSent;
2293
+ if (sendMsd) cmcdData.msd = session.msd;
2294
+ else delete cmcdData.msd;
2003
2295
  const url = new URL(report.url);
2004
2296
  const options = createEncodingOptions(CMCD_REQUEST_MODE, this.config, report.url);
2005
- const cmcd = report.customData.cmcd = prepareCmcdData(cmcdData, options);
2297
+ const cmcd = report.customData.cmcd = copyReportValues(prepareCmcdData(cmcdData, options));
2298
+ if (sendMsd && cmcd.msd !== void 0) session.requestTarget.msdSent = true;
2299
+ const encoded = encodePreparedCmcd(cmcd);
2006
2300
  switch (this.config.transmissionMode) {
2007
2301
  case CMCD_QUERY:
2008
- const param = encodePreparedCmcd(cmcd);
2009
- if (param) {
2010
- url.searchParams.set(CMCD_PARAM, param);
2302
+ if (encoded) {
2303
+ url.searchParams.set(CMCD_PARAM, encoded);
2011
2304
  report.url = url.toString();
2012
2305
  }
2013
2306
  break;
@@ -2024,16 +2317,19 @@ var CmcdReporter = class {
2024
2317
  */
2025
2318
  processEventTargets(flush = false) {
2026
2319
  let reprocess = false;
2027
- this.eventTargets.forEach((target, config) => {
2028
- const { queue } = target;
2029
- if (!queue.length) return;
2030
- if (queue.length < config.batchSize && !flush) return;
2031
- const deleteCount = flush ? queue.length : config.batchSize;
2032
- const events = queue.splice(0, deleteCount);
2033
- this.sendEventReport(config, events).catch(() => {
2034
- target.queue.unshift(...events);
2320
+ this.sessions.forEach((session) => {
2321
+ const drain = flush || session !== this.session;
2322
+ session.eventTargets.forEach((target, config) => {
2323
+ const { queue } = target;
2324
+ if (target.disposed || !queue.length) return;
2325
+ if (queue.length < config.batchSize && !drain) return;
2326
+ const deleteCount = drain ? queue.length : config.batchSize;
2327
+ const events = queue.splice(0, deleteCount);
2328
+ this.sendEventReport(session, config, events).catch(() => {
2329
+ target.queue.unshift(...events);
2330
+ });
2331
+ reprocess ||= queue.length > 0;
2035
2332
  });
2036
- reprocess ||= queue.length > 0;
2037
2333
  });
2038
2334
  if (reprocess) this.processEventTargets();
2039
2335
  }
@@ -2041,44 +2337,42 @@ var CmcdReporter = class {
2041
2337
  * Sends an event report. Called by the reporter when a batch is ready to be sent.
2042
2338
  *
2043
2339
  * @param config - The target config to send the event report to.
2044
- * @param data - The data to send in the event report.
2340
+ * @param data - The encoded report lines to send in the event report.
2045
2341
  */
2046
- async sendEventReport(config, data) {
2047
- const options = createEncodingOptions(CMCD_EVENT_MODE, config);
2342
+ async sendEventReport(session, config, data) {
2048
2343
  const { status } = await this.requester({
2049
2344
  url: config.url,
2050
2345
  method: "POST",
2051
2346
  headers: { "Content-Type": CMCD_MIME_TYPE },
2052
- body: data.map((item) => encodeCmcd(item, options)).join("\n") + "\n"
2347
+ body: data.join("\n") + "\n"
2053
2348
  });
2054
- if (status === 410) this.disposeEventTarget(config);
2349
+ if (status === 410) this.disposeEventTarget(session, config);
2055
2350
  else if (status === 429 || status > 499 && status < 600) throw new Error(`Event report failed with status ${status}`);
2056
2351
  }
2057
2352
  /**
2058
- * Cancels the time-interval timer for an event target and clears the stored id.
2059
- * Safe to call when no timer is armed (clearInterval(undefined) is a no-op).
2353
+ * Cancels the time-interval timer for an event target config and clears the
2354
+ * stored id. Safe to call when no timer is armed (clearInterval(undefined)
2355
+ * is a no-op).
2060
2356
  */
2061
- disarmInterval(target) {
2062
- clearInterval(target.intervalId);
2063
- target.intervalId = void 0;
2357
+ disarmInterval(config) {
2358
+ clearInterval(this.intervals.get(config));
2359
+ this.intervals.delete(config);
2064
2360
  }
2065
2361
  /**
2066
- * Permanently removes an event target: cancels its timer and removes it from the
2067
- * eventTargets map. Used when the collector signals the target is gone (HTTP 410).
2362
+ * Silences an event target URL for the remainder of its session: drops the
2363
+ * queues and blocks further enqueues for every config in the session that
2364
+ * reports to the URL, per CTA-5004-B's per-target-URL suppression scope,
2365
+ * and cancels their timers when the session is the live one. Used when the
2366
+ * collector signals the target is gone (HTTP 410). A session started after
2367
+ * the disposal is unaffected, since it gets fresh target state.
2068
2368
  */
2069
- disposeEventTarget(config) {
2070
- const target = this.eventTargets.get(config);
2071
- if (!target) return;
2072
- this.disarmInterval(target);
2073
- this.eventTargets.delete(config);
2074
- }
2075
- /**
2076
- * Resets the session related data. Called when the session ID changes.
2077
- */
2078
- resetSession() {
2079
- this.eventTargets.forEach((target) => target.sn = 0);
2080
- this.requestTarget.sn = 0;
2081
- this.lastEmitted = {};
2369
+ disposeEventTarget(session, config) {
2370
+ session.eventTargets.forEach((target, sibling) => {
2371
+ if (sibling.url !== config.url || target.disposed) return;
2372
+ target.disposed = true;
2373
+ target.queue.length = 0;
2374
+ if (session === this.session) this.disarmInterval(sibling);
2375
+ });
2082
2376
  }
2083
2377
  };
2084
2378
 
@@ -2141,51 +2435,6 @@ const CmcdValidationSeverity = {
2141
2435
  WARNING: CMCD_VALIDATION_SEVERITY_WARNING
2142
2436
  };
2143
2437
 
2144
- //#endregion
2145
- //#region src/upConvertToV2.ts
2146
- /**
2147
- * Up-convert V1 CMCD data to V2 format.
2148
- *
2149
- * - Wraps plain scalar values in arrays for inner-list keys.
2150
- * - Wraps `nor` string in an array.
2151
- *
2152
- * If the data is already V2 (has `v: 2`), it is returned unchanged.
2153
- *
2154
- * @internal
2155
- */
2156
- function upConvertToV2(obj) {
2157
- if (obj["v"] === CMCD_V2) return obj;
2158
- const result = {};
2159
- for (const [key, value] of Object.entries(obj)) {
2160
- if (value == null) {
2161
- result[key] = value;
2162
- continue;
2163
- }
2164
- if (CMCD_INNER_LIST_KEYS.has(key) && !Array.isArray(value)) result[key] = [value];
2165
- else if (key === "nor" && typeof value === "string") result[key] = [value];
2166
- else result[key] = value;
2167
- }
2168
- return result;
2169
- }
2170
-
2171
- //#endregion
2172
- //#region src/decodeCmcd.ts
2173
- function reduceValue(value) {
2174
- if (Array.isArray(value)) return value.map(reduceValue);
2175
- if (typeof value === "symbol") return symbolToStr(value);
2176
- if (value instanceof SfItem && !value.params) return reduceValue(value.value);
2177
- if (typeof value === "string") return value;
2178
- return value;
2179
- }
2180
- function decodeCmcd(cmcd, options) {
2181
- if (!cmcd) return {};
2182
- const sfDict = decodeSfDict(cmcd);
2183
- const result = {};
2184
- for (const [key, item] of Object.entries(sfDict)) result[key] = reduceValue(item.value);
2185
- if (options?.convertToLatest) return upConvertToV2(result);
2186
- return result;
2187
- }
2188
-
2189
2438
  //#endregion
2190
2439
  //#region src/ensureHeaders.ts
2191
2440
  /**
@@ -2386,7 +2635,8 @@ function validateCmcdStructure(data, options) {
2386
2635
  });
2387
2636
  }
2388
2637
  if ("e" in data) {
2389
- if (data["e"] === CMCD_EVENT_CUSTOM_EVENT) {
2638
+ const eventType = toTokenString(data["e"]);
2639
+ if (eventType === CMCD_EVENT_CUSTOM_EVENT) {
2390
2640
  if (!("cen" in data)) issues.push({
2391
2641
  key: "cen",
2392
2642
  message: "Custom event (e=\"ce\") requires the \"cen\" key to be present.",
@@ -2397,7 +2647,7 @@ function validateCmcdStructure(data, options) {
2397
2647
  message: "The \"cen\" key must only be present when e=\"ce\".",
2398
2648
  severity: CMCD_VALIDATION_SEVERITY_ERROR
2399
2649
  });
2400
- if (data["e"] === CMCD_EVENT_RESPONSE_RECEIVED) {
2650
+ if (eventType === CMCD_EVENT_RESPONSE_RECEIVED) {
2401
2651
  if (!("url" in data)) issues.push({
2402
2652
  key: "url",
2403
2653
  message: "Response received event (e=\"rr\") requires the \"url\" key to be present.",
@@ -2408,12 +2658,12 @@ function validateCmcdStructure(data, options) {
2408
2658
  message: `Response key "${key}" must only be present when e="rr".`,
2409
2659
  severity: CMCD_VALIDATION_SEVERITY_ERROR
2410
2660
  });
2411
- for (const [eventType, requiredField] of CMCD_STATE_EVENT_FIELDS) if (data["e"] === eventType && !(requiredField in data)) issues.push({
2661
+ for (const [stateEventType, requiredField] of CMCD_STATE_EVENT_FIELDS) if (eventType === stateEventType && !(requiredField in data)) issues.push({
2412
2662
  key: requiredField,
2413
- message: `State-change event (e="${eventType}") requires the "${requiredField}" key to be present.`,
2663
+ message: `State-change event (e="${stateEventType}") requires the "${requiredField}" key to be present.`,
2414
2664
  severity: CMCD_VALIDATION_SEVERITY_ERROR
2415
2665
  });
2416
- if (data["e"] === CMCD_EVENT_ERROR && !("ec" in data)) issues.push({
2666
+ if (eventType === CMCD_EVENT_ERROR && !("ec" in data)) issues.push({
2417
2667
  key: "ec",
2418
2668
  message: "Error event (e=\"e\") requires the \"ec\" key to be present.",
2419
2669
  severity: CMCD_VALIDATION_SEVERITY_ERROR
@@ -2799,9 +3049,10 @@ function validateCmcdValues(data, options) {
2799
3049
  break;
2800
3050
  case CMCD_KEY_TYPE_TOKEN: {
2801
3051
  const validValues = CMCD_TOKEN_VALUES[key];
2802
- if (validValues && !validValues.includes(value)) issues.push({
3052
+ const token = toTokenString(value);
3053
+ if (validValues && (token === void 0 || !validValues.includes(token))) issues.push({
2803
3054
  key,
2804
- message: `Key "${key}" has invalid token value "${String(value)}". Expected one of: ${validValues.join(", ")}.`,
3055
+ message: `Key "${key}" has invalid token value "${token ?? String(value)}". Expected one of: ${validValues.join(", ")}.`,
2805
3056
  severity: CMCD_VALIDATION_SEVERITY_ERROR
2806
3057
  });
2807
3058
  break;
@@ -3106,5 +3357,5 @@ function extractHeaderRecord(headers) {
3106
3357
  }
3107
3358
 
3108
3359
  //#endregion
3109
- export { CMCD_DEFAULT_TIME_INTERVAL, CMCD_EVENT_AD_BREAK_END, CMCD_EVENT_AD_BREAK_START, CMCD_EVENT_AD_END, CMCD_EVENT_AD_START, CMCD_EVENT_BACKGROUNDED_MODE, CMCD_EVENT_BITRATE_CHANGE, CMCD_EVENT_CONTENT_ID, CMCD_EVENT_CUSTOM_EVENT, CMCD_EVENT_ERROR, CMCD_EVENT_KEYS, CMCD_EVENT_MODE, CMCD_EVENT_MUTE, CMCD_EVENT_PLAYBACK_RATE, CMCD_EVENT_PLAYER_COLLAPSE, CMCD_EVENT_PLAYER_EXPAND, CMCD_EVENT_PLAY_STATE, CMCD_EVENT_RESPONSE_RECEIVED, CMCD_EVENT_SKIP, CMCD_EVENT_TIME_INTERVAL, CMCD_EVENT_UNMUTE, CMCD_FORMATTER_MAP, CMCD_HEADERS, CMCD_HEADER_FIELDS, CMCD_HEADER_MAP, CMCD_JSON, CMCD_KEYS, CMCD_MIME_TYPE, CMCD_OBJECT, CMCD_PARAM, CMCD_QUERY, CMCD_RECORDED_REPORT_MODE_EVENT, CMCD_RECORDED_REPORT_MODE_HEADER, CMCD_RECORDED_REPORT_MODE_QUERY, CMCD_RECORDED_REQUEST_TYPE_EVENT, CMCD_RECORDED_REQUEST_TYPE_MANIFEST, CMCD_RECORDED_REQUEST_TYPE_SEGMENT, CMCD_RECORDED_REQUEST_TYPE_UNKNOWN, CMCD_REQUEST, CMCD_REQUEST_KEYS, CMCD_REQUEST_MODE, CMCD_RESPONSE_KEYS, CMCD_SESSION, CMCD_STATUS, CMCD_V1, CMCD_V1_KEYS, CMCD_V2, CMCD_VALIDATION_SEVERITY_ERROR, CMCD_VALIDATION_SEVERITY_WARNING, CmcdEventType, CmcdHeaderField, CmcdObjectType, CmcdPlayerState, CmcdRecordedReportMode, CmcdRecordedRequestType, CmcdReportRecorder, CmcdReporter, CmcdReportingMode, CmcdStreamType, CmcdStreamingFormat, CmcdTransmissionMode, CmcdValidationSeverity, appendCmcdHeaders, appendCmcdQuery, createFetchTransport, createXhrTransport, decodeCmcd, encodeCmcd, fromCmcdHeaders, fromCmcdQuery, fromCmcdUrl, groupCmcdHeaders, isCmcdCustomKey, isCmcdEventKey, isCmcdRequestKey, isCmcdResponseReceivedKey, isCmcdV1Data, isCmcdV1Key, isCmcdV2Data, prepareCmcdData, toCmcdHeaders, toCmcdQuery, toCmcdUrl, toCmcdValue, validateCmcd, validateCmcdEventReport, validateCmcdEvents, validateCmcdHeaders, validateCmcdKeys, validateCmcdRequest, validateCmcdStructure, validateCmcdValues };
3360
+ export { CMCD_DEFAULT_TIME_INTERVAL, CMCD_EVENT_AD_BREAK_END, CMCD_EVENT_AD_BREAK_START, CMCD_EVENT_AD_END, CMCD_EVENT_AD_START, CMCD_EVENT_BACKGROUNDED_MODE, CMCD_EVENT_BITRATE_CHANGE, CMCD_EVENT_CONTENT_ID, CMCD_EVENT_CUSTOM_EVENT, CMCD_EVENT_ERROR, CMCD_EVENT_KEYS, CMCD_EVENT_MODE, CMCD_EVENT_MUTE, CMCD_EVENT_PLAYBACK_RATE, CMCD_EVENT_PLAYER_COLLAPSE, CMCD_EVENT_PLAYER_EXPAND, CMCD_EVENT_PLAY_STATE, CMCD_EVENT_RESPONSE_RECEIVED, CMCD_EVENT_SKIP, CMCD_EVENT_TIME_INTERVAL, CMCD_EVENT_UNMUTE, CMCD_FORMATTER_MAP, CMCD_HEADERS, CMCD_HEADER_FIELDS, CMCD_HEADER_MAP, CMCD_JSON, CMCD_KEYS, CMCD_MIME_TYPE, CMCD_OBJECT, CMCD_PARAM, CMCD_QUERY, CMCD_RECORDED_REPORT_MODE_EVENT, CMCD_RECORDED_REPORT_MODE_HEADER, CMCD_RECORDED_REPORT_MODE_QUERY, CMCD_RECORDED_REQUEST_TYPE_EVENT, CMCD_RECORDED_REQUEST_TYPE_MANIFEST, CMCD_RECORDED_REQUEST_TYPE_SEGMENT, CMCD_RECORDED_REQUEST_TYPE_UNKNOWN, CMCD_REQUEST, CMCD_REQUEST_KEYS, CMCD_REQUEST_MODE, CMCD_REQUEST_PROVENANCE, CMCD_RESPONSE_KEYS, CMCD_SESSION, CMCD_STATUS, CMCD_V1, CMCD_V1_KEYS, CMCD_V2, CMCD_VALIDATION_SEVERITY_ERROR, CMCD_VALIDATION_SEVERITY_WARNING, CmcdEventType, CmcdHeaderField, CmcdObjectType, CmcdPlayerState, CmcdRecordedReportMode, CmcdRecordedRequestType, CmcdReportRecorder, CmcdReporter, CmcdReportingMode, CmcdStreamType, CmcdStreamingFormat, CmcdTransmissionMode, CmcdValidationSeverity, appendCmcdHeaders, appendCmcdQuery, createFetchTransport, createXhrTransport, decodeCmcd, encodeCmcd, fromCmcdHeaders, fromCmcdQuery, fromCmcdUrl, groupCmcdHeaders, isCmcdCustomKey, isCmcdEventKey, isCmcdRequestKey, isCmcdResponseReceivedKey, isCmcdV1Data, isCmcdV1Key, isCmcdV2Data, prepareCmcdData, toCmcdHeaders, toCmcdQuery, toCmcdUrl, toCmcdValue, validateCmcd, validateCmcdEventReport, validateCmcdEvents, validateCmcdHeaders, validateCmcdKeys, validateCmcdRequest, validateCmcdStructure, validateCmcdValues };
3110
3361
  //# sourceMappingURL=index.js.map