@svta/cml-cmcd 2.4.0 → 2.5.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
@@ -217,7 +217,7 @@ const CmcdEventType = {
217
217
  *
218
218
  * @internal
219
219
  */
220
- const CMCD_STATE_EVENT_FIELDS = new Map([
220
+ const CMCD_STATE_EVENT_FIELDS = /* @__PURE__ */ new Map([
221
221
  [CMCD_EVENT_PLAY_STATE, "sta"],
222
222
  [CMCD_EVENT_PLAYBACK_RATE, "pr"],
223
223
  [CMCD_EVENT_CONTENT_ID, "cid"],
@@ -315,23 +315,30 @@ const CMCD_REQUEST_KEYS = [
315
315
 
316
316
  //#endregion
317
317
  //#region src/isCmcdCustomKey.ts
318
- const CUSTOM_KEY_REGEX = /^[a-zA-Z0-9-.]+-[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
  *
324
327
  * @returns `true` if the key is a custom key, `false` otherwise.
325
328
  *
326
329
  * @public
330
+ *
331
+ * @example
332
+ * {@includeCode ../test/isCmcdCustomKey.test.ts#example}
327
333
  */
328
334
  function isCmcdCustomKey(key) {
329
- return CUSTOM_KEY_REGEX.test(key);
335
+ const separator = key.indexOf("-", 1);
336
+ return separator > 0 && separator < key.length - 1 && CUSTOM_KEY_REGEX.test(key);
330
337
  }
331
338
 
332
339
  //#endregion
333
340
  //#region src/isCmcdRequestKey.ts
334
- const CMCD_REQUEST_KEY_SET = new Set(CMCD_REQUEST_KEYS);
341
+ const CMCD_REQUEST_KEY_SET = /* @__PURE__ */ new Set(CMCD_REQUEST_KEYS);
335
342
  /**
336
343
  * Check if a key is a valid CMCD request key.
337
344
  *
@@ -368,7 +375,7 @@ const CMCD_RESPONSE_KEYS = [
368
375
 
369
376
  //#endregion
370
377
  //#region src/isCmcdResponseReceivedKey.ts
371
- const CMCD_RESPONSE_KEY_SET = new Set(CMCD_RESPONSE_KEYS);
378
+ const CMCD_RESPONSE_KEY_SET = /* @__PURE__ */ new Set(CMCD_RESPONSE_KEYS);
372
379
  /**
373
380
  * Check if a key is a valid CMCD response key.
374
381
  *
@@ -387,7 +394,7 @@ function isCmcdResponseReceivedKey(key) {
387
394
 
388
395
  //#endregion
389
396
  //#region src/isCmcdEventKey.ts
390
- const CMCD_EVENT_KEY_SET = new Set(CMCD_EVENT_KEYS);
397
+ const CMCD_EVENT_KEY_SET = /* @__PURE__ */ new Set(CMCD_EVENT_KEYS);
391
398
  /**
392
399
  * Check if a key is a valid CMCD event key.
393
400
  *
@@ -460,7 +467,7 @@ const CMCD_V1_KEYS = [
460
467
 
461
468
  //#endregion
462
469
  //#region src/isCmcdV1Key.ts
463
- const CMCD_V1_KEY_SET$1 = new Set(CMCD_V1_KEYS);
470
+ const CMCD_V1_KEY_SET$1 = /* @__PURE__ */ new Set(CMCD_V1_KEYS);
464
471
  /**
465
472
  * Filter function for CMCD v1 keys.
466
473
  *
@@ -479,7 +486,7 @@ function isCmcdV1Key(key) {
479
486
 
480
487
  //#endregion
481
488
  //#region src/isTokenField.ts
482
- const TOKEN_FIELDS = new Set([
489
+ const TOKEN_FIELDS = /* @__PURE__ */ new Set([
483
490
  "ot",
484
491
  "sf",
485
492
  "st",
@@ -565,6 +572,9 @@ function downConvertToV1(obj) {
565
572
  * @param options - Options for encoding.
566
573
  *
567
574
  * @public
575
+ *
576
+ * @example
577
+ * {@includeCode ../test/prepareCmcdData.test.ts#example}
568
578
  */
569
579
  function prepareCmcdData(obj, options = {}) {
570
580
  const results = {};
@@ -583,6 +593,8 @@ function prepareCmcdData(obj, options = {}) {
583
593
  if (!keys.includes("e") && eventType != null) keys.push("e");
584
594
  if (!keys.includes("ts")) keys.push("ts");
585
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");
586
598
  const requiredField = eventType ? CMCD_STATE_EVENT_FIELDS.get(eventType) : void 0;
587
599
  if (requiredField && data[requiredField] != null && !keys.includes(requiredField)) keys.push(requiredField);
588
600
  }
@@ -942,7 +954,7 @@ const CMCD_DEFAULT_TIME_INTERVAL = 30;
942
954
  *
943
955
  * @public
944
956
  */
945
- const CMCD_KEYS = [
957
+ const CMCD_KEYS = /* @__PURE__ */ [
946
958
  ...CMCD_V1_KEYS,
947
959
  ...CMCD_REQUEST_KEYS,
948
960
  ...CMCD_RESPONSE_KEYS,
@@ -1469,7 +1481,8 @@ function createEncodingOptions(reportingMode, config, baseUrl) {
1469
1481
  version: config.version || CMCD_V2,
1470
1482
  reportingMode,
1471
1483
  filter: (key) => enabledKeySet.has(key),
1472
- baseUrl
1484
+ baseUrl,
1485
+ customHeaderMap: config.customHeaderMap
1473
1486
  };
1474
1487
  }
1475
1488
  /**
@@ -1504,7 +1517,7 @@ const identity = (v) => v;
1504
1517
  * Maps each tracked state field to its event type and equality function.
1505
1518
  * Order matters: `update()` fires events in this order for multi-field updates.
1506
1519
  */
1507
- const STATE_FIELDS = Array.from(CMCD_STATE_EVENT_FIELDS, ([event, field]) => {
1520
+ const STATE_FIELDS = /* @__PURE__ */ Array.from(CMCD_STATE_EVENT_FIELDS, ([event, field]) => {
1508
1521
  if (field === "br") return {
1509
1522
  event,
1510
1523
  field,
@@ -1518,7 +1531,69 @@ const STATE_FIELDS = Array.from(CMCD_STATE_EVENT_FIELDS, ([event, field]) => {
1518
1531
  snapshot: identity
1519
1532
  };
1520
1533
  });
1521
- const STATE_FIELDS_BY_EVENT = new Map(STATE_FIELDS.map((e) => [e.event, e]));
1534
+ const STATE_FIELDS_BY_EVENT = /* @__PURE__ */ new Map(/* @__PURE__ */ STATE_FIELDS.map((e) => [e.event, e]));
1535
+ /**
1536
+ * Maps each event type to the key CTA-5004-B requires beyond `e` and `ts`.
1537
+ * Built from the state-change table plus the three event types whose
1538
+ * required key rides the caller's per-event data.
1539
+ */
1540
+ const CMCD_REQUIRED_EVENT_KEYS = /* @__PURE__ */ new Map([
1541
+ ...CMCD_STATE_EVENT_FIELDS,
1542
+ [CMCD_EVENT_CUSTOM_EVENT, "cen"],
1543
+ [CMCD_EVENT_ERROR, "ec"],
1544
+ [CMCD_EVENT_RESPONSE_RECEIVED, "url"]
1545
+ ]);
1546
+ /**
1547
+ * Whether a required key's value will survive report preparation.
1548
+ *
1549
+ * This is `isValid` minus its `false` exclusion, plus an empty-array check.
1550
+ * `false` must count as usable because `bg: false` is a legitimate value on a
1551
+ * backgrounded-mode event, which the encoder emits as `?0`; treating it as
1552
+ * unusable would let restoration silently revert a transform that cleared it.
1553
+ * Empty strings, empty lists and non-finite numbers are dropped downstream, so
1554
+ * a transform substituting one leaves the report short a required key.
1555
+ */
1556
+ function isUsableRequiredValue(value) {
1557
+ if (value == null || value === "") return false;
1558
+ if (typeof value === "number") return Number.isFinite(value);
1559
+ return !Array.isArray(value) || value.length > 0;
1560
+ }
1561
+ /**
1562
+ * Copies an `SfItem`-shaped value and its `params` record.
1563
+ *
1564
+ * The prototype is preserved because `prepareCmcdData`, the formatter map,
1565
+ * validation, and the structured-field encoder all branch on
1566
+ * `instanceof SfItem`. A plain spread (and `structuredClone`) would return a
1567
+ * prototype-less object and silently change what goes on the wire.
1568
+ */
1569
+ function copyItemValue(value) {
1570
+ if (value === null || typeof value !== "object") return value;
1571
+ const copy = Object.assign(Object.create(Object.getPrototypeOf(value)), value);
1572
+ if (copy.params !== null && typeof copy.params === "object") copy.params = { ...copy.params };
1573
+ return copy;
1574
+ }
1575
+ /**
1576
+ * Copies the nested values of a report in place so a transform cannot mutate
1577
+ * the reporter's persistent data, or another target's report for the same
1578
+ * event, by mutating an array or an `SfItem` it was handed.
1579
+ *
1580
+ * Complete for the CMCD value space rather than best-effort: `CmcdValue` and
1581
+ * `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.
1584
+ */
1585
+ function copyReportValues(data) {
1586
+ const record = data;
1587
+ for (const key in record) {
1588
+ const value = record[key];
1589
+ if (Array.isArray(value)) {
1590
+ const copy = new Array(value.length);
1591
+ for (let i = 0; i < value.length; i++) copy[i] = copyItemValue(value[i]);
1592
+ record[key] = copy;
1593
+ } else if (value !== null && typeof value === "object") record[key] = copyItemValue(value);
1594
+ }
1595
+ return data;
1596
+ }
1522
1597
  function defaultRequester(request) {
1523
1598
  const { url,...init } = request;
1524
1599
  return fetch(url, init);
@@ -1537,7 +1612,8 @@ function createCmcdReporterConfig(config) {
1537
1612
  url: target.url,
1538
1613
  events: target.events.slice(),
1539
1614
  interval: target.interval ?? CMCD_DEFAULT_TIME_INTERVAL,
1540
- batchSize: target.batchSize || 1
1615
+ batchSize: target.batchSize || 1,
1616
+ transform: target.transform
1541
1617
  });
1542
1618
  return acc;
1543
1619
  }, [])
@@ -1546,6 +1622,14 @@ function createCmcdReporterConfig(config) {
1546
1622
  /**
1547
1623
  * The CMCD reporter.
1548
1624
  *
1625
+ * `C` describes the player's own `customData`, which the reporter passes
1626
+ * through to each configured `transform`. It is inferred from the
1627
+ * configuration, so annotating a single `transform` types the request in every
1628
+ * other one; the default leaves `customData` values `unknown`.
1629
+ *
1630
+ * @typeParam C - The shape of the player's `customData`. Defaults to
1631
+ * `Record<string, unknown>`.
1632
+ *
1549
1633
  * @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}
1550
1634
  *
1551
1635
  * @public
@@ -1591,6 +1675,7 @@ var CmcdReporter = class {
1591
1675
  * populated before calling start().
1592
1676
  */
1593
1677
  start() {
1678
+ let failure;
1594
1679
  this.eventTargets.forEach((target, config) => {
1595
1680
  this.disarmInterval(target);
1596
1681
  if (config.interval === 0 || !config.events.includes(CMCD_EVENT_TIME_INTERVAL)) return;
@@ -1599,8 +1684,13 @@ var CmcdReporter = class {
1599
1684
  this.processEventTargets();
1600
1685
  };
1601
1686
  target.intervalId = setInterval(timeIntervalEvent, config.interval * 1e3);
1602
- timeIntervalEvent();
1687
+ try {
1688
+ timeIntervalEvent();
1689
+ } catch (error) {
1690
+ failure ??= { error };
1691
+ }
1603
1692
  });
1693
+ if (failure) throw failure.error;
1604
1694
  }
1605
1695
  /**
1606
1696
  * Stops the CMCD reporter. Called by the player when the reporter is disabled.
@@ -1637,6 +1727,16 @@ var CmcdReporter = class {
1637
1727
  * `cid` → `bg` → `br`. The order of keys in the input object does not
1638
1728
  * affect the firing order.
1639
1729
  *
1730
+ * To attach snapshot context (e.g., `bl`, `mtp`, `pt`, `ltc`) to a
1731
+ * state-change event, ensure those fields are in the reporter's data
1732
+ * before the state field changes. Either include them alongside the
1733
+ * state field in the same `update()` call, or persist them via earlier
1734
+ * `update()` calls — auto-fired events emit whatever is currently in
1735
+ * the persistent data store. This is also how to keep `TIME_INTERVAL`
1736
+ * reports useful — those events draw from the persistent data store
1737
+ * with no caller hook for per-event data, so fields the player wants
1738
+ * in periodic reports must be kept fresh here.
1739
+ *
1640
1740
  * A `sid` change resets the dedup baseline.
1641
1741
  *
1642
1742
  * @param data - The data to update.
@@ -1666,9 +1766,19 @@ var CmcdReporter = class {
1666
1766
  *
1667
1767
  * For all other event types, the event is always emitted.
1668
1768
  *
1669
- * Most callers can rely on {@link CmcdReporter.update} to auto-fire state-change events.
1670
- * Use `recordEvent` directly when you need to attach extra context to the
1671
- * event report (e.g., `bl`, `pt` at the moment of a play-state transition).
1769
+ * For state-change events, prefer {@link CmcdReporter.update} — including
1770
+ * for snapshot enrichment via a combined call like
1771
+ * `update({ sta: 'p', bl: [3000], mtp: [8500] })`. Calling `recordEvent()`
1772
+ * for a state-change event after `update()` has already auto-fired it
1773
+ * silently drops the second call's `data`, because dedup suppresses the
1774
+ * second emission.
1775
+ *
1776
+ * Use `recordEvent()` directly for events whose payload is intrinsic to
1777
+ * the event call — `CUSTOM_EVENT` with `cen`, `ERROR` with `ec`,
1778
+ * ad-lifecycle events, `MUTE`/`UNMUTE`, `PLAYER_EXPAND`/`PLAYER_COLLAPSE`,
1779
+ * `SKIP`. For `RESPONSE_RECEIVED`, prefer
1780
+ * {@link CmcdReporter.recordResponseReceived}, which derives the
1781
+ * per-response fields automatically.
1672
1782
  *
1673
1783
  * @param type - The type of event to record.
1674
1784
  * @param data - Additional data to record with the event. This data
@@ -1677,6 +1787,20 @@ var CmcdReporter = class {
1677
1787
  * into the reporter's data store.
1678
1788
  */
1679
1789
  recordEvent(type, data = {}) {
1790
+ this.emitEvent(type, data);
1791
+ }
1792
+ /**
1793
+ * Records an event across every configured target, applying
1794
+ * state-change dedup once before per-target fan-out.
1795
+ *
1796
+ * @param type - The type of event to record.
1797
+ * @param data - Additional data to record with the event.
1798
+ * @param request - The media request that triggered the event, when
1799
+ * one exists. Only `recordResponseReceived()`
1800
+ * populates this; it is threaded through to each
1801
+ * target's `transform`.
1802
+ */
1803
+ emitEvent(type, data, request) {
1680
1804
  const entry = STATE_FIELDS_BY_EVENT.get(type);
1681
1805
  if (entry) {
1682
1806
  const field = entry.field;
@@ -1687,10 +1811,16 @@ var CmcdReporter = class {
1687
1811
  if (entry.equal(current, this.lastEmitted[field])) return;
1688
1812
  Object.assign(this.lastEmitted, { [field]: entry.snapshot(current) });
1689
1813
  }
1814
+ let failure;
1690
1815
  this.eventTargets.forEach((target, config) => {
1691
- this.recordTargetEvent(target, config, type, data);
1816
+ try {
1817
+ this.recordTargetEvent(target, config, type, data, request);
1818
+ } catch (error) {
1819
+ failure ??= { error };
1820
+ }
1692
1821
  });
1693
1822
  this.processEventTargets();
1823
+ if (failure) throw failure.error;
1694
1824
  }
1695
1825
  /**
1696
1826
  * Records an event for a target. Called by the reporter when an event occurs.
@@ -1701,21 +1831,51 @@ var CmcdReporter = class {
1701
1831
  * @param data - Additional data to record with the event. This data
1702
1832
  * only applies to this event report. Persistent data should
1703
1833
  * be updated using `update()`.
1834
+ * @param request - The media request that triggered the event, when
1835
+ * one exists. Passed to the target's `transform`.
1704
1836
  */
1705
- recordTargetEvent(target, config, type, data = {}) {
1837
+ recordTargetEvent(target, config, type, data = {}, request) {
1706
1838
  if (!config.events.includes(type)) return;
1707
1839
  const item = {
1708
1840
  ...this.data,
1709
1841
  ...data,
1710
1842
  e: type,
1711
- ts: data.ts ?? Date.now(),
1712
- sn: target.sn++
1843
+ ts: data.ts ?? Date.now()
1713
1844
  };
1845
+ const { transform } = config;
1846
+ if (!transform) {
1847
+ this.queueTargetEvent(target, item, type);
1848
+ return;
1849
+ }
1850
+ copyReportValues(item);
1851
+ const requiredKey = CMCD_REQUIRED_EVENT_KEYS.get(type);
1852
+ const requiredValue = requiredKey ? item[requiredKey] : void 0;
1853
+ const ts = item.ts;
1854
+ const report = transform(item, request);
1855
+ if (report == null) return;
1856
+ if (!isUsableRequiredValue(report.ts)) report.ts = ts;
1857
+ if (requiredKey && isUsableRequiredValue(requiredValue) && !isUsableRequiredValue(report[requiredKey])) Object.assign(report, { [requiredKey]: requiredValue });
1858
+ this.queueTargetEvent(target, report, type);
1859
+ }
1860
+ /**
1861
+ * Stamps the reporter-owned fields on a finished event report and pushes it
1862
+ * to the target's queue.
1863
+ *
1864
+ * Called after any transform has run, so a transform cannot bypass the
1865
+ * target's `events` filter via `e` or break `sn` continuity.
1866
+ *
1867
+ * @param target - The target to queue the report for.
1868
+ * @param report - The finished report data.
1869
+ * @param type - The type of event being reported.
1870
+ */
1871
+ queueTargetEvent(target, report, type) {
1872
+ report.e = type;
1873
+ report.sn = target.sn++;
1714
1874
  if (!isNaN(this.msd) && !target.msdSent) {
1715
- item.msd = this.msd;
1875
+ report.msd = this.msd;
1716
1876
  target.msdSent = true;
1717
1877
  }
1718
- target.queue.push(item);
1878
+ target.queue.push(report);
1719
1879
  }
1720
1880
  /**
1721
1881
  * Records a response-received event. Called by the player when a media
@@ -1732,6 +1892,20 @@ var CmcdReporter = class {
1732
1892
  * Additional keys like `ttfbb`, `cmsdd`, `cmsds`, and `smrt` can be
1733
1893
  * supplied via the `data` parameter if the player has access to them.
1734
1894
  *
1895
+ * The request's `customData` is generic, so a player can pass a request
1896
+ * 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.
1901
+ *
1902
+ * A reporter given a concrete `C` requires the request to satisfy it, so a
1903
+ * request the configured transforms could not read is rejected here rather
1904
+ * than reaching them; see {@link CmcdReporterCustomData}.
1905
+ *
1906
+ * @typeParam RD - The `customData` this request carries. Defaults to the
1907
+ * reporter's own `C`.
1908
+ *
1735
1909
  * @param response - The HTTP response received.
1736
1910
  * @param data - Additional CMCD data to include with the event.
1737
1911
  * Values provided here override any auto-derived values.
@@ -1755,11 +1929,11 @@ var CmcdReporter = class {
1755
1929
  if (timing.duration != null) derived.ttlb = Math.round(timing.duration);
1756
1930
  }
1757
1931
  const cmcd = request.customData?.cmcd ?? {};
1758
- this.recordEvent(CMCD_EVENT_RESPONSE_RECEIVED, {
1932
+ this.emitEvent(CMCD_EVENT_RESPONSE_RECEIVED, {
1759
1933
  ...cmcd,
1760
1934
  ...derived,
1761
1935
  ...data
1762
- });
1936
+ }, request);
1763
1937
  }
1764
1938
  /**
1765
1939
  * Applies the CMCD request report data to the request. Called by the player
@@ -1785,6 +1959,14 @@ var CmcdReporter = class {
1785
1959
  * Creates a new request with the CMCD request report data applied. Called by the player
1786
1960
  * before sending the request.
1787
1961
  *
1962
+ * A reporter given a concrete `C` requires the request's `customData` to
1963
+ * satisfy it, so a request the configured transform could not read is
1964
+ * rejected here rather than reaching it; see
1965
+ * {@link CmcdReporterCustomData}.
1966
+ *
1967
+ * @typeParam R - The request being decorated. Its `customData` must satisfy
1968
+ * the reporter's `C`.
1969
+ *
1788
1970
  * @param request - The request to apply the CMCD request report to.
1789
1971
  * @param data - The data to apply to the request. This data only
1790
1972
  * applies to this request report. Persistent data
@@ -1802,17 +1984,24 @@ var CmcdReporter = class {
1802
1984
  }
1803
1985
  };
1804
1986
  if (!this.config.enabledKeys?.length || !report.url) return report;
1805
- const url = new URL(report.url);
1806
- const cmcdData = {
1987
+ const merged = {
1807
1988
  ...this.data,
1808
- ...data,
1809
- sn: this.requestTarget.sn++
1989
+ ...data
1810
1990
  };
1811
- const options = createEncodingOptions(CMCD_REQUEST_MODE, this.config, report.url);
1991
+ const { transform } = this.config;
1992
+ let cmcdData = merged;
1993
+ if (transform) {
1994
+ copyReportValues(merged);
1995
+ cmcdData = transform(merged, request);
1996
+ if (cmcdData == null) return report;
1997
+ }
1998
+ cmcdData.sn = this.requestTarget.sn++;
1812
1999
  if (!isNaN(this.msd) && !this.requestTarget.msdSent) {
1813
2000
  cmcdData.msd = this.msd;
1814
2001
  this.requestTarget.msdSent = true;
1815
2002
  }
2003
+ const url = new URL(report.url);
2004
+ const options = createEncodingOptions(CMCD_REQUEST_MODE, this.config, report.url);
1816
2005
  const cmcd = report.customData.cmcd = prepareCmcdData(cmcdData, options);
1817
2006
  switch (this.config.transmissionMode) {
1818
2007
  case CMCD_QUERY:
@@ -2119,8 +2308,8 @@ function resolveVersion(data, options) {
2119
2308
 
2120
2309
  //#endregion
2121
2310
  //#region src/validateCmcdKeys.ts
2122
- const CMCD_V1_KEY_SET = new Set(CMCD_V1_KEYS);
2123
- const CMCD_KEY_SET = new Set(CMCD_KEYS);
2311
+ const CMCD_V1_KEY_SET = /* @__PURE__ */ new Set(CMCD_V1_KEYS);
2312
+ const CMCD_KEY_SET = /* @__PURE__ */ new Set(CMCD_KEYS);
2124
2313
  /**
2125
2314
  * Validates that all keys in a CMCD payload are recognized spec keys or valid custom keys.
2126
2315
  *
@@ -2454,14 +2643,14 @@ const CMCD_TOKEN_VALUES = {
2454
2643
 
2455
2644
  //#endregion
2456
2645
  //#region src/validateCmcdValues.ts
2457
- const HUNDRED_ROUNDING_KEYS = new Set([
2646
+ const HUNDRED_ROUNDING_KEYS = /* @__PURE__ */ new Set([
2458
2647
  "bl",
2459
2648
  "dl",
2460
2649
  "mtp",
2461
2650
  "rtp",
2462
2651
  "tbl"
2463
2652
  ]);
2464
- const INTEGER_ROUNDING_KEYS = new Set([
2653
+ const INTEGER_ROUNDING_KEYS = /* @__PURE__ */ new Set([
2465
2654
  "br",
2466
2655
  "d",
2467
2656
  "tb"