@svta/cml-cmcd 2.4.1 → 2.6.0

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
@@ -315,9 +315,12 @@ const CMCD_REQUEST_KEYS = [
315
315
 
316
316
  //#endregion
317
317
  //#region src/isCmcdCustomKey.ts
318
- const CUSTOM_KEY_REGEX = /^[a-zA-Z0-9.-]+$/;
318
+ const CUSTOM_KEY_REGEX = /^[a-z][a-z0-9.-]*$/;
319
319
  /**
320
- * Check if a key is a custom key.
320
+ * Check if a key is a valid custom key: a lowercase first letter, then
321
+ * characters from `a-z 0-9 . -`, with a hyphen that is neither the first
322
+ * nor the last character. These are the CTA-5004-B custom-key rules
323
+ * restricted to names that survive RFC 8941 key serialization.
321
324
  *
322
325
  * @param key - The key to check.
323
326
  *
@@ -569,6 +572,9 @@ function downConvertToV1(obj) {
569
572
  * @param options - Options for encoding.
570
573
  *
571
574
  * @public
575
+ *
576
+ * @example
577
+ * {@includeCode ../test/prepareCmcdData.test.ts#example}
572
578
  */
573
579
  function prepareCmcdData(obj, options = {}) {
574
580
  const results = {};
@@ -587,6 +593,8 @@ function prepareCmcdData(obj, options = {}) {
587
593
  if (!keys.includes("e") && eventType != null) keys.push("e");
588
594
  if (!keys.includes("ts")) keys.push("ts");
589
595
  if (!keys.includes("cen") && data["cen"] != null && eventType === CMCD_EVENT_CUSTOM_EVENT) keys.push("cen");
596
+ if (!keys.includes("ec") && data["ec"] != null && eventType === CMCD_EVENT_ERROR) keys.push("ec");
597
+ if (!keys.includes("url") && data["url"] != null && eventType === CMCD_EVENT_RESPONSE_RECEIVED) keys.push("url");
590
598
  const requiredField = eventType ? CMCD_STATE_EVENT_FIELDS.get(eventType) : void 0;
591
599
  if (requiredField && data[requiredField] != null && !keys.includes(requiredField)) keys.push(requiredField);
592
600
  }
@@ -962,6 +970,33 @@ const CMCD_KEYS = /* @__PURE__ */ [
962
970
  */
963
971
  const CMCD_MIME_TYPE = "application/cmcd";
964
972
 
973
+ //#endregion
974
+ //#region src/CMCD_REQUEST_PROVENANCE.ts
975
+ /**
976
+ * The `customData` key under which `CmcdReporter.createRequestReport()`
977
+ * stamps session provenance on every request it returns.
978
+ *
979
+ * The value is a frozen `CmcdRequestProvenance` record: `sid` names the
980
+ * session that issued the request, `cid` is the content id in effect when
981
+ * the request was issued, and `data` carries the request's per-call data
982
+ * as an encoded CMCD string. `CmcdReporter.recordResponseReceived()` reads
983
+ * the record to attribute a late response to its session and to rebuild
984
+ * the request-time report keys.
985
+ * Spread and `Object.assign` carry the record through ordinary request
986
+ * clones, but `JSON.stringify` and structured clone drop symbol-keyed
987
+ * properties: read the value before such a boundary and restore it
988
+ * afterward. The record itself survives JSON, and attribution is by the
989
+ * `sid` value rather than object identity, so a revived plain-object copy
990
+ * attributes exactly. A record naming a `sid` the reporter does not retain
991
+ * drops the response rather than relabeling it.
992
+ *
993
+ * Backed by the symbol registry so duplicated copies of this library in
994
+ * one bundle interoperate. The registry key is stable across versions.
995
+ *
996
+ * @public
997
+ */
998
+ const CMCD_REQUEST_PROVENANCE = /* @__PURE__ */ Symbol.for("@svta/cml-cmcd/request-provenance");
999
+
965
1000
  //#endregion
966
1001
  //#region src/CMCD_V1.ts
967
1002
  /**
@@ -1465,6 +1500,50 @@ const CmcdTransmissionMode = {
1465
1500
  HEADERS: CMCD_HEADERS
1466
1501
  };
1467
1502
 
1503
+ //#endregion
1504
+ //#region src/upConvertToV2.ts
1505
+ /**
1506
+ * Up-convert V1 CMCD data to V2 format.
1507
+ *
1508
+ * - Wraps plain scalar values in arrays for inner-list keys.
1509
+ * - Wraps `nor` string in an array.
1510
+ *
1511
+ * If the data is already V2 (has `v: 2`), it is returned unchanged.
1512
+ *
1513
+ * @internal
1514
+ */
1515
+ function upConvertToV2(obj) {
1516
+ if (obj["v"] === CMCD_V2) return obj;
1517
+ const result = {};
1518
+ for (const [key, value] of Object.entries(obj)) {
1519
+ if (value == null) {
1520
+ result[key] = value;
1521
+ continue;
1522
+ }
1523
+ if (CMCD_INNER_LIST_KEYS.has(key) && !Array.isArray(value)) result[key] = [value];
1524
+ else if (key === "nor" && typeof value === "string") result[key] = [value];
1525
+ else result[key] = value;
1526
+ }
1527
+ return result;
1528
+ }
1529
+
1530
+ //#endregion
1531
+ //#region src/decodeCmcd.ts
1532
+ function reduceValue(value, useSymbol) {
1533
+ if (Array.isArray(value)) return value.map((item) => reduceValue(item, useSymbol));
1534
+ if (typeof value === "symbol") return useSymbol === void 0 ? symbolToStr(value) : value;
1535
+ if (value instanceof SfItem) return value.params ? new SfItem(reduceValue(value.value, useSymbol), value.params) : reduceValue(value.value, useSymbol);
1536
+ return value;
1537
+ }
1538
+ function decodeCmcd(cmcd, options) {
1539
+ if (!cmcd) return {};
1540
+ const sfDict = decodeSfDict(cmcd, options);
1541
+ const result = {};
1542
+ for (const [key, item] of Object.entries(sfDict)) result[key] = reduceValue(item, options?.useSymbol);
1543
+ if (options?.convertToLatest) return upConvertToV2(result);
1544
+ return result;
1545
+ }
1546
+
1468
1547
  //#endregion
1469
1548
  //#region src/CmcdReporter.ts
1470
1549
  function createEncodingOptions(reportingMode, config, baseUrl) {
@@ -1473,7 +1552,8 @@ function createEncodingOptions(reportingMode, config, baseUrl) {
1473
1552
  version: config.version || CMCD_V2,
1474
1553
  reportingMode,
1475
1554
  filter: (key) => enabledKeySet.has(key),
1476
- baseUrl
1555
+ baseUrl,
1556
+ customHeaderMap: config.customHeaderMap
1477
1557
  };
1478
1558
  }
1479
1559
  /**
@@ -1523,17 +1603,115 @@ const STATE_FIELDS = /* @__PURE__ */ Array.from(CMCD_STATE_EVENT_FIELDS, ([event
1523
1603
  };
1524
1604
  });
1525
1605
  const STATE_FIELDS_BY_EVENT = /* @__PURE__ */ new Map(/* @__PURE__ */ STATE_FIELDS.map((e) => [e.event, e]));
1606
+ /**
1607
+ * Maps each event type to the key CTA-5004-B requires beyond `e` and `ts`.
1608
+ * Built from the state-change table plus the three event types whose
1609
+ * required key rides the caller's per-event data.
1610
+ */
1611
+ const CMCD_REQUIRED_EVENT_KEYS = /* @__PURE__ */ new Map([
1612
+ ...CMCD_STATE_EVENT_FIELDS,
1613
+ [CMCD_EVENT_CUSTOM_EVENT, "cen"],
1614
+ [CMCD_EVENT_ERROR, "ec"],
1615
+ [CMCD_EVENT_RESPONSE_RECEIVED, "url"]
1616
+ ]);
1617
+ /**
1618
+ * Whether a required key's value will survive report preparation.
1619
+ *
1620
+ * This is `isValid` minus its `false` exclusion, plus an empty-array check.
1621
+ * `false` must count as usable because `bg: false` is a legitimate value on a
1622
+ * backgrounded-mode event, which the encoder emits as `?0`; treating it as
1623
+ * unusable would let restoration silently revert a transform that cleared it.
1624
+ * Empty strings, empty lists and non-finite numbers are dropped downstream, so
1625
+ * a transform substituting one leaves the report short a required key.
1626
+ */
1627
+ function isUsableRequiredValue(value) {
1628
+ if (value == null || value === "") return false;
1629
+ if (typeof value === "number") return Number.isFinite(value);
1630
+ return !Array.isArray(value) || value.length > 0;
1631
+ }
1632
+ /**
1633
+ * Copies an `SfItem`-shaped value and its `params` record.
1634
+ *
1635
+ * The prototype is preserved because `prepareCmcdData`, the formatter map,
1636
+ * validation, and the structured-field encoder all branch on
1637
+ * `instanceof SfItem`. A plain spread (and `structuredClone`) would return a
1638
+ * prototype-less object and silently change what goes on the wire.
1639
+ */
1640
+ function copyItemValue(value) {
1641
+ if (value === null || typeof value !== "object") return value;
1642
+ const copy = Object.assign(Object.create(Object.getPrototypeOf(value)), value);
1643
+ if (copy.params !== null && typeof copy.params === "object") copy.params = { ...copy.params };
1644
+ return copy;
1645
+ }
1646
+ /**
1647
+ * Copies the nested values of a report in place so a transform cannot mutate
1648
+ * the reporter's persistent data, or another target's report for the same
1649
+ * event, by mutating an array or an `SfItem` it was handed.
1650
+ *
1651
+ * Complete for the CMCD value space rather than best-effort: `CmcdValue` and
1652
+ * `CmcdCustomValue` admit only primitives, `SfItem<primitive>`, and arrays of
1653
+ * those, and `SfItem.params` is a flat record. Called where a transform is
1654
+ * configured, on the ended session's store at archival (detaching the frozen
1655
+ * snapshot from caller-held references), and on the request's stored
1656
+ * player-facing view.
1657
+ */
1658
+ function copyReportValues(data) {
1659
+ const record = data;
1660
+ for (const key in record) {
1661
+ const value = record[key];
1662
+ if (Array.isArray(value)) {
1663
+ const copy = new Array(value.length);
1664
+ for (let i = 0; i < value.length; i++) copy[i] = copyItemValue(value[i]);
1665
+ record[key] = copy;
1666
+ } else if (value !== null && typeof value === "object") record[key] = copyItemValue(value);
1667
+ }
1668
+ return data;
1669
+ }
1670
+ /**
1671
+ * Decodes the per-call data snapshot a provenance record carries into
1672
+ * fresh, encodable report data: tokens revive as `SfToken` and
1673
+ * params-bearing items as `SfItem` (`useSymbol: false`), so every value
1674
+ * keeps its wire type through re-encoding. Only called in
1675
+ * `recordResponseReceived()`. Returns an empty object when the record is
1676
+ * absent, carries no snapshot, or the snapshot does not parse (a value
1677
+ * this reporter did not write); the response then reports its derived keys
1678
+ * over the session's data alone.
1679
+ */
1680
+ function decodeSnapshot(provenance) {
1681
+ const encoded = provenance !== null && typeof provenance === "object" ? provenance.data : void 0;
1682
+ if (typeof encoded !== "string" || !encoded) return {};
1683
+ try {
1684
+ return decodeCmcd(encoded, { useSymbol: false });
1685
+ } catch {
1686
+ return {};
1687
+ }
1688
+ }
1689
+ /**
1690
+ * Mints a session's frozen base provenance record: the issuing `sid`, and
1691
+ * the `cid` in effect at mint time. `update()` re-mints on every `cid`
1692
+ * change, so requests issued before a mid-session content change keep the
1693
+ * `cid` they were issued under while later requests carry the new one.
1694
+ */
1695
+ function mintProvenance(sid, cid) {
1696
+ return Object.freeze(typeof cid === "string" && cid ? {
1697
+ sid,
1698
+ cid
1699
+ } : { sid });
1700
+ }
1526
1701
  function defaultRequester(request) {
1527
1702
  const { url,...init } = request;
1528
1703
  return fetch(url, init);
1529
1704
  }
1530
1705
  function createCmcdReporterConfig(config) {
1531
1706
  const { version = CMCD_V2, eventTargets = [], sid = uuid(), transmissionMode = CMCD_QUERY,...rest } = config;
1707
+ const retention = config.sessionRetention;
1708
+ const sessionRetention = typeof retention === "number" ? Math.floor(retention) : NaN;
1532
1709
  return {
1533
1710
  ...rest,
1534
1711
  version,
1535
1712
  transmissionMode,
1536
1713
  sid,
1714
+ sessionRetention: sessionRetention >= 0 ? sessionRetention : 2,
1537
1715
  eventTargets: eventTargets.reduce((acc, target) => {
1538
1716
  if (target?.url && target.events?.length) acc.push({
1539
1717
  version: target.version || CMCD_V2,
@@ -1541,7 +1719,8 @@ function createCmcdReporterConfig(config) {
1541
1719
  url: target.url,
1542
1720
  events: target.events.slice(),
1543
1721
  interval: target.interval ?? CMCD_DEFAULT_TIME_INTERVAL,
1544
- batchSize: target.batchSize || 1
1722
+ batchSize: target.batchSize || 1,
1723
+ transform: target.transform
1545
1724
  });
1546
1725
  return acc;
1547
1726
  }, [])
@@ -1550,6 +1729,14 @@ function createCmcdReporterConfig(config) {
1550
1729
  /**
1551
1730
  * The CMCD reporter.
1552
1731
  *
1732
+ * `C` describes the player's own `customData`, which the reporter passes
1733
+ * through to each configured `transform`. It is inferred from the
1734
+ * configuration, so annotating a single `transform` types the request in every
1735
+ * other one; the default leaves `customData` values `unknown`.
1736
+ *
1737
+ * @typeParam C - The shape of the player's `customData`. Defaults to
1738
+ * `Record<string, unknown>`.
1739
+ *
1553
1740
  * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#reporting-modes-when-we-send-data | CTA-5004-B Reporting Modes}
1554
1741
  *
1555
1742
  * @public
@@ -1565,27 +1752,41 @@ var CmcdReporter = class {
1565
1752
  */
1566
1753
  constructor(config, requester = defaultRequester) {
1567
1754
  this.timeOrigin = performance.timeOrigin || performance.timing?.fetchStart || Date.now() - performance.now();
1568
- this.data = {};
1569
- this.msd = NaN;
1570
- this.eventTargets = /* @__PURE__ */ new Map();
1571
- this.lastEmitted = {};
1572
- this.requestTarget = {
1573
- sn: 0,
1574
- msdSent: false
1575
- };
1755
+ this.sessions = /* @__PURE__ */ new Map();
1756
+ this.intervals = /* @__PURE__ */ new Map();
1757
+ this.started = false;
1576
1758
  this.config = createCmcdReporterConfig(config);
1577
- this.data = {
1759
+ this.session = this.createSession(this.config.sid, {
1578
1760
  cid: this.config.cid,
1579
- sid: this.config.sid,
1580
1761
  v: this.config.version
1581
- };
1762
+ });
1763
+ this.sessions.set(this.session.sid, this.session);
1582
1764
  this.requester = requester;
1583
- for (const target of this.config.eventTargets) this.eventTargets.set(target, {
1584
- intervalId: void 0,
1765
+ }
1766
+ /**
1767
+ * Creates the state for a new session: fresh counters, gates, queues and
1768
+ * dedup baseline for every configured target.
1769
+ */
1770
+ createSession(sid, data) {
1771
+ const eventTargets = /* @__PURE__ */ new Map();
1772
+ for (const target of this.config.eventTargets) eventTargets.set(target, {
1585
1773
  sn: 0,
1586
1774
  msdSent: false,
1587
- queue: []
1775
+ queue: [],
1776
+ disposed: false
1588
1777
  });
1778
+ return {
1779
+ sid,
1780
+ provenance: mintProvenance(sid, data.cid),
1781
+ data,
1782
+ msd: NaN,
1783
+ lastEmitted: {},
1784
+ eventTargets,
1785
+ requestTarget: {
1786
+ sn: 0,
1787
+ msdSent: false
1788
+ }
1789
+ };
1589
1790
  }
1590
1791
  /**
1591
1792
  * Starts the CMCD reporter. Called by the player when the reporter is enabled.
@@ -1595,16 +1796,37 @@ var CmcdReporter = class {
1595
1796
  * populated before calling start().
1596
1797
  */
1597
1798
  start() {
1598
- this.eventTargets.forEach((target, config) => {
1599
- this.disarmInterval(target);
1600
- if (config.interval === 0 || !config.events.includes(CMCD_EVENT_TIME_INTERVAL)) return;
1601
- const timeIntervalEvent = () => {
1602
- this.recordTargetEvent(target, config, CMCD_EVENT_TIME_INTERVAL);
1799
+ this.started = true;
1800
+ let failure;
1801
+ const session = this.session;
1802
+ session.eventTargets.forEach((target, config) => {
1803
+ this.disarmInterval(config);
1804
+ if (target.disposed || !this.armInterval(config)) return;
1805
+ try {
1806
+ this.recordTargetEvent(session, target, config, CMCD_EVENT_TIME_INTERVAL);
1603
1807
  this.processEventTargets();
1604
- };
1605
- target.intervalId = setInterval(timeIntervalEvent, config.interval * 1e3);
1606
- timeIntervalEvent();
1808
+ } catch (error) {
1809
+ failure ??= { error };
1810
+ }
1607
1811
  });
1812
+ if (failure) throw failure.error;
1813
+ }
1814
+ /**
1815
+ * Arms the time-interval timer for an event target when its config calls
1816
+ * for one. Returns whether a timer was armed. The callback reports into
1817
+ * whichever session is current when it fires.
1818
+ */
1819
+ armInterval(config) {
1820
+ if (config.interval === 0 || !config.events.includes(CMCD_EVENT_TIME_INTERVAL)) return false;
1821
+ this.intervals.set(config, setInterval(() => {
1822
+ const session = this.session;
1823
+ const target = session.eventTargets.get(config);
1824
+ if (target) {
1825
+ this.recordTargetEvent(session, target, config, CMCD_EVENT_TIME_INTERVAL);
1826
+ this.processEventTargets();
1827
+ }
1828
+ }, config.interval * 1e3));
1829
+ return true;
1608
1830
  }
1609
1831
  /**
1610
1832
  * Stops the CMCD reporter. Called by the player when the reporter is disabled.
@@ -1612,10 +1834,9 @@ var CmcdReporter = class {
1612
1834
  * @param flush - Whether to flush the event targets.
1613
1835
  */
1614
1836
  stop(flush = false) {
1837
+ this.started = false;
1615
1838
  if (flush) this.flush();
1616
- this.eventTargets.forEach((target) => {
1617
- this.disarmInterval(target);
1618
- });
1839
+ for (const config of this.config.eventTargets) this.disarmInterval(config);
1619
1840
  }
1620
1841
  /**
1621
1842
  * Forces the sending of all event reports, regardless of the batch size or interval.
@@ -1653,17 +1874,63 @@ var CmcdReporter = class {
1653
1874
  *
1654
1875
  * A `sid` change resets the dedup baseline.
1655
1876
  *
1877
+ * `sid` and `msd` are session-owned: the reporter tracks them itself and
1878
+ * stamps them onto every outgoing report, so this method is the only way
1879
+ * to change them. A per-call value on {@link CmcdReporter.recordEvent},
1880
+ * {@link CmcdReporter.createRequestReport}, or
1881
+ * {@link CmcdReporter.recordResponseReceived} has no effect; response
1882
+ * attribution is by the provenance record alone.
1883
+ * `msd` must be a finite number of milliseconds between `0` and
1884
+ * `999_999_999_999_999` (the RFC 8941 integer maximum); it is rounded to
1885
+ * the nearest integer, and invalid values are ignored.
1886
+ *
1656
1887
  * @param data - The data to update.
1657
1888
  */
1658
1889
  update(data) {
1659
- if (data.sid && data.sid !== this.data.sid) this.resetSession();
1660
- if (data.msd && !isNaN(data.msd)) this.msd = data.msd;
1661
- this.data = {
1662
- ...this.data,
1890
+ if (data.sid && data.sid !== this.session.sid) this.startSession(data.sid);
1891
+ const session = this.session;
1892
+ const { msd } = data;
1893
+ if (typeof msd === "number" && Number.isFinite(msd) && msd >= 0) {
1894
+ const rounded = Math.round(msd);
1895
+ if (rounded <= 999999999999999) session.msd = rounded;
1896
+ }
1897
+ session.data = {
1898
+ ...session.data,
1663
1899
  ...data,
1900
+ sid: void 0,
1664
1901
  msd: void 0
1665
1902
  };
1666
- 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);
1903
+ if (session.data.cid !== session.provenance.cid) session.provenance = mintProvenance(session.sid, session.data.cid);
1904
+ 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);
1905
+ }
1906
+ /**
1907
+ * Starts a new session: the current one is archived in place for stale
1908
+ * attribution, a fresh one takes over, ended sessions are drained, and
1909
+ * the oldest are evicted beyond the configured retention.
1910
+ *
1911
+ * The data store is carried over, and the archived snapshot is frozen:
1912
+ * the ended session's value graph is detached first, so nested values
1913
+ * the caller handed to `update()` can no longer mutate it, and the new
1914
+ * session starts from a shallow copy of the detached graph, so `cid`,
1915
+ * `br`, custom keys and the rest survive a `sid` change as they always
1916
+ * have. Sessions are keyed by `sid`, which CTA-5004-B expects to be
1917
+ * unique per playback session: reusing one replaces the retained
1918
+ * namesake, whose remaining state dies as if evicted and whose late
1919
+ * responses relabel onto the replacement.
1920
+ */
1921
+ startSession(sid) {
1922
+ this.session.data = copyReportValues({ ...this.session.data });
1923
+ this.session = this.createSession(sid, { ...this.session.data });
1924
+ this.sessions.delete(sid);
1925
+ this.sessions.set(sid, this.session);
1926
+ this.processEventTargets();
1927
+ for (const key of this.sessions.keys()) {
1928
+ if (this.sessions.size <= this.config.sessionRetention + 1) break;
1929
+ this.sessions.delete(key);
1930
+ }
1931
+ if (this.started) {
1932
+ for (const config of this.config.eventTargets) if (!this.intervals.has(config)) this.armInterval(config);
1933
+ }
1667
1934
  }
1668
1935
  /**
1669
1936
  * Records an event. Called by the player when an event occurs.
@@ -1698,23 +1965,49 @@ var CmcdReporter = class {
1698
1965
  * @param data - Additional data to record with the event. This data
1699
1966
  * only applies to this event report, except for the dedup
1700
1967
  * field of a state-change event, which is also persisted
1701
- * into the reporter's data store.
1968
+ * into the reporter's data store. Session-owned keys
1969
+ * (`sid`, `msd`) supplied here are ignored; the reporter
1970
+ * stamps its own values.
1702
1971
  */
1703
1972
  recordEvent(type, data = {}) {
1973
+ this.emitEvent(this.session, type, data);
1974
+ }
1975
+ /**
1976
+ * Records an event across every configured target of a session, applying
1977
+ * state-change dedup once before per-target fan-out.
1978
+ *
1979
+ * @param session - The session the event belongs to. Everything the event
1980
+ * touches (data store, dedup baseline, counters, queues)
1981
+ * is that session's; only `recordResponseReceived()` ever
1982
+ * passes an archived one.
1983
+ * @param type - The type of event to record.
1984
+ * @param data - Additional data to record with the event.
1985
+ * @param request - The media request that triggered the event, when
1986
+ * one exists. Only `recordResponseReceived()`
1987
+ * populates this; it is threaded through to each
1988
+ * target's `transform`.
1989
+ */
1990
+ emitEvent(session, type, data, request) {
1704
1991
  const entry = STATE_FIELDS_BY_EVENT.get(type);
1705
1992
  if (entry) {
1706
1993
  const field = entry.field;
1707
1994
  const incoming = data[field];
1708
- if (incoming !== void 0) Object.assign(this.data, { [field]: incoming });
1709
- const current = this.data[field];
1995
+ if (incoming !== void 0) Object.assign(session.data, { [field]: incoming });
1996
+ const current = session.data[field];
1710
1997
  if (current === void 0) return;
1711
- if (entry.equal(current, this.lastEmitted[field])) return;
1712
- Object.assign(this.lastEmitted, { [field]: entry.snapshot(current) });
1998
+ if (entry.equal(current, session.lastEmitted[field])) return;
1999
+ Object.assign(session.lastEmitted, { [field]: entry.snapshot(current) });
1713
2000
  }
1714
- this.eventTargets.forEach((target, config) => {
1715
- this.recordTargetEvent(target, config, type, data);
2001
+ let failure;
2002
+ session.eventTargets.forEach((target, config) => {
2003
+ try {
2004
+ this.recordTargetEvent(session, target, config, type, data, request);
2005
+ } catch (error) {
2006
+ failure ??= { error };
2007
+ }
1716
2008
  });
1717
2009
  this.processEventTargets();
2010
+ if (failure) throw failure.error;
1718
2011
  }
1719
2012
  /**
1720
2013
  * Records an event for a target. Called by the reporter when an event occurs.
@@ -1725,21 +2018,58 @@ var CmcdReporter = class {
1725
2018
  * @param data - Additional data to record with the event. This data
1726
2019
  * only applies to this event report. Persistent data should
1727
2020
  * be updated using `update()`.
2021
+ * @param request - The media request that triggered the event, when
2022
+ * one exists. Passed to the target's `transform`.
1728
2023
  */
1729
- recordTargetEvent(target, config, type, data = {}) {
1730
- if (!config.events.includes(type)) return;
2024
+ recordTargetEvent(session, target, config, type, data = {}, request) {
2025
+ if (target.disposed || !config.events.includes(type)) return;
1731
2026
  const item = {
1732
- ...this.data,
2027
+ ...session.data,
1733
2028
  ...data,
2029
+ sid: session.sid,
1734
2030
  e: type,
1735
- ts: data.ts ?? Date.now(),
1736
- sn: target.sn++
2031
+ ts: data.ts ?? Date.now()
1737
2032
  };
1738
- if (!isNaN(this.msd) && !target.msdSent) {
1739
- item.msd = this.msd;
1740
- target.msdSent = true;
2033
+ const { transform } = config;
2034
+ if (!transform) {
2035
+ this.queueTargetEvent(session, target, config, item, type);
2036
+ return;
1741
2037
  }
1742
- target.queue.push(item);
2038
+ copyReportValues(item);
2039
+ const requiredKey = CMCD_REQUIRED_EVENT_KEYS.get(type);
2040
+ const requiredValue = requiredKey ? item[requiredKey] : void 0;
2041
+ const ts = item.ts;
2042
+ const report = transform(item, request);
2043
+ if (report == null) return;
2044
+ if (!isUsableRequiredValue(report.ts)) report.ts = ts;
2045
+ if (requiredKey && isUsableRequiredValue(requiredValue) && !isUsableRequiredValue(report[requiredKey])) Object.assign(report, { [requiredKey]: requiredValue });
2046
+ this.queueTargetEvent(session, target, config, report, type);
2047
+ }
2048
+ /**
2049
+ * Stamps the reporter-owned fields on a finished event report, encodes it,
2050
+ * and pushes the wire line to the target's queue.
2051
+ *
2052
+ * Called after any transform has run, so a transform cannot bypass the
2053
+ * target's `events` filter via `e`, break `sn` continuity, or substitute
2054
+ * the session identity carried by `sid` and `msd`. Encoding here means a
2055
+ * report that cannot serialize throws inside the recording call that
2056
+ * produced it, instead of rejecting the batch send and re-queueing
2057
+ * forever.
2058
+ *
2059
+ * @param target - The target to queue the report for.
2060
+ * @param config - The configuration for the target.
2061
+ * @param report - The finished report data.
2062
+ * @param type - The type of event being reported.
2063
+ */
2064
+ queueTargetEvent(session, target, config, report, type) {
2065
+ report.e = type;
2066
+ report.sn = target.sn++;
2067
+ report.sid = session.sid;
2068
+ if (!isNaN(session.msd) && !target.msdSent && config.enabledKeys?.includes("msd")) {
2069
+ report.msd = session.msd;
2070
+ target.msdSent = true;
2071
+ } else delete report.msd;
2072
+ target.queue.push(encodeCmcd(report, createEncodingOptions(CMCD_EVENT_MODE, config)));
1743
2073
  }
1744
2074
  /**
1745
2075
  * Records a response-received event. Called by the player when a media
@@ -1756,14 +2086,57 @@ var CmcdReporter = class {
1756
2086
  * Additional keys like `ttfbb`, `cmsdd`, `cmsds`, and `smrt` can be
1757
2087
  * supplied via the `data` parameter if the player has access to them.
1758
2088
  *
2089
+ * The request's `customData` is generic, so a player can pass a request
2090
+ * carrying its own taxonomy (e.g. `{ requestType: 'segment' }`) without a
2091
+ * cast. The reporter reads only the provenance record that
2092
+ * {@link CmcdReporter.createRequestReport} writes there; every other key
2093
+ * is left untouched and stays visible to an event target's `transform`
2094
+ * via its `request` argument.
2095
+ *
2096
+ * A reporter given a concrete `C` requires the request to satisfy it, so a
2097
+ * request the configured transforms could not read is rejected here rather
2098
+ * than reaching them; see {@link CmcdReporterCustomData}.
2099
+ *
2100
+ * The event is attributed to the session that issued the request, and to
2101
+ * nothing else: the provenance record that
2102
+ * {@link CmcdReporter.createRequestReport} stored on the request's
2103
+ * `customData` (under {@link CMCD_REQUEST_PROVENANCE}) selects the
2104
+ * session by its `sid`, or the response is dropped rather than
2105
+ * relabeled. There is no other key: a record lost to a serialization
2106
+ * boundary (and not restored; see the bridge notes on
2107
+ * {@link CMCD_REQUEST_PROVENANCE}) and a session no longer retained
2108
+ * (see `CmcdReporterConfig.sessionRetention`) both drop, and a per-call
2109
+ * `data.sid` cannot substitute. The record is honored wherever its
2110
+ * `sid` resolves: a request decorated by another reporter configured
2111
+ * with the same session attributes here, as does a hand-built record.
2112
+ * A response that completes after a `sid` change reports under its own
2113
+ * retained session, with that session's data snapshot and sequence
2114
+ * numbers.
2115
+ *
2116
+ * Request-time report keys come from the record's encoded per-call
2117
+ * `data` snapshot, decoded fresh per response, and the record's `cid`
2118
+ * reports in place of the session's current one, so a response that
2119
+ * completes after a mid-session content change keeps the meaning it
2120
+ * had when its request was issued.
2121
+ *
2122
+ * @typeParam RD - The `customData` this request carries. Defaults to the
2123
+ * reporter's own `C`.
2124
+ *
1759
2125
  * @param response - The HTTP response received.
1760
2126
  * @param data - Additional CMCD data to include with the event.
1761
2127
  * Values provided here override any auto-derived values.
2128
+ * Session-owned keys (`sid`, `msd`) supplied here are
2129
+ * ignored; attribution is by the provenance record alone.
1762
2130
  */
1763
2131
  recordResponseReceived(response, data = {}) {
1764
2132
  const { request } = response;
1765
2133
  const url = data.url ?? request?.url;
1766
2134
  if (!url) return;
2135
+ const provenance = request.customData?.[CMCD_REQUEST_PROVENANCE];
2136
+ const session = this.resolveSession(provenance);
2137
+ if (!session) return;
2138
+ const cmcd = decodeSnapshot(provenance);
2139
+ const { cid } = provenance;
1767
2140
  const urlObj = new URL(url);
1768
2141
  urlObj.searchParams.delete(CMCD_PARAM);
1769
2142
  const derived = {
@@ -1778,12 +2151,26 @@ var CmcdReporter = class {
1778
2151
  }
1779
2152
  if (timing.duration != null) derived.ttlb = Math.round(timing.duration);
1780
2153
  }
1781
- const cmcd = request.customData?.cmcd ?? {};
1782
- this.recordEvent(CMCD_EVENT_RESPONSE_RECEIVED, {
2154
+ this.emitEvent(session, CMCD_EVENT_RESPONSE_RECEIVED, {
2155
+ ...typeof cid === "string" && cid ? { cid } : void 0,
1783
2156
  ...cmcd,
1784
2157
  ...derived,
1785
2158
  ...data
1786
- });
2159
+ }, request);
2160
+ }
2161
+ /**
2162
+ * Resolves the session a response belongs to: the provenance record's
2163
+ * `sid` names one of this reporter's retained sessions, or the response
2164
+ * is dropped. There is no other key — a record that was lost, or that
2165
+ * names an evicted or never-seen `sid`, resolves nothing, and
2166
+ * attributing it anywhere else would relabel it. The `sid` is read
2167
+ * structurally, so a JSON-revived copy of a record attributes exactly,
2168
+ * and a hand-built record naming a retained session is honored.
2169
+ */
2170
+ resolveSession(provenance) {
2171
+ if (provenance === null || typeof provenance !== "object") return;
2172
+ const { sid } = provenance;
2173
+ return typeof sid === "string" ? this.sessions.get(sid) : void 0;
1787
2174
  }
1788
2175
  /**
1789
2176
  * Applies the CMCD request report data to the request. Called by the player
@@ -1806,9 +2193,45 @@ var CmcdReporter = class {
1806
2193
  return !!this.config.enabledKeys?.length;
1807
2194
  }
1808
2195
  /**
2196
+ * The provenance record to stamp on a returned request: the session's
2197
+ * frozen base record, extended with the caller's per-call data encoded
2198
+ * as a CMCD string when there is any. Requests without per-call data
2199
+ * share the base record, so decoration stays a single property write.
2200
+ * The snapshot never contains reporter-stamped fields, and a value that
2201
+ * cannot encode contributes no snapshot rather than failing the
2202
+ * request; its response still attributes and reports derived keys over
2203
+ * session data, matching `decodeSnapshot()`'s tolerance on the read
2204
+ * side.
2205
+ */
2206
+ createRequestProvenance(data, baseUrl) {
2207
+ const base = this.session.provenance;
2208
+ if (!data) return base;
2209
+ try {
2210
+ const encoded = encodeCmcd(data, {
2211
+ version: this.config.version,
2212
+ reportingMode: CMCD_REQUEST_MODE,
2213
+ baseUrl
2214
+ });
2215
+ return encoded ? Object.freeze({
2216
+ ...base,
2217
+ data: encoded
2218
+ }) : base;
2219
+ } catch {
2220
+ return base;
2221
+ }
2222
+ }
2223
+ /**
1809
2224
  * Creates a new request with the CMCD request report data applied. Called by the player
1810
2225
  * before sending the request.
1811
2226
  *
2227
+ * A reporter given a concrete `C` requires the request's `customData` to
2228
+ * satisfy it, so a request the configured transform could not read is
2229
+ * rejected here rather than reaching it; see
2230
+ * {@link CmcdReporterCustomData}.
2231
+ *
2232
+ * @typeParam R - The request being decorated. Its `customData` must satisfy
2233
+ * the reporter's `C`.
2234
+ *
1812
2235
  * @param request - The request to apply the CMCD request report to.
1813
2236
  * @param data - The data to apply to the request. This data only
1814
2237
  * applies to this request report. Persistent data
@@ -1822,27 +2245,38 @@ var CmcdReporter = class {
1822
2245
  headers: { ...headers },
1823
2246
  customData: {
1824
2247
  ...customData,
1825
- cmcd: {}
2248
+ cmcd: {},
2249
+ [CMCD_REQUEST_PROVENANCE]: this.createRequestProvenance(data, request.url)
1826
2250
  }
1827
2251
  };
1828
2252
  if (!this.config.enabledKeys?.length || !report.url) return report;
1829
- const url = new URL(report.url);
1830
- const cmcdData = {
1831
- ...this.data,
2253
+ const session = this.session;
2254
+ const merged = {
2255
+ ...session.data,
1832
2256
  ...data,
1833
- sn: this.requestTarget.sn++
2257
+ sid: session.sid
1834
2258
  };
1835
- const options = createEncodingOptions(CMCD_REQUEST_MODE, this.config, report.url);
1836
- if (!isNaN(this.msd) && !this.requestTarget.msdSent) {
1837
- cmcdData.msd = this.msd;
1838
- this.requestTarget.msdSent = true;
2259
+ const { transform } = this.config;
2260
+ let cmcdData = merged;
2261
+ if (transform) {
2262
+ copyReportValues(merged);
2263
+ cmcdData = transform(merged, request);
2264
+ if (cmcdData == null) return report;
1839
2265
  }
1840
- const cmcd = report.customData.cmcd = prepareCmcdData(cmcdData, options);
2266
+ cmcdData.sn = session.requestTarget.sn++;
2267
+ cmcdData.sid = session.sid;
2268
+ const sendMsd = !isNaN(session.msd) && !session.requestTarget.msdSent;
2269
+ if (sendMsd) cmcdData.msd = session.msd;
2270
+ else delete cmcdData.msd;
2271
+ const url = new URL(report.url);
2272
+ const options = createEncodingOptions(CMCD_REQUEST_MODE, this.config, report.url);
2273
+ const cmcd = report.customData.cmcd = copyReportValues(prepareCmcdData(cmcdData, options));
2274
+ if (sendMsd && cmcd.msd !== void 0) session.requestTarget.msdSent = true;
2275
+ const encoded = encodePreparedCmcd(cmcd);
1841
2276
  switch (this.config.transmissionMode) {
1842
2277
  case CMCD_QUERY:
1843
- const param = encodePreparedCmcd(cmcd);
1844
- if (param) {
1845
- url.searchParams.set(CMCD_PARAM, param);
2278
+ if (encoded) {
2279
+ url.searchParams.set(CMCD_PARAM, encoded);
1846
2280
  report.url = url.toString();
1847
2281
  }
1848
2282
  break;
@@ -1859,16 +2293,19 @@ var CmcdReporter = class {
1859
2293
  */
1860
2294
  processEventTargets(flush = false) {
1861
2295
  let reprocess = false;
1862
- this.eventTargets.forEach((target, config) => {
1863
- const { queue } = target;
1864
- if (!queue.length) return;
1865
- if (queue.length < config.batchSize && !flush) return;
1866
- const deleteCount = flush ? queue.length : config.batchSize;
1867
- const events = queue.splice(0, deleteCount);
1868
- this.sendEventReport(config, events).catch(() => {
1869
- target.queue.unshift(...events);
2296
+ this.sessions.forEach((session) => {
2297
+ const drain = flush || session !== this.session;
2298
+ session.eventTargets.forEach((target, config) => {
2299
+ const { queue } = target;
2300
+ if (target.disposed || !queue.length) return;
2301
+ if (queue.length < config.batchSize && !drain) return;
2302
+ const deleteCount = drain ? queue.length : config.batchSize;
2303
+ const events = queue.splice(0, deleteCount);
2304
+ this.sendEventReport(session, config, events).catch(() => {
2305
+ target.queue.unshift(...events);
2306
+ });
2307
+ reprocess ||= queue.length > 0;
1870
2308
  });
1871
- reprocess ||= queue.length > 0;
1872
2309
  });
1873
2310
  if (reprocess) this.processEventTargets();
1874
2311
  }
@@ -1876,44 +2313,42 @@ var CmcdReporter = class {
1876
2313
  * Sends an event report. Called by the reporter when a batch is ready to be sent.
1877
2314
  *
1878
2315
  * @param config - The target config to send the event report to.
1879
- * @param data - The data to send in the event report.
2316
+ * @param data - The encoded report lines to send in the event report.
1880
2317
  */
1881
- async sendEventReport(config, data) {
1882
- const options = createEncodingOptions(CMCD_EVENT_MODE, config);
2318
+ async sendEventReport(session, config, data) {
1883
2319
  const { status } = await this.requester({
1884
2320
  url: config.url,
1885
2321
  method: "POST",
1886
2322
  headers: { "Content-Type": CMCD_MIME_TYPE },
1887
- body: data.map((item) => encodeCmcd(item, options)).join("\n") + "\n"
2323
+ body: data.join("\n") + "\n"
1888
2324
  });
1889
- if (status === 410) this.disposeEventTarget(config);
2325
+ if (status === 410) this.disposeEventTarget(session, config);
1890
2326
  else if (status === 429 || status > 499 && status < 600) throw new Error(`Event report failed with status ${status}`);
1891
2327
  }
1892
2328
  /**
1893
- * Cancels the time-interval timer for an event target and clears the stored id.
1894
- * Safe to call when no timer is armed (clearInterval(undefined) is a no-op).
1895
- */
1896
- disarmInterval(target) {
1897
- clearInterval(target.intervalId);
1898
- target.intervalId = void 0;
1899
- }
1900
- /**
1901
- * Permanently removes an event target: cancels its timer and removes it from the
1902
- * eventTargets map. Used when the collector signals the target is gone (HTTP 410).
2329
+ * Cancels the time-interval timer for an event target config and clears the
2330
+ * stored id. Safe to call when no timer is armed (clearInterval(undefined)
2331
+ * is a no-op).
1903
2332
  */
1904
- disposeEventTarget(config) {
1905
- const target = this.eventTargets.get(config);
1906
- if (!target) return;
1907
- this.disarmInterval(target);
1908
- this.eventTargets.delete(config);
2333
+ disarmInterval(config) {
2334
+ clearInterval(this.intervals.get(config));
2335
+ this.intervals.delete(config);
1909
2336
  }
1910
2337
  /**
1911
- * Resets the session related data. Called when the session ID changes.
2338
+ * Silences an event target URL for the remainder of its session: drops the
2339
+ * queues and blocks further enqueues for every config in the session that
2340
+ * reports to the URL, per CTA-5004-B's per-target-URL suppression scope,
2341
+ * and cancels their timers when the session is the live one. Used when the
2342
+ * collector signals the target is gone (HTTP 410). A session started after
2343
+ * the disposal is unaffected, since it gets fresh target state.
1912
2344
  */
1913
- resetSession() {
1914
- this.eventTargets.forEach((target) => target.sn = 0);
1915
- this.requestTarget.sn = 0;
1916
- this.lastEmitted = {};
2345
+ disposeEventTarget(session, config) {
2346
+ session.eventTargets.forEach((target, sibling) => {
2347
+ if (sibling.url !== config.url || target.disposed) return;
2348
+ target.disposed = true;
2349
+ target.queue.length = 0;
2350
+ if (session === this.session) this.disarmInterval(sibling);
2351
+ });
1917
2352
  }
1918
2353
  };
1919
2354
 
@@ -1976,51 +2411,6 @@ const CmcdValidationSeverity = {
1976
2411
  WARNING: CMCD_VALIDATION_SEVERITY_WARNING
1977
2412
  };
1978
2413
 
1979
- //#endregion
1980
- //#region src/upConvertToV2.ts
1981
- /**
1982
- * Up-convert V1 CMCD data to V2 format.
1983
- *
1984
- * - Wraps plain scalar values in arrays for inner-list keys.
1985
- * - Wraps `nor` string in an array.
1986
- *
1987
- * If the data is already V2 (has `v: 2`), it is returned unchanged.
1988
- *
1989
- * @internal
1990
- */
1991
- function upConvertToV2(obj) {
1992
- if (obj["v"] === CMCD_V2) return obj;
1993
- const result = {};
1994
- for (const [key, value] of Object.entries(obj)) {
1995
- if (value == null) {
1996
- result[key] = value;
1997
- continue;
1998
- }
1999
- if (CMCD_INNER_LIST_KEYS.has(key) && !Array.isArray(value)) result[key] = [value];
2000
- else if (key === "nor" && typeof value === "string") result[key] = [value];
2001
- else result[key] = value;
2002
- }
2003
- return result;
2004
- }
2005
-
2006
- //#endregion
2007
- //#region src/decodeCmcd.ts
2008
- function reduceValue(value) {
2009
- if (Array.isArray(value)) return value.map(reduceValue);
2010
- if (typeof value === "symbol") return symbolToStr(value);
2011
- if (value instanceof SfItem && !value.params) return reduceValue(value.value);
2012
- if (typeof value === "string") return value;
2013
- return value;
2014
- }
2015
- function decodeCmcd(cmcd, options) {
2016
- if (!cmcd) return {};
2017
- const sfDict = decodeSfDict(cmcd);
2018
- const result = {};
2019
- for (const [key, item] of Object.entries(sfDict)) result[key] = reduceValue(item.value);
2020
- if (options?.convertToLatest) return upConvertToV2(result);
2021
- return result;
2022
- }
2023
-
2024
2414
  //#endregion
2025
2415
  //#region src/ensureHeaders.ts
2026
2416
  /**
@@ -2941,5 +3331,5 @@ function extractHeaderRecord(headers) {
2941
3331
  }
2942
3332
 
2943
3333
  //#endregion
2944
- 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 };
3334
+ 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 };
2945
3335
  //# sourceMappingURL=index.js.map