@svta/cml-cmcd 2.5.0 → 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/README.md +4 -4
- package/dist/index.d.ts +229 -30
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +379 -154
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["CMCD_FORMATTER_MAP: Record<string, CmcdFormatter>","CMCD_STATE_EVENT_FIELDS: ReadonlyMap<CmcdEventType, CmcdKey>","CMCD_REQUEST_KEY_SET: ReadonlySet<string>","CMCD_RESPONSE_KEY_SET: ReadonlySet<string>","CMCD_EVENT_KEY_SET: ReadonlySet<string>","CMCD_INNER_LIST_KEYS: Set<string>","CMCD_V1_KEY_SET: ReadonlySet<string>","CMCD_V1_KEY_SET","filterMap: Record<string, (key: string) => boolean>","item: any","item","result: Record<string, any>","results: Cmcd","formatterOptions: CmcdFormatterOptions","CMCD_HEADER_FIELDS: readonly CmcdHeaderField[]","CMCD_HEADER_MAP: Record<CmcdRequestKey | 'nrr', CmcdHeaderField>","custom: Partial<Record<CmcdHeaderKey, CmcdHeaderField>>","CMCD_KEYS: CmcdKey[]","headers: Record<string, string>","body: string | undefined","ProgressEventCtor: typeof ProgressEvent | typeof Event","#deliver","#eventTargetUrls","captured: CmcdRecordedReport","#reports","#onReport","#notifyWaiters","#waiters","#getMatching","#waitTimeout","#attached","#detachers","#waitFor","STATE_FIELDS: readonly StateFieldEntry[]","STATE_FIELDS_BY_EVENT: ReadonlyMap<CmcdEventType, StateFieldEntry>","CMCD_REQUIRED_EVENT_KEYS: ReadonlyMap<CmcdEventType, CmcdKey>","failure: { error: unknown; } | undefined","item: Cmcd","derived: Partial<Cmcd>","merged: Cmcd","cmcdData: Cmcd | null","result: Record<string, any>","result: Record<string, unknown>","result: Record<string, unknown>","CMCD_V1_KEY_SET: ReadonlySet<string>","CMCD_KEY_SET: ReadonlySet<string>","issues: CmcdValidationResult['issues']","issues: CmcdValidationIssue[]","CMCD_KEY_TYPES: Record<string, string>","CMCD_V1_KEY_TYPE_OVERRIDES: Record<string, string>","CMCD_STRING_LENGTH_LIMITS: Record<string, number>","CMCD_TOKEN_VALUES: Record<string, readonly string[]>","issues: CmcdValidationIssue[]","decodedLines: CmcdData[]","lineResults: CmcdValidationResult[]","issues: CmcdEventsValidationResult['issues']","issues: CmcdValidationResult['issues']","decoded: Partial<Record<CmcdHeaderField, Record<string, unknown>>>","shard: Record<string, unknown>","shardResult: CmcdValidationResult","merged: Record<string, unknown>","data: CmcdData","result: Partial<Record<CmcdHeaderField, string>>"],"sources":["../src/CMCD_FORMATTER_MAP.ts","../src/CMCD_V2.ts","../src/CmcdEventType.ts","../src/CMCD_STATE_EVENT_FIELDS.ts","../src/CmcdReportingMode.ts","../src/CMCD_EVENT_KEYS.ts","../src/CMCD_REQUEST_KEYS.ts","../src/isCmcdCustomKey.ts","../src/isCmcdRequestKey.ts","../src/CMCD_RESPONSE_KEYS.ts","../src/isCmcdResponseReceivedKey.ts","../src/isCmcdEventKey.ts","../src/CMCD_INNER_LIST_KEYS.ts","../src/CMCD_V1_KEYS.ts","../src/isCmcdV1Key.ts","../src/isTokenField.ts","../src/isValid.ts","../src/prepareCmcdData.ts","../src/CmcdHeaderField.ts","../src/CMCD_HEADER_MAP.ts","../src/groupCmcdHeaders.ts","../src/toPreparedCmcdHeaders.ts","../src/toCmcdHeaders.ts","../src/appendCmcdHeaders.ts","../src/CMCD_PARAM.ts","../src/encodePreparedCmcd.ts","../src/encodeCmcd.ts","../src/toCmcdUrl.ts","../src/toCmcdQuery.ts","../src/appendCmcdQuery.ts","../src/CMCD_DEFAULT_TIME_INTERVAL.ts","../src/CMCD_KEYS.ts","../src/CMCD_MIME_TYPE.ts","../src/CMCD_V1.ts","../src/CmcdObjectType.ts","../src/CmcdPlayerState.ts","../src/CmcdRecordedReportMode.ts","../src/CmcdRecordedRequestType.ts","../src/createFetchTransport.ts","../src/createXhrTransport.ts","../src/CmcdReportRecorder.ts","../src/CmcdTransmissionMode.ts","../src/CmcdReporter.ts","../src/CmcdStreamingFormat.ts","../src/CmcdStreamType.ts","../src/CmcdValidationSeverity.ts","../src/upConvertToV2.ts","../src/decodeCmcd.ts","../src/ensureHeaders.ts","../src/fromCmcdHeaders.ts","../src/fromCmcdQuery.ts","../src/fromCmcdUrl.ts","../src/isCmcdV1Data.ts","../src/isCmcdV2Data.ts","../src/toCmcdValue.ts","../src/mergeValidationResults.ts","../src/resolveVersion.ts","../src/validateCmcdKeys.ts","../src/validateCmcdStructure.ts","../src/CMCD_KEY_TYPES.ts","../src/CMCD_STRING_LENGTH_LIMITS.ts","../src/CMCD_TOKEN_VALUES.ts","../src/validateCmcdValues.ts","../src/validateCmcd.ts","../src/validateCmcdEvents.ts","../src/validateCmcdEventReport.ts","../src/validateCmcdHeaders.ts","../src/validateCmcdRequest.ts"],"sourcesContent":["import { SfItem } from '@svta/cml-structured-field-values'\nimport { getBaseUrl, urlToRelativePath, type ValueOrArray } from '@svta/cml-utils'\nimport type { CmcdFormatter } from './CmcdFormatter.ts'\nimport type { CmcdFormatterOptions } from './CmcdFormatterOptions.ts'\nimport type { CmcdValue } from './CmcdValue.ts'\n\nconst roundValue = (value: CmcdValue): number | SfItem<number> => {\n\tif (value instanceof SfItem) {\n\t\treturn new SfItem(Math.round(value.value as number), value.params)\n\t}\n\treturn Math.round(value as number)\n}\n\nconst toRounded = (value: CmcdValue) => {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(roundValue)\n\t}\n\treturn roundValue(value)\n}\n\nconst toUrlSafe = (value: CmcdValue, options: CmcdFormatterOptions): ValueOrArray<string | SfItem<string>> => {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(item => toUrlSafe(item, options) as string)\n\t}\n\n\tif (value instanceof SfItem && typeof value.value === 'string') {\n\t\treturn new SfItem(toUrlSafe(value.value, options), value.params)\n\t}\n\telse {\n\t\tif (options.baseUrl) {\n\t\t\tvalue = urlToRelativePath(value as string, getBaseUrl(options.baseUrl))\n\t\t}\n\t\treturn options.version === 1 ? encodeURIComponent(value as string) : (value as string)\n\t}\n}\n\nconst hundredValue = (value: CmcdValue): number | SfItem<number> => {\n\tif (value instanceof SfItem) {\n\t\treturn new SfItem(Math.round((value.value as number) / 100) * 100, value.params)\n\t}\n\treturn Math.round((value as number) / 100) * 100\n}\n\nconst toHundred = (value: CmcdValue) => {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(hundredValue)\n\t}\n\treturn hundredValue(value)\n}\n\nconst nor = (value: CmcdValue, options: CmcdFormatterOptions) => {\n\tlet norValue = value\n\n\tif (options.version >= 2) {\n\t\tif (value instanceof SfItem && typeof value.value === 'string') {\n\t\t\tnorValue = new SfItem([value])\n\t\t}\n\t\telse if (typeof value === 'string') {\n\t\t\tnorValue = [value]\n\t\t}\n\t}\n\n\treturn toUrlSafe(norValue, options)\n}\n\n/**\n * The default formatters for CMCD values.\n *\n * @public\n */\nexport const CMCD_FORMATTER_MAP: Record<string, CmcdFormatter> = {\n\t/**\n\t * Bitrate (kbps) rounded integer\n\t */\n\tbr: toRounded,\n\n\t/**\n\t * Duration (milliseconds) rounded integer\n\t */\n\td: toRounded,\n\n\t/**\n\t * Buffer Length (milliseconds) rounded nearest 100ms\n\t */\n\tbl: toHundred,\n\n\t/**\n\t * Deadline (milliseconds) rounded nearest 100ms\n\t */\n\tdl: toHundred,\n\n\t/**\n\t * Measured Throughput (kbps) rounded nearest 100kbps\n\t */\n\tmtp: toHundred,\n\n\t/**\n\t * Next Object Request URL encoded\n\t */\n\tnor,\n\n\t/**\n\t * Requested maximum throughput (kbps) rounded nearest 100kbps\n\t */\n\trtp: toHundred,\n\n\t/**\n\t * Top Bitrate (kbps) rounded integer\n\t */\n\ttb: toRounded,\n} as const\n","/**\n * CMCD Version 2\n *\n * @public\n */\nexport const CMCD_V2 = 2 as const\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * CMCD event type for the 'bc' key (bitrate change).\n *\n * @public\n */\nexport const CMCD_EVENT_BITRATE_CHANGE = 'bc' as const\n\n/**\n * CMCD event type for the 'ps' key (play state change).\n *\n * @public\n */\nexport const CMCD_EVENT_PLAY_STATE = 'ps' as const\n\n/**\n * CMCD event type for the 'pr' key (playback rate change).\n *\n * @public\n */\nexport const CMCD_EVENT_PLAYBACK_RATE = 'pr' as const\n\n/**\n * CMCD event type for the 'e' key (error).\n *\n * @public\n */\nexport const CMCD_EVENT_ERROR = 'e' as const\n\n/**\n * CMCD event type for the 't' key (time interval).\n *\n * @public\n */\nexport const CMCD_EVENT_TIME_INTERVAL = 't' as const\n\n/**\n * CMCD event type for the 'c' key (content ID).\n *\n * @public\n */\nexport const CMCD_EVENT_CONTENT_ID = 'c' as const\n\n/**\n * CMCD event type for the 'b' key (backgrounded mode).\n *\n * @public\n */\nexport const CMCD_EVENT_BACKGROUNDED_MODE = 'b' as const\n\n/**\n * CMCD event type for the 'm' key (mute).\n *\n * @public\n */\nexport const CMCD_EVENT_MUTE = 'm' as const\n\n/**\n * CMCD event type for the 'um' key (unmute).\n *\n * @public\n */\nexport const CMCD_EVENT_UNMUTE = 'um' as const\n\n/**\n * CMCD event type for the 'pe' key (player expand).\n *\n * @public\n */\nexport const CMCD_EVENT_PLAYER_EXPAND = 'pe' as const\n\n/**\n * CMCD event type for the 'pc' key (player collapse).\n *\n * @public\n */\nexport const CMCD_EVENT_PLAYER_COLLAPSE = 'pc' as const\n\n/**\n * CMCD event type for the 'rr' key (response received).\n *\n * @public\n */\nexport const CMCD_EVENT_RESPONSE_RECEIVED = 'rr' as const\n\n/**\n * CMCD event type for the 'as' key (ad start).\n *\n * @public\n */\nexport const CMCD_EVENT_AD_START = 'as' as const\n\n/**\n * CMCD event type for the 'ae' key (ad end).\n *\n * @public\n */\nexport const CMCD_EVENT_AD_END = 'ae' as const\n\n/**\n * CMCD event type for the 'abs' key (ad break start).\n *\n * @public\n */\nexport const CMCD_EVENT_AD_BREAK_START = 'abs' as const\n\n/**\n * CMCD event type for the 'abe' key (ad break end).\n *\n * @public\n */\nexport const CMCD_EVENT_AD_BREAK_END = 'abe' as const\n\n/**\n * CMCD event type for the 'sk' key (skip).\n *\n * @public\n */\nexport const CMCD_EVENT_SKIP = 'sk' as const\n\n/**\n * CMCD event type for the 'ce' key (custom event).\n *\n * @public\n */\nexport const CMCD_EVENT_CUSTOM_EVENT = 'ce' as const\n\n/**\n * CMCD event types for the 'e' key (event mode).\n *\n * @enum\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#event | CTA-5004-B Event}\n *\n * @public\n */\nexport const CmcdEventType = {\n\t/**\n\t * A change in the bitrate.\n\t */\n\tBITRATE_CHANGE: CMCD_EVENT_BITRATE_CHANGE as typeof CMCD_EVENT_BITRATE_CHANGE,\n\n\t/**\n\t * A change in the player state.\n\t */\n\tPLAY_STATE: CMCD_EVENT_PLAY_STATE as typeof CMCD_EVENT_PLAY_STATE,\n\n\t/**\n\t * A change in the playback rate.\n\t */\n\tPLAYBACK_RATE: CMCD_EVENT_PLAYBACK_RATE as typeof CMCD_EVENT_PLAYBACK_RATE,\n\n\t/**\n\t * An error event.\n\t */\n\tERROR: CMCD_EVENT_ERROR as typeof CMCD_EVENT_ERROR,\n\n\t/**\n\t * A periodic report sent on a time interval.\n\t */\n\tTIME_INTERVAL: CMCD_EVENT_TIME_INTERVAL as typeof CMCD_EVENT_TIME_INTERVAL,\n\n\t/**\n\t * A change of the content ID.\n\t */\n\tCONTENT_ID: CMCD_EVENT_CONTENT_ID as typeof CMCD_EVENT_CONTENT_ID,\n\n\t/**\n\t * A change in the application's backgrounded state.\n\t */\n\tBACKGROUNDED_MODE: CMCD_EVENT_BACKGROUNDED_MODE as typeof CMCD_EVENT_BACKGROUNDED_MODE,\n\n\t/**\n\t * The player was muted.\n\t */\n\tMUTE: CMCD_EVENT_MUTE as typeof CMCD_EVENT_MUTE,\n\n\t/**\n\t * Player unmuted.\n\t */\n\tUNMUTE: CMCD_EVENT_UNMUTE as typeof CMCD_EVENT_UNMUTE,\n\n\t/**\n\t * The player view was expanded.\n\t */\n\tPLAYER_EXPAND: CMCD_EVENT_PLAYER_EXPAND as typeof CMCD_EVENT_PLAYER_EXPAND,\n\n\t/**\n\t * The player view was collapsed.\n\t */\n\tPLAYER_COLLAPSE: CMCD_EVENT_PLAYER_COLLAPSE as typeof CMCD_EVENT_PLAYER_COLLAPSE,\n\n\t/**\n\t * The receipt of a response.\n\t */\n\tRESPONSE_RECEIVED: CMCD_EVENT_RESPONSE_RECEIVED as typeof CMCD_EVENT_RESPONSE_RECEIVED,\n\n\t/**\n\t * The start of an ad.\n\t */\n\tAD_START: CMCD_EVENT_AD_START as typeof CMCD_EVENT_AD_START,\n\n\t/**\n\t * The end of an ad.\n\t */\n\tAD_END: CMCD_EVENT_AD_END as typeof CMCD_EVENT_AD_END,\n\n\t/**\n\t * The start of an ad break.\n\t */\n\tAD_BREAK_START: CMCD_EVENT_AD_BREAK_START as typeof CMCD_EVENT_AD_BREAK_START,\n\n\t/**\n\t * The end of an ad break.\n\t */\n\tAD_BREAK_END: CMCD_EVENT_AD_BREAK_END as typeof CMCD_EVENT_AD_BREAK_END,\n\n\t/**\n\t * The user skipped an ad.\n\t */\n\tSKIP: CMCD_EVENT_SKIP as typeof CMCD_EVENT_SKIP,\n\n\t/**\n\t * A custom event.\n\t */\n\tCUSTOM_EVENT: CMCD_EVENT_CUSTOM_EVENT as typeof CMCD_EVENT_CUSTOM_EVENT,\n} as const\n\n/**\n * @public\n */\nexport type CmcdEventType = ValueOf<typeof CmcdEventType>;\n","import {\n\tCMCD_EVENT_BACKGROUNDED_MODE,\n\tCMCD_EVENT_BITRATE_CHANGE,\n\tCMCD_EVENT_CONTENT_ID,\n\tCMCD_EVENT_PLAY_STATE,\n\tCMCD_EVENT_PLAYBACK_RATE,\n\ttype CmcdEventType,\n} from './CmcdEventType.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\n\n/**\n * Maps each state-change event type to the persistent field whose value\n * the event signals.\n *\n * Per CTA-5004-B, the state-change events `ps`, `pr`, `c`, `b`, `bc` are\n * state-transition markers and must carry the field whose value they signal.\n * Consumers force-include the field post-filter (`prepareCmcdData`), dedup\n * against its value (`CmcdReporter`), and check its presence in payloads\n * (`validateCmcdStructure`).\n *\n * Iteration order is load-bearing: `CmcdReporter.update()` fires state-change\n * events in map order when multiple tracked fields change in a single call.\n * Do not reorder entries without auditing reporter behavior.\n *\n * @internal\n */\nexport const CMCD_STATE_EVENT_FIELDS: ReadonlyMap<CmcdEventType, CmcdKey> = /* @__PURE__ */ new Map([\n\t[CMCD_EVENT_PLAY_STATE, 'sta'],\n\t[CMCD_EVENT_PLAYBACK_RATE, 'pr'],\n\t[CMCD_EVENT_CONTENT_ID, 'cid'],\n\t[CMCD_EVENT_BACKGROUNDED_MODE, 'bg'],\n\t[CMCD_EVENT_BITRATE_CHANGE, 'br'],\n])\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * CMCD event mode variable name.\n *\n * @public\n */\nexport const CMCD_EVENT_MODE = 'event' as const\n\n/**\n * CMCD request mode variable name.\n *\n * @public\n */\nexport const CMCD_REQUEST_MODE = 'request' as const\n\n/**\n * CMCD reporting mode types.\n *\n * @enum\n *\n * @public\n */\nexport const CmcdReportingMode = {\n\t/**\n\t * Request mode\n\t */\n\tREQUEST: CMCD_REQUEST_MODE as typeof CMCD_REQUEST_MODE,\n\n\t/**\n\t * Event mode\n\t */\n\tEVENT: CMCD_EVENT_MODE as typeof CMCD_EVENT_MODE,\n} as const\n\n/**\n * @public\n */\nexport type CmcdReportingMode = ValueOf<typeof CmcdReportingMode>;\n","/**\n * Defines the event-specific keys for CMCD (Common Media Client Data) version 2.\n *\n * @public\n */\nexport const CMCD_EVENT_KEYS = [\n\t'cen',\n\t'e',\n\t'h',\n\t'ts',\n] as const\n","/**\n * Defines the request-specific keys for CMCD (Common Media Client Data) version 2.\n *\n * @public\n */\nexport const CMCD_REQUEST_KEYS = [\n\t'ab',\n\t'bg',\n\t'bl',\n\t'br',\n\t'bs',\n\t'bsa',\n\t'bsd',\n\t'bsda',\n\t'cdn',\n\t'cid',\n\t'cs',\n\t'd',\n\t'dfa',\n\t'dl',\n\t'ec',\n\t'lab',\n\t'lb',\n\t'ltc',\n\t'msd',\n\t'mtp',\n\t'nor',\n\t'nr',\n\t'ot',\n\t'pb',\n\t'pr',\n\t'pt',\n\t'rtp',\n\t'sf',\n\t'sid',\n\t'sn',\n\t'st',\n\t'sta',\n\t'su',\n\t'tab',\n\t'tb',\n\t'tbl',\n\t'tpb',\n\t'v',\n] as const\n","import type { CmcdKey } from './CmcdKey.ts'\n\n// The CMCD custom-key charset restricted to RFC 8941 key serialization\n// (serializeKey): a lowercase first letter, then `a-z 0-9 . -`.\nconst CUSTOM_KEY_REGEX = /^[a-z][a-z0-9.-]*$/\n\n/**\n * Check if a key is a valid custom key: a lowercase first letter, then\n * characters from `a-z 0-9 . -`, with a hyphen that is neither the first\n * nor the last character. These are the CTA-5004-B custom-key rules\n * restricted to names that survive RFC 8941 key serialization.\n *\n * @param key - The key to check.\n *\n * @returns `true` if the key is a custom key, `false` otherwise.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/isCmcdCustomKey.test.ts#example}\n */\nexport function isCmcdCustomKey(key: CmcdKey): boolean {\n\t// The separator is checked outside the regex to keep matching linear (CodeQL js/polynomial-redos).\n\tconst separator = key.indexOf('-', 1)\n\treturn separator > 0 && separator < key.length - 1 && CUSTOM_KEY_REGEX.test(key)\n}\n","import { CMCD_REQUEST_KEYS } from './CMCD_REQUEST_KEYS.ts'\nimport type { Cmcd } from './Cmcd.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\nimport { isCmcdCustomKey } from './isCmcdCustomKey.ts'\n\nconst CMCD_REQUEST_KEY_SET: ReadonlySet<string> = /* @__PURE__ */ new Set(CMCD_REQUEST_KEYS)\n\n/**\n * Check if a key is a valid CMCD request key.\n *\n * @param key - The key to check.\n *\n * @returns `true` if the key is a valid CMCD request key, `false` otherwise.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/isCmcdRequestKey.test.ts#example}\n */\nexport function isCmcdRequestKey(key: string): key is keyof Cmcd {\n\treturn CMCD_REQUEST_KEY_SET.has(key) ||\n\t\tisCmcdCustomKey(key as CmcdKey)\n}\n","/**\n * CMCD v2 - Response-only and timing keys.\n *\n * @public\n */\nexport const CMCD_RESPONSE_KEYS = [\n\t'cmsdd',\n\t'cmsds',\n\t'rc',\n\t'smrt',\n\t'ttfb',\n\t'ttfbb',\n\t'ttlb',\n\t'url',\n] as const\n","import { CMCD_RESPONSE_KEYS } from './CMCD_RESPONSE_KEYS.ts'\nimport type { Cmcd } from './Cmcd.ts'\n\nconst CMCD_RESPONSE_KEY_SET: ReadonlySet<string> = /* @__PURE__ */ new Set(CMCD_RESPONSE_KEYS)\n\n/**\n * Check if a key is a valid CMCD response key.\n *\n * @param key - The key to check.\n *\n * @returns `true` if the key is a valid CMCD request key, `false` otherwise.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/isCmcdResponseReceivedKey.test.ts#example}\n */\nexport function isCmcdResponseReceivedKey(key: string): key is keyof Cmcd {\n\treturn CMCD_RESPONSE_KEY_SET.has(key)\n}\n","import { CMCD_EVENT_KEYS } from './CMCD_EVENT_KEYS.ts'\nimport type { Cmcd } from './Cmcd.ts'\nimport { isCmcdRequestKey } from './isCmcdRequestKey.ts'\nimport { isCmcdResponseReceivedKey } from './isCmcdResponseReceivedKey.ts'\n\nconst CMCD_EVENT_KEY_SET: ReadonlySet<string> = /* @__PURE__ */ new Set(CMCD_EVENT_KEYS)\n\n/**\n * Check if a key is a valid CMCD event key.\n *\n * @param key - The key to check.\n *\n * @returns `true` if the key is a valid CMCD event key, `false` otherwise.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/isCmcdEventKey.test.ts#example}\n */\nexport function isCmcdEventKey(key: string): key is keyof Cmcd {\n\treturn isCmcdRequestKey(key) ||\n\t\tisCmcdResponseReceivedKey(key) ||\n\t\tCMCD_EVENT_KEY_SET.has(key)\n}\n","/**\n * Keys that are inner lists in V2 but plain scalars in V1.\n *\n * Used by both encoding (down-conversion) and decoding (up-conversion).\n *\n * @internal\n */\nexport const CMCD_INNER_LIST_KEYS: Set<string> = new Set<string>([\n\t'ab', 'bl', 'br', 'bsa', 'bsd', 'bsda', 'lab', 'lb', 'mtp', 'pb', 'tab', 'tb', 'tbl', 'tpb',\n])\n","/**\n * Defines the keys for CMCD (Common Media Client Data) version 1.\n *\n * @public\n */\nexport const CMCD_V1_KEYS = [\n\t'bl',\n\t'br',\n\t'bs',\n\t'cid',\n\t'd',\n\t'dl',\n\t'mtp',\n\t'nor',\n\t'nrr',\n\t'ot',\n\t'pr',\n\t'rtp',\n\t'sf',\n\t'sid',\n\t'st',\n\t'su',\n\t'tb',\n\t'v',\n] as const\n","import { CMCD_V1_KEYS } from './CMCD_V1_KEYS.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\nimport { isCmcdCustomKey } from './isCmcdCustomKey.ts'\n\nconst CMCD_V1_KEY_SET: ReadonlySet<string> = /* @__PURE__ */ new Set(CMCD_V1_KEYS)\n\n/**\n * Filter function for CMCD v1 keys.\n *\n * @param key - The CMCD key to filter.\n *\n * @returns `true` if the key should be included, `false` otherwise.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/isCmcdV1Key.test.ts#example}\n */\nexport function isCmcdV1Key(key: string): key is CmcdKey {\n\treturn CMCD_V1_KEY_SET.has(key) || isCmcdCustomKey(key as CmcdKey)\n}\n","const TOKEN_FIELDS = /* @__PURE__ */ new Set(['ot', 'sf', 'st', 'e', 'sta'])\n\n/**\n * Checks if the given key is a token field.\n *\n * @param key - The key to check.\n *\n * @returns `true` if the key is a token field.\n *\n * @internal\n */\nexport function isTokenField(key: string): boolean {\n\treturn TOKEN_FIELDS.has(key)\n}\n","/**\n * Checks if the given value is valid\n *\n * @param value - The value to check.\n *\n * @returns `true` if the key is a value is valid.\n *\n * @internal\n */\nexport function isValid(value: unknown): boolean {\n\tif (typeof value === 'number') {\n\t\treturn Number.isFinite(value)\n\t}\n\n\treturn value != null && value !== '' && value !== false\n}\n","import { SfItem, SfToken } from '@svta/cml-structured-field-values'\nimport { CMCD_FORMATTER_MAP } from './CMCD_FORMATTER_MAP.ts'\nimport { CMCD_V2 } from './CMCD_V2.ts'\nimport type { Cmcd } from './Cmcd.ts'\nimport type { CmcdEncodeOptions } from './CmcdEncodeOptions.ts'\nimport { CMCD_EVENT_BACKGROUNDED_MODE, CMCD_EVENT_CUSTOM_EVENT, CMCD_EVENT_ERROR, CMCD_EVENT_PLAYBACK_RATE, CMCD_EVENT_RESPONSE_RECEIVED } from './CmcdEventType.ts'\nimport { CMCD_STATE_EVENT_FIELDS } from './CMCD_STATE_EVENT_FIELDS.ts'\nimport type { CmcdFormatterOptions } from './CmcdFormatterOptions.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\nimport type { CmcdVersion } from './CmcdVersion.ts'\nimport type { CmcdObjectType } from './CmcdObjectType.ts'\nimport { CMCD_EVENT_MODE, CMCD_REQUEST_MODE } from './CmcdReportingMode.ts'\nimport type { CmcdValue } from './CmcdValue.ts'\nimport { isCmcdEventKey } from './isCmcdEventKey.ts'\nimport { isCmcdRequestKey } from './isCmcdRequestKey.ts'\nimport { isCmcdResponseReceivedKey } from './isCmcdResponseReceivedKey.ts'\nimport { CMCD_INNER_LIST_KEYS } from './CMCD_INNER_LIST_KEYS.ts'\nimport { isCmcdV1Key } from './isCmcdV1Key.ts'\nimport { isTokenField } from './isTokenField.ts'\nimport { isValid } from './isValid.ts'\n\nconst filterMap: Record<string, (key: string) => boolean> = {\n\t[CMCD_EVENT_MODE]: isCmcdEventKey,\n\t[CMCD_REQUEST_MODE]: isCmcdRequestKey,\n}\n\n/**\n * Unwrap an inner list or SfItem value to a plain scalar.\n */\nfunction unwrapValue(value: any, ot?: CmcdObjectType): any {\n\tif (Array.isArray(value)) {\n\t\tlet item: any\n\n\t\tif (ot) {\n\t\t\titem = value.find(item => item.params?.ot === ot)\n\t\t}\n\n\t\tif (!item) {\n\t\t\titem = value[0]\n\t\t}\n\n\t\treturn unwrapValue(item)\n\t}\n\n\tif (value instanceof SfItem) {\n\t\treturn value.value\n\t}\n\n\treturn value\n}\n\n/**\n * Down-convert V2 CMCD data to V1 format.\n *\n * - Extracts `nrr` from `nor` SfItem `r` parameter.\n * - Unwraps inner-list values to plain scalars.\n */\nfunction downConvertToV1(obj: Record<string, any>): Record<string, any> {\n\tconst result: Record<string, any> = {}\n\n\tfor (const [key, value] of Object.entries(obj)) {\n\t\tif (value == null) {\n\t\t\tresult[key] = value\n\t\t\tcontinue\n\t\t}\n\n\t\tif (key === 'nor') {\n\t\t\tconst items = Array.isArray(value) ? value : [value]\n\t\t\tconst first = items[0]\n\n\t\t\tif (first instanceof SfItem) {\n\t\t\t\tresult['nor'] = first.value\n\t\t\t\tif (first.params?.r) {\n\t\t\t\t\tresult['nrr'] = first.params.r\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tresult['nor'] = first\n\t\t\t}\n\t\t}\n\t\telse if (CMCD_INNER_LIST_KEYS.has(key)) {\n\t\t\tresult[key] = unwrapValue(value, obj['ot'])\n\t\t}\n\t\telse {\n\t\t\tresult[key] = value\n\t\t}\n\t}\n\n\treturn result\n}\n\n/**\n * Convert a generic object to CMCD data.\n *\n * @param obj - The CMCD object to process.\n * @param options - Options for encoding.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/prepareCmcdData.test.ts#example}\n */\nexport function prepareCmcdData(obj: Record<string, any>, options: CmcdEncodeOptions = {}): Cmcd {\n\tconst results: Cmcd = {}\n\n\tif (obj == null || typeof obj !== 'object') {\n\t\treturn results\n\t}\n\n\tconst version = options.version || (obj['v'] as CmcdVersion) || CMCD_V2\n\tconst reportingMode = options.reportingMode || CMCD_REQUEST_MODE\n\n\t// Down-convert V2 data to V1 format if needed\n\tconst data = version === 1 ? downConvertToV1(obj) : obj\n\n\tconst keyFilter = version === 1 ? isCmcdV1Key : filterMap[reportingMode]\n\n\t// Filter keys based on the version, reporting mode and options. Every key\n\t// passing a filter is RFC 8941 serializable: standard keys by definition,\n\t// custom keys because isCmcdCustomKey enforces the serializable charset.\n\tlet keys = Object.keys(data).filter(keyFilter) as CmcdKey[]\n\n\tif (data['e'] && data['e'] !== CMCD_EVENT_RESPONSE_RECEIVED) {\n\t\tkeys = keys.filter(key => !isCmcdResponseReceivedKey(key))\n\t}\n\n\tconst filter = options.filter\n\tif (typeof filter === 'function') {\n\t\tkeys = keys.filter(filter)\n\t}\n\n\t// Ensure all required event keys are present before sorting\n\tconst isEventMode = reportingMode === CMCD_EVENT_MODE\n\n\tif (isEventMode) {\n\t\tconst eventType = data['e']\n\n\t\tif (!keys.includes('e') && eventType != null) {\n\t\t\tkeys.push('e')\n\t\t}\n\n\t\tif (!keys.includes('ts')) {\n\t\t\tkeys.push('ts')\n\t\t}\n\n\t\tif (!keys.includes('cen') && data['cen'] != null && eventType === CMCD_EVENT_CUSTOM_EVENT) {\n\t\t\tkeys.push('cen')\n\t\t}\n\n\t\tif (!keys.includes('ec') && data['ec'] != null && eventType === CMCD_EVENT_ERROR) {\n\t\t\tkeys.push('ec')\n\t\t}\n\n\t\tif (!keys.includes('url') && data['url'] != null && eventType === CMCD_EVENT_RESPONSE_RECEIVED) {\n\t\t\tkeys.push('url')\n\t\t}\n\n\t\tconst requiredField = eventType ? CMCD_STATE_EVENT_FIELDS.get(eventType) : undefined\n\t\tif (requiredField && data[requiredField] != null && !keys.includes(requiredField)) {\n\t\t\tkeys.push(requiredField)\n\t\t}\n\t}\n\n\tif (keys.length === 0) {\n\t\treturn results\n\t}\n\n\tif (version > 1 && !keys.includes('v')) {\n\t\tkeys.push('v')\n\t}\n\n\tconst formatterOptions: CmcdFormatterOptions = {\n\t\tversion,\n\t\treportingMode,\n\t\tbaseUrl: options.baseUrl,\n\t}\n\n\tkeys.sort()\n\n\tfor (const key of keys) {\n\t\tlet value = data[key] as CmcdValue\n\n\t\tconst formatter = options.formatters?.[key] ?? CMCD_FORMATTER_MAP[key]\n\t\tif (typeof formatter === 'function') {\n\t\t\tvalue = formatter(value, formatterOptions)\n\t\t}\n\n\t\t// Version should only be reported if not equal to 1.\n\t\tif (key === 'v') {\n\t\t\tif (version === 1) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\telse {\n\t\t\t\tvalue = version\n\t\t\t}\n\t\t}\n\n\t\t// Playback rate should only be sent if not equal to 1, except as\n\t\t// the value of a PLAYBACK_RATE state-change event (where pr=1 is\n\t\t// the data being reported, not a default to skip).\n\t\tif (key === 'pr' && value === 1 && !(isEventMode && data['e'] === CMCD_EVENT_PLAYBACK_RATE)) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Ensure a timestamp is set for event mode\n\t\tif (isEventMode && key === 'ts' && !Number.isFinite(value)) {\n\t\t\tvalue = Date.now()\n\t\t}\n\n\t\t// Ignore invalid values, except `bg: false` on a backgrounded-mode (e=b) state-\n\t\t// change event — the wire must carry `?0` per CTA-5004-B so the transition is\n\t\t// reportable. `bg` is the only state-change required field typed as boolean;\n\t\t// `false` on other required fields (e.g. `cid`, `sta`) is a caller bug and stays\n\t\t// stripped so the validator flags it.\n\t\tconst isBgFalseTransition = isEventMode\n\t\t\t&& value === false\n\t\t\t&& key === 'bg'\n\t\t\t&& data['e'] === CMCD_EVENT_BACKGROUNDED_MODE\n\t\tif (!isValid(value) && !isBgFalseTransition) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif (isTokenField(key) && typeof value === 'string') {\n\t\t\tvalue = new SfToken(value)\n\t\t}\n\n\t\t(results as any)[key] = value\n\t}\n\n\treturn results\n}\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * CMCD object header name.\n *\n * @public\n */\nexport const CMCD_OBJECT = 'CMCD-Object' as const\n\n/**\n * CMCD request header name.\n *\n * @public\n */\nexport const CMCD_REQUEST = 'CMCD-Request' as const\n\n/**\n * CMCD session header name.\n *\n * @public\n */\nexport const CMCD_SESSION = 'CMCD-Session' as const\n\n/**\n * CMCD status header name.\n *\n * @public\n */\nexport const CMCD_STATUS = 'CMCD-Status' as const\n\n/**\n * CMCD header fields.\n *\n *\n * @enum\n *\n * @public\n */\nexport const CmcdHeaderField = {\n\t/**\n\t * keys whose values vary with the object being requested.\n\t */\n\tOBJECT: CMCD_OBJECT as typeof CMCD_OBJECT,\n\n\t/**\n\t * keys whose values vary with each request.\n\t */\n\tREQUEST: CMCD_REQUEST as typeof CMCD_REQUEST,\n\n\t/**\n\t * keys whose values are expected to be invariant over the life of the session.\n\t */\n\tSESSION: CMCD_SESSION as typeof CMCD_SESSION,\n\n\t/**\n\t * keys whose values do not vary with every request or object.\n\t */\n\tSTATUS: CMCD_STATUS as typeof CMCD_STATUS,\n} as const\n\n/**\n * @public\n */\nexport type CmcdHeaderField = ValueOf<typeof CmcdHeaderField>;\n\n/**\n * All CMCD header fields as an array.\n *\n * @public\n */\nexport const CMCD_HEADER_FIELDS: readonly CmcdHeaderField[] = [CMCD_OBJECT, CMCD_REQUEST, CMCD_SESSION, CMCD_STATUS]\n","import { type CmcdHeaderField, CMCD_OBJECT, CMCD_REQUEST, CMCD_SESSION, CMCD_STATUS } from './CmcdHeaderField.ts'\nimport type { CmcdRequestKey } from './CmcdRequestKey.ts'\n\n/**\n * The map of CMCD keys to their appropriate header shard.\n *\n * Note: Event-only keys (e, ts, cen, h) and response-received keys\n * (rc, ttfb, ttlb, url, etc.) are intentionally absent. They are\n * transmitted via the event-mode POST body, not HTTP headers.\n *\n * @public\n */\nexport const CMCD_HEADER_MAP: Record<CmcdRequestKey | 'nrr', CmcdHeaderField> = {\n\t// Object\n\tab: CMCD_OBJECT,\n\tbr: CMCD_OBJECT,\n\td: CMCD_OBJECT,\n\tlab: CMCD_OBJECT,\n\tlb: CMCD_OBJECT,\n\tot: CMCD_OBJECT,\n\ttab: CMCD_OBJECT,\n\ttb: CMCD_OBJECT,\n\ttpb: CMCD_OBJECT,\n\n\t// Request\n\tbl: CMCD_REQUEST,\n\tcs: CMCD_REQUEST,\n\tdfa: CMCD_REQUEST,\n\tdl: CMCD_REQUEST,\n\tltc: CMCD_REQUEST,\n\tmtp: CMCD_REQUEST,\n\tnor: CMCD_REQUEST,\n\tnrr: CMCD_REQUEST,\n\tpb: CMCD_REQUEST,\n\tsn: CMCD_REQUEST,\n\tsta: CMCD_REQUEST,\n\tsu: CMCD_REQUEST,\n\ttbl: CMCD_REQUEST,\n\n\t// Session\n\tcid: CMCD_SESSION,\n\tmsd: CMCD_SESSION,\n\tsf: CMCD_SESSION,\n\tsid: CMCD_SESSION,\n\tst: CMCD_SESSION,\n\tv: CMCD_SESSION,\n\n\t// Status\n\tbg: CMCD_STATUS,\n\tbs: CMCD_STATUS,\n\tbsa: CMCD_STATUS,\n\tbsd: CMCD_STATUS,\n\tbsda: CMCD_STATUS,\n\tcdn: CMCD_STATUS,\n\tec: CMCD_STATUS,\n\tnr: CMCD_STATUS,\n\tpr: CMCD_STATUS,\n\tpt: CMCD_STATUS,\n\trtp: CMCD_STATUS,\n}\n","import type { Cmcd } from './Cmcd.ts'\nimport { CMCD_HEADER_MAP } from './CMCD_HEADER_MAP.ts'\nimport { CmcdHeaderField } from './CmcdHeaderField.ts'\nimport type { CmcdHeaderKey } from './CmcdHeaderKey.ts'\nimport type { CmcdHeaderMap } from './CmcdHeaderMap.ts'\nimport type { CmcdHeaderValue } from './CmcdHeaderValue.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\n\nfunction createHeaderMap(headerMap: Partial<CmcdHeaderMap>): Record<CmcdHeaderKey, CmcdHeaderField> {\n\treturn Object.keys(headerMap)\n\t\t.reduce((acc, field) => {\n\t\t\theaderMap[field as CmcdHeaderField]?.forEach(key => acc[key] = field as CmcdHeaderField)\n\t\t\treturn acc\n\t\t}, {} as Record<CmcdKey, CmcdHeaderField>)\n}\n\n/**\n * Group a CMCD data object into header shards\n *\n * @param cmcd - The CMCD data object to convert.\n * @param customHeaderMap - A map of CMCD header fields to custom CMCD keys.\n *\n * @returns The CMCD header shards.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#header-field-definition | CTA-5004-B Header Field Definition}\n *\n * @public\n */\nexport function groupCmcdHeaders(cmcd: Cmcd, customHeaderMap?: Partial<CmcdHeaderMap>): Record<CmcdHeaderField, CmcdHeaderValue> {\n\tconst result = {} as Record<CmcdHeaderField, CmcdHeaderValue>\n\n\tif (!cmcd) {\n\t\treturn result\n\t}\n\n\tconst keys = Object.keys(cmcd) as CmcdHeaderKey[]\n\tconst custom: Partial<Record<CmcdHeaderKey, CmcdHeaderField>> = customHeaderMap ? createHeaderMap(customHeaderMap) : {}\n\n\tfor (const key of keys) {\n\t\tconst field = CMCD_HEADER_MAP[key] || custom[key] || CmcdHeaderField.REQUEST\n\t\tconst data = result[field] ??= {};\n\t\t(data as Record<string, unknown>)[key] = (cmcd as Record<string, unknown>)[key]\n\t}\n\n\treturn result\n}\n","import { encodeSfDict } from '@svta/cml-structured-field-values'\nimport type { Cmcd } from './Cmcd.ts'\nimport type { CmcdHeaderField } from './CmcdHeaderField.ts'\nimport type { CmcdHeaderMap } from './CmcdHeaderMap.ts'\nimport type { CmcdHeaderValue } from './CmcdHeaderValue.ts'\nimport { groupCmcdHeaders } from './groupCmcdHeaders.ts'\n\n/**\n * Encode already-prepared CMCD data to CMCD header shards.\n *\n * @param data - The prepared CMCD data to encode.\n * @param customHeaderMap - A map of CMCD header fields to custom CMCD keys.\n * @returns The CMCD header shards.\n *\n * @internal\n */\nexport function toPreparedCmcdHeaders(data: Cmcd, customHeaderMap?: Partial<CmcdHeaderMap>): Record<CmcdHeaderField, string> {\n\tconst result = {} as Record<CmcdHeaderField, string>\n\tconst shards = groupCmcdHeaders(data, customHeaderMap)\n\n\tfor (const [field, value] of Object.entries(shards)) {\n\t\tconst shard = encodeSfDict(value as CmcdHeaderValue, { whitespace: false })\n\t\tif (shard) {\n\t\t\tresult[field as CmcdHeaderField] = shard\n\t\t}\n\t}\n\n\treturn result\n}\n","import type { Cmcd } from './Cmcd.ts'\nimport type { CmcdEncodeOptions } from './CmcdEncodeOptions.ts'\nimport type { CmcdHeaderField } from './CmcdHeaderField.ts'\nimport { prepareCmcdData } from './prepareCmcdData.ts'\nimport { toPreparedCmcdHeaders } from './toPreparedCmcdHeaders.ts'\n\n/**\n * Convert a CMCD data object to request headers\n *\n * @param cmcd - The CMCD data object to convert.\n * @param options - Options for encoding the CMCD object.\n *\n * @returns The CMCD header shards.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#header-field-definition | CTA-5004-B Header Field Definition}\n *\n * @public\n *\n * @example\n * {@includeCode ../test/toCmcdHeaders.test.ts#example}\n */\nexport function toCmcdHeaders(cmcd: Cmcd, options: CmcdEncodeOptions = {}): Record<CmcdHeaderField, string> {\n\tif (!cmcd) {\n\t\treturn {} as Record<CmcdHeaderField, string>\n\t}\n\n\treturn toPreparedCmcdHeaders(prepareCmcdData(cmcd, options), options?.customHeaderMap)\n}\n","import type { Cmcd } from './Cmcd.ts'\nimport type { CmcdEncodeOptions } from './CmcdEncodeOptions.ts'\nimport { toCmcdHeaders } from './toCmcdHeaders.ts'\n\n/**\n * Append CMCD query args to a header object.\n *\n * @param headers - The headers to append to.\n * @param cmcd - The CMCD object to append.\n * @param options - Encode options.\n *\n * @returns The headers with the CMCD header shards appended.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/appendCmcdHeaders.test.ts#example}\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#header-field-definition | CTA-5004-B Header Field Definition}\n */\nexport function appendCmcdHeaders(headers: Record<string, string>, cmcd: Cmcd, options?: CmcdEncodeOptions): Record<string, string> {\n\treturn Object.assign(headers, toCmcdHeaders(cmcd, options))\n}\n","/**\n * CMCD parameter name.\n *\n * @public\n */\nexport const CMCD_PARAM = 'CMCD'\n","import { encodeSfDict } from '@svta/cml-structured-field-values'\nimport type { Cmcd } from './Cmcd.ts'\n\n/**\n * Encode already-prepared CMCD data to a structured field dictionary string.\n *\n * @param data - The prepared CMCD data to encode.\n * @returns The encoded CMCD string.\n *\n * @internal\n */\nexport function encodePreparedCmcd(data: Cmcd): string {\n\treturn encodeSfDict(data, { whitespace: false })\n}\n","import type { Cmcd } from './Cmcd.ts'\nimport type { CmcdEncodeOptions } from './CmcdEncodeOptions.ts'\nimport { encodePreparedCmcd } from './encodePreparedCmcd.ts'\nimport { prepareCmcdData } from './prepareCmcdData.ts'\n\n/**\n * Encode a CMCD object to a string.\n *\n * @param cmcd - The CMCD object to encode.\n * @param options - Options for encoding.\n *\n * @returns The encoded CMCD string.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#payload-definition-for-headers-and-query-argument-transmission | CTA-5004-B Payload Definition}\n *\n * @public\n *\n * @example\n * {@includeCode ../test/encodeCmcd.test.ts#example}\n */\nexport function encodeCmcd(cmcd: Cmcd, options: CmcdEncodeOptions = {}): string {\n\tif (!cmcd) {\n\t\treturn ''\n\t}\n\n\treturn encodePreparedCmcd(prepareCmcdData(cmcd, options))\n}\n","import type { Cmcd } from './Cmcd.ts'\nimport type { CmcdEncodeOptions } from './CmcdEncodeOptions.ts'\nimport { encodeCmcd } from './encodeCmcd.ts'\n\n/**\n * Convert a CMCD data object to a URL encoded string.\n *\n * @param cmcd - The CMCD object to convert.\n * @param options - Options for encoding the CMCD object.\n *\n * @returns The URL encoded CMCD data.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#query-argument-definition | CTA-5004-B Query Argument Definition}\n *\n * @public\n */\nexport function toCmcdUrl(cmcd: Cmcd, options: CmcdEncodeOptions = {}): string {\n\tif (!cmcd) {\n\t\treturn ''\n\t}\n\n\tconst params = encodeCmcd(cmcd, options)\n\n\treturn encodeURIComponent(params)\n}\n","import { CMCD_PARAM } from './CMCD_PARAM.ts'\nimport type { Cmcd } from './Cmcd.ts'\nimport type { CmcdEncodeOptions } from './CmcdEncodeOptions.ts'\nimport { toCmcdUrl } from './toCmcdUrl.ts'\n\n/**\n * Convert a CMCD data object to a query arg.\n *\n * @param cmcd - The CMCD object to convert.\n * @param options - Options for encoding the CMCD object.\n *\n * @returns The CMCD query arg.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#query-argument-definition | CTA-5004-B Query Argument Definition}\n *\n * @public\n *\n * @example\n * {@includeCode ../test/toCmcdQuery.test.ts#example}\n */\nexport function toCmcdQuery(cmcd: Cmcd, options: CmcdEncodeOptions = {}): string {\n\tif (!cmcd) {\n\t\treturn ''\n\t}\n\n\tconst value = toCmcdUrl(cmcd, options)\n\n\treturn `${CMCD_PARAM}=${value}`\n}\n","import type { Cmcd } from './Cmcd.ts'\nimport type { CmcdEncodeOptions } from './CmcdEncodeOptions.ts'\nimport { toCmcdQuery } from './toCmcdQuery.ts'\n\nconst REGEX = /CMCD=[^&#]+/\n\n/**\n * Append CMCD query args to a URL.\n *\n * @param url - The URL to append to.\n * @param cmcd - The CMCD object to append.\n * @param options - Options for encoding the CMCD object.\n *\n * @returns The URL with the CMCD query args appended.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/appendCmcdQuery.test.ts#example}\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#query-argument-definition | CTA-5004-B Query Argument Definition}\n */\nexport function appendCmcdQuery(url: string, cmcd: Cmcd, options?: CmcdEncodeOptions): string {\n\tconst query = toCmcdQuery(cmcd, options)\n\tif (!query) {\n\t\treturn url\n\t}\n\n\tif (REGEX.test(url)) {\n\t\treturn url.replace(REGEX, query)\n\t}\n\n\tconst separator = url.includes('?') ? '&' : '?'\n\treturn `${url}${separator}${query}`\n}\n","/**\n * The default time interval in seconds when using using event mode\n *\n * @public\n */\nexport const CMCD_DEFAULT_TIME_INTERVAL = 30\n","import { CMCD_EVENT_KEYS } from './CMCD_EVENT_KEYS.ts'\nimport { CMCD_REQUEST_KEYS } from './CMCD_REQUEST_KEYS.ts'\nimport { CMCD_RESPONSE_KEYS } from './CMCD_RESPONSE_KEYS.ts'\nimport { CMCD_V1_KEYS } from './CMCD_V1_KEYS.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\n\n/**\n * A list of all CMCD keys.\n *\n * @public\n */\nexport const CMCD_KEYS: CmcdKey[] = /* @__PURE__ */ [\n\t...CMCD_V1_KEYS,\n\t...CMCD_REQUEST_KEYS,\n\t...CMCD_RESPONSE_KEYS,\n\t...CMCD_EVENT_KEYS,\n].filter((key, index, arr) => arr.indexOf(key) === index)\n","/**\n * CMCD MIME type for event report payloads.\n *\n * @public\n */\nexport const CMCD_MIME_TYPE = 'application/cmcd'\n","/**\n * CMCD Version 1\n *\n * @public\n */\nexport const CMCD_V1 = 1 as const\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * Common Media Client Data Object Type\n *\n * @public\n *\n * @enum\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#object-type | CTA-5004-B Object Type}\n */\nexport const CmcdObjectType = {\n\t/**\n\t * text file, such as a manifest or playlist\n\t */\n\tMANIFEST: 'm',\n\n\t/**\n\t * audio only\n\t */\n\tAUDIO: 'a',\n\n\t/**\n\t * video only\n\t */\n\tVIDEO: 'v',\n\n\t/**\n\t * muxed audio and video\n\t */\n\tMUXED: 'av',\n\n\t/**\n\t * init segment\n\t */\n\tINIT: 'i',\n\n\t/**\n\t * caption or subtitle\n\t */\n\tCAPTION: 'c',\n\n\t/**\n\t * ISOBMFF timed text track\n\t */\n\tTIMED_TEXT: 'tt',\n\n\t/**\n\t * cryptographic key, license or certificate.\n\t */\n\tKEY: 'k',\n\n\t/**\n\t * other\n\t */\n\tOTHER: 'o',\n} as const\n\n/**\n * @public\n */\nexport type CmcdObjectType = ValueOf<typeof CmcdObjectType>;\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * CMCD v2 player states for the 'sta' key.\n *\n *\n * @enum\n *\n * @public\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#state | CTA-5004-B State}\n */\nexport const CmcdPlayerState = {\n\t/**\n\t * Starting: Initial startup of the player.\n\t */\n\tSTARTING: 's',\n\n\t/**\n\t * Playing: The player is actively rendering content.\n\t */\n\tPLAYING: 'p',\n\n\t/**\n\t * Seeking: The player is seeking to a new position.\n\t */\n\tSEEKING: 'k',\n\n\t/**\n\t * Rebuffering: The player is buffering data during playback.\n\t */\n\tREBUFFERING: 'r',\n\n\t/**\n\t * Paused: The player is paused.\n\t */\n\tPAUSED: 'a',\n\n\t/**\n\t * Waiting: The player is waiting for a user action or another event.\n\t */\n\tWAITING: 'w',\n\n\t/**\n\t * Ended: The media has finished playing.\n\t */\n\tENDED: 'e',\n\n\t/**\n\t * Fatal Error: The player has encountered a fatal error.\n\t */\n\tFATAL_ERROR: 'f',\n\n\t/**\n\t * Quit: User initiated end of playback before media asset completion.\n\t */\n\tQUIT: 'q',\n\n\t/**\n\t * Preloading: The player is loading assets ahead of starting in order to provide a fast startup. The expectation is that playback will commence at a future time.\n\t */\n\tPRELOADING: 'd',\n} as const\n\n/**\n * @public\n */\nexport type CmcdPlayerState = ValueOf<typeof CmcdPlayerState>;\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * CMCD query reporting mode — CMCD data carried as a `CMCD=` URL\n * query parameter.\n *\n * @public\n */\nexport const CMCD_RECORDED_REPORT_MODE_QUERY = 'query' as const\n\n/**\n * CMCD header reporting mode — CMCD data carried as `Cmcd-*` HTTP\n * headers.\n *\n * @public\n */\nexport const CMCD_RECORDED_REPORT_MODE_HEADER = 'header' as const\n\n/**\n * CMCD event reporting mode — CMCD data carried as a POST body to an\n * event-target URL.\n *\n * @public\n */\nexport const CMCD_RECORDED_REPORT_MODE_EVENT = 'event' as const\n\n/**\n * Reporting mode under which a captured report was observed by\n * `CmcdReportRecorder`.\n *\n * @enum\n *\n * @public\n */\nexport const CmcdRecordedReportMode = {\n\tQUERY: CMCD_RECORDED_REPORT_MODE_QUERY as typeof CMCD_RECORDED_REPORT_MODE_QUERY,\n\tHEADER: CMCD_RECORDED_REPORT_MODE_HEADER as typeof CMCD_RECORDED_REPORT_MODE_HEADER,\n\tEVENT: CMCD_RECORDED_REPORT_MODE_EVENT as typeof CMCD_RECORDED_REPORT_MODE_EVENT,\n} as const\n\n/**\n * @public\n */\nexport type CmcdRecordedReportMode = ValueOf<typeof CmcdRecordedReportMode>\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * Manifest or playlist request classification.\n *\n * @public\n */\nexport const CMCD_RECORDED_REQUEST_TYPE_MANIFEST = 'manifest' as const\n\n/**\n * Media segment request classification.\n *\n * @public\n */\nexport const CMCD_RECORDED_REQUEST_TYPE_SEGMENT = 'segment' as const\n\n/**\n * CMCD event-mode report request classification (POST to a URL in\n * `eventTargetUrls`).\n *\n * @public\n */\nexport const CMCD_RECORDED_REQUEST_TYPE_EVENT = 'event' as const\n\n/**\n * Fallback classification for requests the recorder did not recognize\n * as manifest, segment, or event.\n *\n * @public\n */\nexport const CMCD_RECORDED_REQUEST_TYPE_UNKNOWN = 'unknown' as const\n\n/**\n * Classification of a captured request, used by `CmcdReportRecorder`\n * for filtering.\n *\n * @enum\n *\n * @public\n */\nexport const CmcdRecordedRequestType = {\n\tMANIFEST: CMCD_RECORDED_REQUEST_TYPE_MANIFEST as typeof CMCD_RECORDED_REQUEST_TYPE_MANIFEST,\n\tSEGMENT: CMCD_RECORDED_REQUEST_TYPE_SEGMENT as typeof CMCD_RECORDED_REQUEST_TYPE_SEGMENT,\n\tEVENT: CMCD_RECORDED_REQUEST_TYPE_EVENT as typeof CMCD_RECORDED_REQUEST_TYPE_EVENT,\n\tUNKNOWN: CMCD_RECORDED_REQUEST_TYPE_UNKNOWN as typeof CMCD_RECORDED_REQUEST_TYPE_UNKNOWN,\n} as const\n\n/**\n * @public\n */\nexport type CmcdRecordedRequestType = ValueOf<typeof CmcdRecordedRequestType>\n","import type { HttpRequest } from '@svta/cml-utils'\nimport type { CmcdRequestDeliver, CmcdTransportAdapter } from './CmcdTransportAdapter.ts'\n\nasync function toHttpRequest(request: Request): Promise<HttpRequest> {\n\tconst headers: Record<string, string> = {}\n\trequest.headers.forEach((value, name) => {\n\t\theaders[name.toLowerCase()] = value\n\t})\n\n\tlet body: string | undefined\n\tif (request.body) {\n\t\ttry {\n\t\t\tbody = await request.text()\n\t\t} catch {\n\t\t\tbody = undefined\n\t\t}\n\t}\n\n\treturn {\n\t\turl: request.url,\n\t\tmethod: request.method,\n\t\theaders,\n\t\tbody,\n\t}\n}\n\n/**\n * Create a transport adapter that patches `globalThis.fetch` to capture\n * CMCD-bearing requests, normalizing each to `HttpRequest` (lowercase\n * headers, body read as UTF-8 string). Returns the adapter object\n * expected by `CmcdReportRecorder`.\n *\n * Bodies are read once via `Request.text()` for inspection. This is\n * safe for the body types CMCD reports use in practice (`string`,\n * `Blob`, `ArrayBuffer`, `FormData`, `URLSearchParams`), which can be\n * read by the wrapper and re-read by the underlying `fetch`. Passing\n * a `ReadableStream` as `init.body` is not supported — the stream is\n * consumed by the wrapper and the underlying `fetch` will receive an\n * already-disturbed stream.\n *\n * @public\n */\nexport function createFetchTransport(): CmcdTransportAdapter {\n\treturn {\n\t\tattach(deliver: CmcdRequestDeliver): () => void {\n\t\t\tconst origFetch = globalThis.fetch\n\n\t\t\tglobalThis.fetch = async (\n\t\t\t\tinput: RequestInfo | URL,\n\t\t\t\tinit?: RequestInit,\n\t\t\t): Promise<Response> => {\n\t\t\t\tconst inspect = input instanceof Request\n\t\t\t\t\t? input.clone()\n\t\t\t\t\t: new Request(input, init)\n\t\t\t\tconst httpRequest = await toHttpRequest(inspect)\n\t\t\t\tconst synthetic = deliver(httpRequest)\n\t\t\t\tif (synthetic) {\n\t\t\t\t\treturn synthetic\n\t\t\t\t}\n\t\t\t\treturn origFetch.call(globalThis, input as RequestInfo, init)\n\t\t\t}\n\n\t\t\treturn () => {\n\t\t\t\tglobalThis.fetch = origFetch\n\t\t\t}\n\t\t},\n\t}\n}\n","import type { HttpRequest } from '@svta/cml-utils'\nimport type { CmcdRequestDeliver, CmcdTransportAdapter } from './CmcdTransportAdapter.ts'\n\ntype XhrInstance = XMLHttpRequest & {\n\t_cmcdMethod?: string;\n\t_cmcdUrl?: string;\n\t_cmcdHeaders?: Record<string, string>;\n}\n\nasync function completeXhrWith(xhr: XhrInstance, response: Response): Promise<void> {\n\tconst text = await response.clone().text().catch(() => '')\n\tconst ProgressEventCtor: typeof ProgressEvent | typeof Event =\n\t\ttypeof ProgressEvent !== 'undefined' ? ProgressEvent : Event\n\n\tqueueMicrotask(() => {\n\t\ttry {\n\t\t\tObject.defineProperty(xhr, 'status', { value: response.status, configurable: true })\n\t\t\tObject.defineProperty(xhr, 'statusText', { value: response.statusText, configurable: true })\n\t\t\tObject.defineProperty(xhr, 'readyState', { value: 4, configurable: true })\n\t\t\tObject.defineProperty(xhr, 'responseURL', { value: xhr._cmcdUrl ?? '', configurable: true })\n\t\t\tObject.defineProperty(xhr, 'response', { value: text, configurable: true })\n\t\t\tObject.defineProperty(xhr, 'responseText', { value: text, configurable: true })\n\n\t\t\tif (typeof xhr.onload === 'function') {\n\t\t\t\txhr.onload.call(xhr, new ProgressEventCtor('load') as ProgressEvent<EventTarget>)\n\t\t\t}\n\t\t\tif (typeof xhr.onloadend === 'function') {\n\t\t\t\txhr.onloadend.call(xhr, new ProgressEventCtor('loadend') as ProgressEvent<EventTarget>)\n\t\t\t}\n\t\t} catch {\n\t\t\t// MockXhr may not allow defineProperty on some properties;\n\t\t\t// for shim simplicity we set them directly as a fallback.\n\t\t\tconst target = xhr as unknown as Record<string, unknown>\n\t\t\ttarget['status'] = response.status\n\t\t\ttarget['statusText'] = response.statusText\n\t\t\ttarget['readyState'] = 4\n\t\t\ttarget['responseURL'] = xhr._cmcdUrl ?? ''\n\t\t\ttarget['response'] = text\n\t\t\ttarget['responseText'] = text\n\t\t\tif (typeof xhr.onload === 'function') {\n\t\t\t\txhr.onload.call(xhr as unknown as XMLHttpRequest, new ProgressEventCtor('load') as ProgressEvent<EventTarget>)\n\t\t\t}\n\t\t\tif (typeof xhr.onloadend === 'function') {\n\t\t\t\txhr.onloadend.call(xhr as unknown as XMLHttpRequest, new ProgressEventCtor('loadend') as ProgressEvent<EventTarget>)\n\t\t\t}\n\t\t}\n\t})\n}\n\n/**\n * Create a transport adapter that patches `XMLHttpRequest.prototype` to\n * capture CMCD-bearing requests. Returns the adapter object expected by\n * `CmcdReportRecorder`.\n *\n * @public\n */\nexport function createXhrTransport(): CmcdTransportAdapter {\n\treturn {\n\t\tattach(deliver: CmcdRequestDeliver): () => void {\n\t\t\tconst Xhr = globalThis.XMLHttpRequest\n\t\t\tif (!Xhr) {\n\t\t\t\treturn () => { /* no XHR to detach */ }\n\t\t\t}\n\t\t\tconst origOpen = Xhr.prototype.open\n\t\t\tconst origSetRequestHeader = Xhr.prototype.setRequestHeader\n\t\t\tconst origSend = Xhr.prototype.send\n\n\t\t\tXhr.prototype.open = function (this: XhrInstance, method: string, url: string | URL): void {\n\t\t\t\tthis._cmcdMethod = method\n\t\t\t\tthis._cmcdUrl = typeof url === 'string' ? url : url.toString()\n\t\t\t\tthis._cmcdHeaders = {}\n\t\t\t\t// eslint-disable-next-line prefer-rest-params\n\t\t\t\treturn origOpen.apply(this, arguments as unknown as Parameters<typeof origOpen>)\n\t\t\t}\n\n\t\t\tXhr.prototype.setRequestHeader = function (this: XhrInstance, name: string, value: string): void {\n\t\t\t\tif (this._cmcdHeaders) {\n\t\t\t\t\tthis._cmcdHeaders[name.toLowerCase()] = value\n\t\t\t\t}\n\t\t\t\treturn origSetRequestHeader.apply(this, [name, value])\n\t\t\t}\n\n\t\t\tXhr.prototype.send = function (this: XhrInstance, body?: Document | XMLHttpRequestBodyInit | null): void {\n\t\t\t\tconst httpRequest: HttpRequest = {\n\t\t\t\t\turl: this._cmcdUrl ?? '',\n\t\t\t\t\tmethod: (this._cmcdMethod ?? 'GET').toUpperCase(),\n\t\t\t\t\theaders: this._cmcdHeaders ?? {},\n\t\t\t\t\tbody: (typeof Document !== 'undefined' && body instanceof Document ? undefined : body as BodyInit | null | undefined) ?? undefined,\n\t\t\t\t}\n\n\t\t\t\tconst synthetic = deliver(httpRequest)\n\n\t\t\t\tif (synthetic) {\n\t\t\t\t\tcompleteXhrWith(this, synthetic)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\treturn origSend.apply(this, [body])\n\t\t\t}\n\n\t\t\treturn () => {\n\t\t\t\tXhr.prototype.open = origOpen\n\t\t\t\tXhr.prototype.setRequestHeader = origSetRequestHeader\n\t\t\t\tXhr.prototype.send = origSend\n\t\t\t}\n\t\t},\n\t}\n}\n","import type { HttpRequest } from '@svta/cml-utils'\nimport { CMCD_PARAM } from './CMCD_PARAM.ts'\nimport type { CmcdRecordedReport } from './CmcdRecordedReport.ts'\nimport type { CmcdRecordedReportMode } from './CmcdRecordedReportMode.ts'\nimport type { CmcdReportRecorderOptions } from './CmcdReportRecorderOptions.ts'\nimport type { CmcdReportRecorderWaitOptions } from './CmcdReportRecorderWaitOptions.ts'\nimport { CmcdRecordedRequestType } from './CmcdRecordedRequestType.ts'\nimport { createFetchTransport } from './createFetchTransport.ts'\nimport { createXhrTransport } from './createXhrTransport.ts'\n\nconst MANIFEST_EXTENSIONS = /\\.(m3u8|mpd)(\\?|$|\\/)/i\nconst SEGMENT_EXTENSIONS = /\\.(m4s|m4v|m4a|mp4|ts|aac)(\\?|$|\\/)/i\n\nfunction classifyUrl(url: string, isEventTarget: boolean): CmcdRecordedRequestType {\n\tif (isEventTarget) {\n\t\treturn CmcdRecordedRequestType.EVENT\n\t}\n\tif (MANIFEST_EXTENSIONS.test(url)) {\n\t\treturn CmcdRecordedRequestType.MANIFEST\n\t}\n\tif (SEGMENT_EXTENSIONS.test(url)) {\n\t\treturn CmcdRecordedRequestType.SEGMENT\n\t}\n\treturn CmcdRecordedRequestType.UNKNOWN\n}\n\nfunction hasCmcdHeader(headers: Record<string, string> | undefined): boolean {\n\tif (!headers) {\n\t\treturn false\n\t}\n\tfor (const name in headers) {\n\t\tif (name.toLowerCase().startsWith('cmcd-')) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunction detectReportingMode(\n\turl: string,\n\theaders: Record<string, string> | undefined,\n\tisEventTarget: boolean,\n): CmcdRecordedReportMode | null {\n\tif (isEventTarget) {\n\t\treturn 'event'\n\t}\n\tif (hasCmcdHeader(headers)) {\n\t\treturn 'header'\n\t}\n\treturn url.includes(`${CMCD_PARAM}=`) ? 'query' : null\n}\n\ntype CmcdReportWaiter = {\n\ttype: CmcdRecordedRequestType | undefined\n\tcount: number\n\tresolve: (r: CmcdRecordedReport[]) => void\n\treject: (e: Error) => void\n}\n\n/**\n * Test helper that records CMCD-bearing reports across XHR and fetch\n * transports for assertion in e2e tests. Each captured request is\n * normalized to {@link @svta/cml-utils!HttpRequest | HttpRequest} so\n * tests are identical regardless of which transport the player uses.\n *\n * @example\n * {@includeCode ../test/CmcdReportRecorder.test.ts#example}\n *\n * @public\n */\nexport class CmcdReportRecorder {\n\t#reports: CmcdRecordedReport[] = []\n\t#detachers: (() => void)[] = []\n\t#attached = false\n\t#eventTargetUrls: readonly string[] = []\n\t#waiters = new Map<ReturnType<typeof setTimeout>, CmcdReportWaiter>()\n\t#onReport: ((report: CmcdRecordedReport) => void) | undefined\n\t#waitTimeout = 15000\n\n\treadonly #deliver = (request: HttpRequest): Response | undefined => {\n\t\tconst url = request.url\n\t\tconst method = (request.method ?? 'GET').toUpperCase()\n\t\tconst isEventTarget = method === 'POST' && this.#eventTargetUrls.some((t) => url.startsWith(t))\n\n\t\tconst reportingMode = detectReportingMode(url, request.headers, isEventTarget)\n\t\tif (reportingMode === null) {\n\t\t\treturn undefined\n\t\t}\n\n\t\tconst captured: CmcdRecordedReport = {\n\t\t\trequest,\n\t\t\ttype: classifyUrl(url, isEventTarget),\n\t\t\treportingMode,\n\t\t\ttimestamp: Date.now(),\n\t\t}\n\t\tthis.#reports.push(captured)\n\t\tif (this.#onReport) {\n\t\t\ttry {\n\t\t\t\tthis.#onReport(captured)\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error('CmcdReportRecorder onReport listener threw:', err)\n\t\t\t}\n\t\t}\n\t\tthis.#notifyWaiters()\n\n\t\treturn isEventTarget ? new Response(null, { status: 204 }) : undefined\n\t}\n\n\t#getMatching(type: CmcdRecordedRequestType | undefined): CmcdRecordedReport[] {\n\t\treturn type === undefined\n\t\t\t? [...this.#reports]\n\t\t\t: this.#reports.filter((r) => r.type === type)\n\t}\n\n\t#notifyWaiters(): void {\n\t\tfor (const [timer, waiter] of this.#waiters) {\n\t\t\tconst matching = this.#getMatching(waiter.type)\n\t\t\tif (matching.length >= waiter.count) {\n\t\t\t\tclearTimeout(timer)\n\t\t\t\tthis.#waiters.delete(timer)\n\t\t\t\twaiter.resolve(matching)\n\t\t\t}\n\t\t}\n\t}\n\n\t#waitFor(\n\t\ttype: CmcdRecordedRequestType | undefined,\n\t\toptions: CmcdReportRecorderWaitOptions,\n\t): Promise<CmcdRecordedReport[]> {\n\t\tconst count = options.count ?? 1\n\t\tconst timeout = options.timeout ?? this.#waitTimeout\n\n\t\tconst matching = this.#getMatching(type)\n\t\tif (matching.length >= count) {\n\t\t\treturn Promise.resolve(matching)\n\t\t}\n\n\t\treturn new Promise<CmcdRecordedReport[]>((resolve, reject) => {\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tthis.#waiters.delete(timer)\n\t\t\t\tconst current = this.#getMatching(type)\n\t\t\t\treject(new Error(\n\t\t\t\t\t`Timeout waiting for ${count} ${type ?? 'any'} CMCD report(s). Got ${current.length}. Total recorded: ${this.#reports.length}.`,\n\t\t\t\t))\n\t\t\t}, timeout)\n\n\t\t\tthis.#waiters.set(timer, { type, count, resolve, reject })\n\t\t})\n\t}\n\n\t/**\n\t * Install transport patches and begin recording CMCD reports.\n\t * No-op if already attached — the previously supplied options are\n\t * retained and the new `options` argument is silently ignored.\n\t * Call `detach()` first if you need to re-attach with different\n\t * options.\n\t *\n\t * @public\n\t */\n\tattach(options: CmcdReportRecorderOptions = {}): void {\n\t\tif (this.#attached) {\n\t\t\treturn\n\t\t}\n\t\tthis.#attached = true\n\t\tthis.#eventTargetUrls = options.eventTargetUrls ?? []\n\t\tthis.#onReport = options.onReport\n\t\tthis.#waitTimeout = options.waitTimeout ?? 15000\n\n\t\tconst transports = options.transports ?? [createXhrTransport(), createFetchTransport()]\n\t\tfor (const transport of transports) {\n\t\t\tthis.#detachers.push(transport.attach(this.#deliver))\n\t\t}\n\t}\n\n\t/**\n\t * Remove transport patches and stop recording. Rejects any pending\n\t * wait promises with `Error('Recorder detached while waiting')`.\n\t *\n\t * @public\n\t */\n\tdetach(): void {\n\t\tif (!this.#attached) {\n\t\t\treturn\n\t\t}\n\t\tfor (const detacher of this.#detachers) {\n\t\t\tdetacher()\n\t\t}\n\t\tthis.#detachers = []\n\t\tthis.#attached = false\n\t\tthis.#eventTargetUrls = []\n\t\tthis.#onReport = undefined\n\n\t\tfor (const [timer, waiter] of this.#waiters) {\n\t\t\tclearTimeout(timer)\n\t\t\twaiter.reject(new Error('Recorder detached while waiting'))\n\t\t}\n\t\tthis.#waiters.clear()\n\t}\n\n\t/**\n\t * Discard all recorded reports. Does not affect the attached state.\n\t *\n\t * @public\n\t */\n\tclear(): void {\n\t\tthis.#reports = []\n\t}\n\n\t/**\n\t * Return a defensive copy of all recorded reports.\n\t *\n\t * @public\n\t */\n\tgetReports(): CmcdRecordedReport[] {\n\t\treturn [...this.#reports]\n\t}\n\n\t/**\n\t * Wait until at least `count` reports of any type are recorded.\n\t * Resolves with all matching reports; rejects with a diagnostic error\n\t * on timeout. `count` defaults to 1; `timeout` falls back to the\n\t * recorder's `waitTimeout` option (default 15000 ms).\n\t *\n\t * @public\n\t */\n\twaitForReports(options: CmcdReportRecorderWaitOptions = {}): Promise<CmcdRecordedReport[]> {\n\t\treturn this.#waitFor(undefined, options)\n\t}\n\n\t/**\n\t * Wait until at least `count` manifest reports are recorded.\n\t * Resolves with all matching reports; rejects with a diagnostic error\n\t * on timeout. `count` defaults to 1; `timeout` falls back to the\n\t * recorder's `waitTimeout` option (default 15000 ms).\n\t *\n\t * @public\n\t */\n\twaitForManifest(options: CmcdReportRecorderWaitOptions = {}): Promise<CmcdRecordedReport[]> {\n\t\treturn this.#waitFor(CmcdRecordedRequestType.MANIFEST, options)\n\t}\n\n\t/**\n\t * Wait until at least `count` segment reports are recorded.\n\t * Resolves with all matching reports; rejects with a diagnostic error\n\t * on timeout. `count` defaults to 1; `timeout` falls back to the\n\t * recorder's `waitTimeout` option (default 15000 ms).\n\t *\n\t * @public\n\t */\n\twaitForSegments(options: CmcdReportRecorderWaitOptions = {}): Promise<CmcdRecordedReport[]> {\n\t\treturn this.#waitFor(CmcdRecordedRequestType.SEGMENT, options)\n\t}\n\n\t/**\n\t * Wait until at least `count` event-mode reports are recorded.\n\t * Resolves with all matching reports; rejects with a diagnostic error\n\t * on timeout. `count` defaults to 1; `timeout` falls back to the\n\t * recorder's `waitTimeout` option (default 15000 ms).\n\t *\n\t * @public\n\t */\n\twaitForEvents(options: CmcdReportRecorderWaitOptions = {}): Promise<CmcdRecordedReport[]> {\n\t\treturn this.#waitFor(CmcdRecordedRequestType.EVENT, options)\n\t}\n}\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * CMCD `query` transmission mode.\n *\n * @public\n */\nexport const CMCD_QUERY = 'query' as const\n\n/**\n * CMCD `headers` transmission mode.\n *\n * @public\n */\nexport const CMCD_HEADERS = 'headers' as const\n\n/**\n * CMCD `json` transmission mode.\n *\n * @public\n *\n * @deprecated JSON transmission mode is deprecated and will be removed in future versions.\n */\nexport const CMCD_JSON = 'json' as const\n\n/**\n * CMCD transmission modes.\n *\n * @enum\n *\n * @public\n */\nexport const CmcdTransmissionMode = {\n\t/**\n\t * JSON\n\t *\n\t * @deprecated JSON transmission mode is deprecated and will be removed in future versions.\n\t */\n\tJSON: CMCD_JSON as typeof CMCD_JSON,\n\n\t/**\n\t * Query string\n\t */\n\tQUERY: CMCD_QUERY as typeof CMCD_QUERY,\n\n\t/**\n\t * Request headers\n\t */\n\tHEADERS: CMCD_HEADERS as typeof CMCD_HEADERS,\n\n} as const\n\n/**\n * @public\n */\nexport type CmcdTransmissionMode = ValueOf<typeof CmcdTransmissionMode>;\n","import type { HttpRequest, HttpResponse } from '@svta/cml-utils'\nimport { uuid } from '@svta/cml-utils'\nimport { CMCD_DEFAULT_TIME_INTERVAL } from './CMCD_DEFAULT_TIME_INTERVAL.ts'\nimport { CMCD_MIME_TYPE } from './CMCD_MIME_TYPE.ts'\nimport { CMCD_PARAM } from './CMCD_PARAM.ts'\nimport { CMCD_V2 } from './CMCD_V2.ts'\nimport type { Cmcd } from './Cmcd.ts'\nimport type { CmcdEncodeOptions } from './CmcdEncodeOptions.ts'\nimport type { CmcdEventReportConfig } from './CmcdEventReportConfig.ts'\nimport { CMCD_EVENT_CUSTOM_EVENT, CMCD_EVENT_ERROR, CMCD_EVENT_RESPONSE_RECEIVED, CMCD_EVENT_TIME_INTERVAL, CmcdEventType } from './CmcdEventType.ts'\nimport { CMCD_STATE_EVENT_FIELDS } from './CMCD_STATE_EVENT_FIELDS.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\nimport type { CmcdObjectTypeList } from './CmcdObjectTypeList.ts'\nimport type { CmcdReportConfig } from './CmcdReportConfig.ts'\nimport type { CmcdReporterConfig } from './CmcdReporterConfig.ts'\nimport type { CmcdReporterCustomData } from './CmcdReporterCustomData.ts'\nimport type { CmcdRequestReportConfig } from './CmcdRequestReportConfig.ts'\nimport type { CmcdReportingMode } from './CmcdReportingMode.ts'\nimport { CMCD_EVENT_MODE, CMCD_REQUEST_MODE } from './CmcdReportingMode.ts'\nimport type { CmcdRequestReport } from './CmcdRequestReport.ts'\nimport type { CmcdTransformRequest } from './CmcdTransformRequest.ts'\nimport { CMCD_HEADERS, CMCD_QUERY } from './CmcdTransmissionMode.ts'\nimport type { CmcdVersion } from './CmcdVersion.ts'\nimport { encodeCmcd } from './encodeCmcd.ts'\nimport { encodePreparedCmcd } from './encodePreparedCmcd.ts'\nimport { prepareCmcdData } from './prepareCmcdData.ts'\nimport { toPreparedCmcdHeaders } from './toPreparedCmcdHeaders.ts'\n\ntype CmcdReportConfigNormalized = CmcdReportConfig & {\n\tversion: CmcdVersion;\n}\n\ntype CmcdEventReportConfigNormalized<C> = CmcdEventReportConfig<C> & CmcdReportConfigNormalized & {\n\tevents: CmcdEventType[];\n\tinterval: number;\n\tbatchSize: number;\n}\n\ntype CmcdReporterConfigNormalized<C> = CmcdReporterConfig<C> & CmcdReportConfigNormalized & {\n\tsid: string;\n\teventTargets: CmcdEventReportConfigNormalized<C>[];\n}\n\nfunction createEncodingOptions(reportingMode: CmcdReportingMode, config: CmcdReportConfig & Pick<CmcdRequestReportConfig, 'customHeaderMap'>, baseUrl?: string): CmcdEncodeOptions {\n\tconst enabledKeySet = new Set(config.enabledKeys ?? [])\n\n\treturn {\n\t\tversion: config.version || CMCD_V2,\n\t\treportingMode,\n\t\tfilter: (key: CmcdKey) => enabledKeySet.has(key),\n\t\tbaseUrl,\n\t\tcustomHeaderMap: config.customHeaderMap,\n\t}\n}\n\n/**\n * Tracked state field for dedup + auto-trigger.\n */\ntype StateField = 'sta' | 'pr' | 'cid' | 'bg' | 'br'\n\n/**\n * One row in the STATE_FIELDS dispatch table.\n *\n * `snapshot` captures the value stored in `lastEmitted` for dedup\n * comparisons. Reference types must clone so the baseline doesn't\n * share a reference with the caller's input, which would let in-place\n * mutation silently poison the dedup state.\n */\ntype StateFieldEntry = {\n\tfield: StateField\n\tevent: CmcdEventType\n\tequal: (a: unknown, b: unknown) => boolean\n\tsnapshot: (v: unknown) => unknown\n}\n\n/**\n * Deep equality for CmcdObjectTypeList (used for `br` dedup).\n *\n * Order-sensitive: arrays with the same elements in different positions\n * are treated as different. Players that construct `br` consistently\n * get correct dedup; shuffling produces spurious emits, which is the\n * safer failure mode.\n */\nfunction cmcdObjectTypeListEqual(a: CmcdObjectTypeList, b: CmcdObjectTypeList): boolean {\n\tif (a === b) return true\n\tif (a.length !== b.length) return false\n\n\tfor (let i = 0; i < a.length; i++) {\n\t\tconst ai = a[i]\n\t\tconst bi = b[i]\n\t\tif (ai === bi) continue\n\t\tif (typeof ai === 'number' || typeof bi === 'number') return false\n\n\t\t// Both are SfItem<number, ExclusiveRecord<CmcdObjectType, boolean>>\n\t\tif (ai.value !== bi.value) return false\n\n\t\t// ExclusiveRecord: params (when defined) has exactly one key\n\t\tconst ap = ai.params\n\t\tconst bp = bi.params\n\t\tconst ak = ap && Object.keys(ap)[0]\n\t\tconst bk = bp && Object.keys(bp)[0]\n\t\tif (ak !== bk) return false\n\t\tif (ak !== undefined && bk !== undefined && ap && bp && ap[ak as keyof typeof ap] !== bp[bk as keyof typeof bp]) return false\n\t}\n\n\treturn true\n}\n\nconst equal = Object.is\nconst identity = <T>(v: T): T => v\n\n/**\n * Maps each tracked state field to its event type and equality function.\n * Order matters: `update()` fires events in this order for multi-field updates.\n */\nconst STATE_FIELDS: readonly StateFieldEntry[] = /* @__PURE__ */ Array.from(\n\tCMCD_STATE_EVENT_FIELDS,\n\t([event, field]): StateFieldEntry => {\n\t\tif (field === 'br') {\n\t\t\treturn {\n\t\t\t\tevent,\n\t\t\t\tfield,\n\t\t\t\tequal: (a, b) => (a === undefined || b === undefined) ? a === b : cmcdObjectTypeListEqual(a as CmcdObjectTypeList, b as CmcdObjectTypeList),\n\t\t\t\tsnapshot: (v) => (v as CmcdObjectTypeList).slice(),\n\t\t\t}\n\t\t}\n\t\treturn { event, field: field as StateField, equal, snapshot: identity }\n\t},\n)\n\nconst STATE_FIELDS_BY_EVENT: ReadonlyMap<CmcdEventType, StateFieldEntry> = /* @__PURE__ */ new Map(\n\t/* @__PURE__ */ STATE_FIELDS.map(e => [e.event, e]),\n)\n\n/**\n * Maps each event type to the key CTA-5004-B requires beyond `e` and `ts`.\n * Built from the state-change table plus the three event types whose\n * required key rides the caller's per-event data.\n */\nconst CMCD_REQUIRED_EVENT_KEYS: ReadonlyMap<CmcdEventType, CmcdKey> = /* @__PURE__ */ new Map([\n\t.../* @__PURE__ */ CMCD_STATE_EVENT_FIELDS,\n\t[CMCD_EVENT_CUSTOM_EVENT, 'cen'] as const,\n\t[CMCD_EVENT_ERROR, 'ec'] as const,\n\t[CMCD_EVENT_RESPONSE_RECEIVED, 'url'] as const,\n])\n\n/**\n * Whether a required key's value will survive report preparation.\n *\n * This is `isValid` minus its `false` exclusion, plus an empty-array check.\n * `false` must count as usable because `bg: false` is a legitimate value on a\n * backgrounded-mode event, which the encoder emits as `?0`; treating it as\n * unusable would let restoration silently revert a transform that cleared it.\n * Empty strings, empty lists and non-finite numbers are dropped downstream, so\n * a transform substituting one leaves the report short a required key.\n */\nfunction isUsableRequiredValue(value: unknown): boolean {\n\tif (value == null || value === '') {\n\t\treturn false\n\t}\n\n\tif (typeof value === 'number') {\n\t\treturn Number.isFinite(value)\n\t}\n\n\treturn !Array.isArray(value) || value.length > 0\n}\n\n/**\n * Copies an `SfItem`-shaped value and its `params` record.\n *\n * The prototype is preserved because `prepareCmcdData`, the formatter map,\n * validation, and the structured-field encoder all branch on\n * `instanceof SfItem`. A plain spread (and `structuredClone`) would return a\n * prototype-less object and silently change what goes on the wire.\n */\nfunction copyItemValue(value: unknown): unknown {\n\tif (value === null || typeof value !== 'object') {\n\t\treturn value\n\t}\n\n\tconst copy = Object.assign(Object.create(Object.getPrototypeOf(value)), value) as { params?: unknown; }\n\n\tif (copy.params !== null && typeof copy.params === 'object') {\n\t\tcopy.params = { ...copy.params }\n\t}\n\n\treturn copy\n}\n\n/**\n * Copies the nested values of a report in place so a transform cannot mutate\n * the reporter's persistent data, or another target's report for the same\n * event, by mutating an array or an `SfItem` it was handed.\n *\n * Complete for the CMCD value space rather than best-effort: `CmcdValue` and\n * `CmcdCustomValue` admit only primitives, `SfItem<primitive>`, and arrays of\n * those, and `SfItem.params` is a flat record. Only called where a transform\n * is configured.\n */\nfunction copyReportValues(data: Cmcd): Cmcd {\n\tconst record = data as Record<string, unknown>\n\n\tfor (const key in record) {\n\t\tconst value = record[key]\n\n\t\tif (Array.isArray(value)) {\n\t\t\tconst copy = new Array(value.length)\n\n\t\t\tfor (let i = 0; i < value.length; i++) {\n\t\t\t\tcopy[i] = copyItemValue(value[i])\n\t\t\t}\n\n\t\t\trecord[key] = copy\n\t\t}\n\t\telse if (value !== null && typeof value === 'object') {\n\t\t\trecord[key] = copyItemValue(value)\n\t\t}\n\t}\n\n\treturn data\n}\n\nfunction defaultRequester(request: HttpRequest): Promise<{ status: number; }> {\n\tconst { url, ...init } = request\n\treturn fetch(url, init)\n}\n\nfunction createCmcdReporterConfig<C>(config: Partial<CmcdReporterConfig<C>>): CmcdReporterConfigNormalized<C> {\n\t// Apply top-level config defaults\n\tconst {\n\t\tversion = CMCD_V2,\n\t\teventTargets = [],\n\t\tsid = uuid(),\n\t\ttransmissionMode = CMCD_QUERY,\n\t\t...rest\n\t} = config\n\n\treturn {\n\t\t...rest,\n\t\tversion,\n\t\ttransmissionMode,\n\t\tsid,\n\t\t// Apply target config defaults\n\t\teventTargets: eventTargets.reduce((acc, target) => {\n\t\t\tif (target?.url && target.events?.length) {\n\t\t\t\tacc.push({\n\t\t\t\t\tversion: target.version || CMCD_V2,\n\t\t\t\t\tenabledKeys: target.enabledKeys?.slice() || [],\n\t\t\t\t\turl: target.url,\n\t\t\t\t\tevents: target.events.slice(),\n\t\t\t\t\tinterval: target.interval ?? CMCD_DEFAULT_TIME_INTERVAL,\n\t\t\t\t\tbatchSize: target.batchSize || 1,\n\t\t\t\t\ttransform: target.transform,\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn acc\n\t\t}, [] as CmcdEventReportConfigNormalized<C>[]),\n\t}\n}\n\ntype CmcdTarget = {\n\tsn: number;\n\tmsdSent: boolean;\n}\n\ntype CmcdEventTarget = CmcdTarget & {\n\tintervalId: ReturnType<typeof setInterval> | undefined;\n\tqueue: Cmcd[];\n}\n\n/**\n * The CMCD reporter.\n *\n * `C` describes the player's own `customData`, which the reporter passes\n * through to each configured `transform`. It is inferred from the\n * configuration, so annotating a single `transform` types the request in every\n * other one; the default leaves `customData` values `unknown`.\n *\n * @typeParam C - The shape of the player's `customData`. Defaults to\n * `Record<string, unknown>`.\n *\n * @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}\n *\n * @public\n */\nexport class CmcdReporter<C = Record<string, unknown>> {\n\tprivate timeOrigin = performance.timeOrigin || performance.timing?.fetchStart || Date.now() - performance.now()\n\tprivate data: Cmcd = {}\n\tprivate config: CmcdReporterConfigNormalized<C>\n\tprivate msd: number = NaN\n\tprivate eventTargets = new Map<CmcdEventReportConfigNormalized<C>, CmcdEventTarget>()\n\tprivate lastEmitted: Partial<Pick<Cmcd, StateField>> = {}\n\tprivate requestTarget: CmcdTarget = {\n\t\tsn: 0,\n\t\tmsdSent: false,\n\t}\n\n\tprivate requester: (request: HttpRequest) => Promise<{ status: number; }>\n\n\t/**\n\t * Creates a new CMCD reporter.\n\t *\n\t * @param config - The configuration for the CMCD reporter.\n\t * @param requester - The function to use to send the request.\n\t * The default is a simple wrapper around the\n\t * native `fetch` API.\n\t */\n\tconstructor(config: Partial<CmcdReporterConfig<C>>, requester: (request: HttpRequest) => Promise<{ status: number; }> = defaultRequester) {\n\t\tthis.config = createCmcdReporterConfig(config)\n\t\tthis.data = {\n\t\t\tcid: this.config.cid,\n\t\t\tsid: this.config.sid,\n\t\t\tv: this.config.version,\n\t\t}\n\t\tthis.requester = requester\n\n\t\tfor (const target of this.config.eventTargets) {\n\t\t\tthis.eventTargets.set(target, {\n\t\t\t\tintervalId: undefined,\n\t\t\t\tsn: 0,\n\t\t\t\tmsdSent: false,\n\t\t\t\tqueue: [],\n\t\t\t})\n\t\t}\n\t}\n\n\t/**\n\t * Starts the CMCD reporter. Called by the player when the reporter is enabled.\n\t *\n\t * Note: This fires an initial time-interval event immediately (synchronously)\n\t * before the first interval elapses. Ensure CMCD data (sid, cid, etc.) is\n\t * populated before calling start().\n\t */\n\tstart(): void {\n\t\t// The initial time-interval event is fired synchronously per target, so a\n\t\t// throwing transform must not abort the loop: later targets would never\n\t\t// have their intervals armed and would report nothing for the session,\n\t\t// and a retried start() would fail on the same target again. Same\n\t\t// continue-then-rethrow contract as `emitEvent()`.\n\t\tlet failure: { error: unknown; } | undefined\n\n\t\tthis.eventTargets.forEach((target, config) => {\n\t\t\t// Disarm any existing timer so repeated start() calls do not leak intervals.\n\t\t\tthis.disarmInterval(target)\n\n\t\t\t// If the interval is 0 or the TIME_INTERVAL event is not enabled, do not start the interval.\n\t\t\tif (config.interval === 0 || !config.events.includes(CMCD_EVENT_TIME_INTERVAL)) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst timeIntervalEvent = () => {\n\t\t\t\tthis.recordTargetEvent(target, config, CMCD_EVENT_TIME_INTERVAL)\n\t\t\t\tthis.processEventTargets()\n\t\t\t}\n\n\t\t\t// Armed before the initial event so a throwing transform leaves the\n\t\t\t// timer in the same state a successful start() would, rather than\n\t\t\t// silently disabling the target.\n\t\t\ttarget.intervalId = setInterval(timeIntervalEvent, config.interval * 1000)\n\n\t\t\ttry {\n\t\t\t\ttimeIntervalEvent()\n\t\t\t}\n\t\t\tcatch (error) {\n\t\t\t\tfailure ??= { error }\n\t\t\t}\n\t\t})\n\n\t\tif (failure) {\n\t\t\tthrow failure.error\n\t\t}\n\t}\n\n\t/**\n\t * Stops the CMCD reporter. Called by the player when the reporter is disabled.\n\t *\n\t * @param flush - Whether to flush the event targets.\n\t */\n\tstop(flush: boolean = false): void {\n\t\tif (flush) {\n\t\t\tthis.flush()\n\t\t}\n\n\t\tthis.eventTargets.forEach((target) => {\n\t\t\tthis.disarmInterval(target)\n\t\t})\n\t}\n\n\t/**\n\t * Forces the sending of all event reports, regardless of the batch size or interval.\n\t * Useful for sending outstanding reports when the player is destroyed or a playback\n\t * session ends.\n\t */\n\tflush(): void {\n\t\tthis.processEventTargets(true)\n\t}\n\n\t/**\n\t * Updates the CMCD data.\n\t *\n\t * Called by the player when data changes. For tracked state fields\n\t * (`sta`, `pr`, `cid`, `bg`, `br`), if the new value differs from the\n\t * last-reported value (the value most recently emitted on the wire for\n\t * that field), the corresponding state-change event is automatically\n\t * fired. Comparing against the last-reported value (rather than the\n\t * previous persisted value) ensures the first state-change event in a\n\t * new session always emits, even when the persisted value didn't change\n\t * across the `sid` boundary.\n\t *\n\t * Multi-field updates fire multiple events in the order: `sta` → `pr` →\n\t * `cid` → `bg` → `br`. The order of keys in the input object does not\n\t * affect the firing order.\n\t *\n\t * To attach snapshot context (e.g., `bl`, `mtp`, `pt`, `ltc`) to a\n\t * state-change event, ensure those fields are in the reporter's data\n\t * before the state field changes. Either include them alongside the\n\t * state field in the same `update()` call, or persist them via earlier\n\t * `update()` calls — auto-fired events emit whatever is currently in\n\t * the persistent data store. This is also how to keep `TIME_INTERVAL`\n\t * reports useful — those events draw from the persistent data store\n\t * with no caller hook for per-event data, so fields the player wants\n\t * in periodic reports must be kept fresh here.\n\t *\n\t * A `sid` change resets the dedup baseline.\n\t *\n\t * @param data - The data to update.\n\t */\n\tupdate(data: Partial<Cmcd>): void {\n\t\tif (data.sid && data.sid !== this.data.sid) {\n\t\t\tthis.resetSession()\n\t\t}\n\n\t\tif (data.msd && !isNaN(data.msd)) {\n\t\t\tthis.msd = data.msd\n\t\t}\n\n\t\t// msd is tracked separately via this.msd and sent once per target,\n\t\t// so it is stripped from the persistent data store after each update.\n\t\tthis.data = { ...this.data, ...data, msd: undefined }\n\n\t\t// Auto-trigger state-change events for any tracked field whose value\n\t\t// differs from the last wire-emitted value. Comparing against lastEmitted\n\t\t// (not the pre-merge value) ensures correctness after a session reset,\n\t\t// and unifies the comparison basis with recordEvent's internal dedup.\n\t\tfor (const entry of STATE_FIELDS) {\n\t\t\tif (entry.field in data && !entry.equal(this.data[entry.field], this.lastEmitted[entry.field])) {\n\t\t\t\tthis.recordEvent(entry.event)\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Records an event. Called by the player when an event occurs.\n\t *\n\t * For state-change events (`PLAY_STATE`, `PLAYBACK_RATE`, `CONTENT_ID`,\n\t * `BACKGROUNDED_MODE`, `BITRATE_CHANGE`), this method:\n\t * 1. Persists the dedup field from `data` (if present) into the reporter's\n\t * persistent data store — equivalent to a write-through `update()`.\n\t * 2. Drops the event entirely if the dedup field has no value after the\n\t * write-through (never set, or cleared via `update({ field: undefined })`).\n\t * State-change events without their required field would violate CTA-5004-B.\n\t * 3. Suppresses the event if the field's current value matches the\n\t * last-emitted value (no state transition).\n\t *\n\t * For all other event types, the event is always emitted.\n\t *\n\t * For state-change events, prefer {@link CmcdReporter.update} — including\n\t * for snapshot enrichment via a combined call like\n\t * `update({ sta: 'p', bl: [3000], mtp: [8500] })`. Calling `recordEvent()`\n\t * for a state-change event after `update()` has already auto-fired it\n\t * silently drops the second call's `data`, because dedup suppresses the\n\t * second emission.\n\t *\n\t * Use `recordEvent()` directly for events whose payload is intrinsic to\n\t * the event call — `CUSTOM_EVENT` with `cen`, `ERROR` with `ec`,\n\t * ad-lifecycle events, `MUTE`/`UNMUTE`, `PLAYER_EXPAND`/`PLAYER_COLLAPSE`,\n\t * `SKIP`. For `RESPONSE_RECEIVED`, prefer\n\t * {@link CmcdReporter.recordResponseReceived}, which derives the\n\t * per-response fields automatically.\n\t *\n\t * @param type - The type of event to record.\n\t * @param data - Additional data to record with the event. This data\n\t * only applies to this event report, except for the dedup\n\t * field of a state-change event, which is also persisted\n\t * into the reporter's data store.\n\t */\n\trecordEvent(type: CmcdEventType, data: Partial<Cmcd> = {}): void {\n\t\tthis.emitEvent(type, data)\n\t}\n\n\t/**\n\t * Records an event across every configured target, applying\n\t * state-change dedup once before per-target fan-out.\n\t *\n\t * @param type - The type of event to record.\n\t * @param data - Additional data to record with the event.\n\t * @param request - The media request that triggered the event, when\n\t * one exists. Only `recordResponseReceived()`\n\t * populates this; it is threaded through to each\n\t * target's `transform`.\n\t */\n\tprivate emitEvent(type: CmcdEventType, data: Partial<Cmcd>, request?: HttpRequest): void {\n\t\tconst entry = STATE_FIELDS_BY_EVENT.get(type)\n\t\tif (entry) {\n\t\t\tconst field = entry.field\n\t\t\tconst incoming = data[field]\n\n\t\t\tif (incoming !== undefined) {\n\t\t\t\tObject.assign(this.data, { [field]: incoming })\n\t\t\t}\n\n\t\t\tconst current = this.data[field]\n\n\t\t\t// Never emit a state-change event with a missing required field — per\n\t\t\t// CTA-5004-B these events must carry their dedup field. Catches both\n\t\t\t// \"no value ever set\" and \"previous value was cleared to undefined\".\n\t\t\tif (current === undefined) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (entry.equal(current, this.lastEmitted[field])) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tObject.assign(this.lastEmitted, { [field]: entry.snapshot(current) })\n\t\t}\n\n\t\t// A throwing transform must not abort the fan-out. The dedup baseline\n\t\t// above is already committed and is never rolled back, so aborting here\n\t\t// would strand the transition: targets after the throwing one would\n\t\t// never receive it, and the caller's retry would be deduped away.\n\t\tlet failure: { error: unknown; } | undefined\n\n\t\tthis.eventTargets.forEach((target, config) => {\n\t\t\ttry {\n\t\t\t\tthis.recordTargetEvent(target, config, type, data, request)\n\t\t\t}\n\t\t\tcatch (error) {\n\t\t\t\tfailure ??= { error }\n\t\t\t}\n\t\t})\n\n\t\tthis.processEventTargets()\n\n\t\t// Surfaced only once every target has had its turn and the queues have\n\t\t// been processed. Transforms must not throw; this makes the violation\n\t\t// visible without letting it starve unrelated targets.\n\t\tif (failure) {\n\t\t\tthrow failure.error\n\t\t}\n\t}\n\n\t/**\n\t * Records an event for a target. Called by the reporter when an event occurs.\n\t *\n\t * @param target - The target to record the event for.\n\t * @param config - The configuration for the target.\n\t * @param type - The type of event to record.\n\t * @param data - Additional data to record with the event. This data\n\t * only applies to this event report. Persistent data should\n\t * be updated using `update()`.\n\t * @param request - The media request that triggered the event, when\n\t * one exists. Passed to the target's `transform`.\n\t */\n\tprivate recordTargetEvent(target: CmcdEventTarget, config: CmcdEventReportConfigNormalized<C>, type: CmcdEventType, data: Partial<Cmcd> = {}, request?: HttpRequest): void {\n\t\tif (!config.events.includes(type)) {\n\t\t\treturn\n\t\t}\n\n\t\t// Each target gets its own copy, so a transform that mutates in\n\t\t// place affects neither sibling targets nor the persistent data.\n\t\tconst item: Cmcd = {\n\t\t\t...this.data,\n\t\t\t...data,\n\t\t\te: type,\n\t\t\tts: data.ts ?? Date.now(),\n\t\t}\n\n\t\tconst { transform } = config\n\n\t\tif (!transform) {\n\t\t\tthis.queueTargetEvent(target, item, type)\n\t\t\treturn\n\t\t}\n\n\t\t// The spread above is shallow, so nested values are still shared with\n\t\t// the persistent store and with the other targets' copies.\n\t\tcopyReportValues(item)\n\n\t\t// Captured so a transform cannot strip a key the event requires.\n\t\t// `CmcdKey` spans custom keys too, so index through a record view.\n\t\tconst requiredKey = CMCD_REQUIRED_EVENT_KEYS.get(type)\n\t\tconst requiredValue = requiredKey ? (item as Record<string, unknown>)[requiredKey] : undefined\n\t\tconst ts = item.ts\n\n\t\tconst report = transform(item, request)\n\n\t\t// A cancelled report consumes neither a sequence number nor msd.\n\t\tif (report == null) {\n\t\t\treturn\n\t\t}\n\n\t\t// Restore, never fabricate: a required key that was already absent (or\n\t\t// already unusable) before the transform ran was a caller bug, not a\n\t\t// transform bug. Removal and substitution are both covered, because a\n\t\t// value the encoder drops leaves the report just as invalid as a missing\n\t\t// one.\n\t\tif (!isUsableRequiredValue(report.ts)) {\n\t\t\treport.ts = ts\n\t\t}\n\n\t\tif (requiredKey && isUsableRequiredValue(requiredValue) && !isUsableRequiredValue((report as Record<string, unknown>)[requiredKey])) {\n\t\t\tObject.assign(report, { [requiredKey]: requiredValue })\n\t\t}\n\n\t\tthis.queueTargetEvent(target, report, type)\n\t}\n\n\t/**\n\t * Stamps the reporter-owned fields on a finished event report and pushes it\n\t * to the target's queue.\n\t *\n\t * Called after any transform has run, so a transform cannot bypass the\n\t * target's `events` filter via `e` or break `sn` continuity.\n\t *\n\t * @param target - The target to queue the report for.\n\t * @param report - The finished report data.\n\t * @param type - The type of event being reported.\n\t */\n\tprivate queueTargetEvent(target: CmcdEventTarget, report: Cmcd, type: CmcdEventType): void {\n\t\treport.e = type\n\t\treport.sn = target.sn++\n\n\t\tif (!isNaN(this.msd) && !target.msdSent) {\n\t\t\treport.msd = this.msd\n\t\t\ttarget.msdSent = true\n\t\t}\n\n\t\ttarget.queue.push(report)\n\t}\n\n\t/**\n\t * Records a response-received event. Called by the player when a media\n\t * request response has been fully received.\n\t *\n\t * This method automatically derives the `rr` event keys from the\n\t *\n\t * - `url` - the original requested URL (before any redirects)\n\t * - `rc` - the HTTP response status code\n\t * - `ts` - the request initiation time (from `resourceTiming.startTime`)\n\t * - `ttfb` - time to first byte (from `resourceTiming.responseStart`)\n\t * - `ttlb` - time to last byte (from `resourceTiming.duration`)\n\t *\n\t * Additional keys like `ttfbb`, `cmsdd`, `cmsds`, and `smrt` can be\n\t * supplied via the `data` parameter if the player has access to them.\n\t *\n\t * The request's `customData` is generic, so a player can pass a request\n\t * carrying its own taxonomy (e.g. `{ requestType: 'segment' }`) without a\n\t * cast. The reporter only reads the optional `cmcd` key that\n\t * {@link CmcdReporter.createRequestReport} writes there; every other key is\n\t * left untouched and stays visible to an event target's `transform` via\n\t * its `request` argument.\n\t *\n\t * A reporter given a concrete `C` requires the request to satisfy it, so a\n\t * request the configured transforms could not read is rejected here rather\n\t * than reaching them; see {@link CmcdReporterCustomData}.\n\t *\n\t * @typeParam RD - The `customData` this request carries. Defaults to the\n\t * reporter's own `C`.\n\t *\n\t * @param response - The HTTP response received.\n\t * @param data - Additional CMCD data to include with the event.\n\t * Values provided here override any auto-derived values.\n\t */\n\trecordResponseReceived<RD extends CmcdReporterCustomData<C> = C>(response: HttpResponse<HttpRequest<RD & { cmcd?: Cmcd }>>, data: Partial<Cmcd> = {}): void {\n\t\tconst { request } = response\n\n\t\tconst url = data.url ?? request?.url\n\n\t\tif (!url) {\n\t\t\treturn\n\t\t}\n\n\t\tconst urlObj = new URL(url)\n\t\turlObj.searchParams.delete(CMCD_PARAM)\n\n\t\tconst derived: Partial<Cmcd> = {\n\t\t\turl: urlObj.toString(),\n\t\t\trc: response.status,\n\t\t}\n\n\t\tconst timing = response.resourceTiming\n\n\t\tif (timing) {\n\t\t\tif (timing.startTime != null) {\n\t\t\t\tderived.ts = Math.round(this.timeOrigin + timing.startTime)\n\n\t\t\t\tif (timing.responseStart != null) {\n\t\t\t\t\tderived.ttfb = Math.round(timing.responseStart - timing.startTime)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (timing.duration != null) {\n\t\t\t\tderived.ttlb = Math.round(timing.duration)\n\t\t\t}\n\t\t}\n\n\t\tconst cmcd = request.customData?.cmcd ?? {}\n\n\t\tthis.emitEvent(CMCD_EVENT_RESPONSE_RECEIVED, { ...cmcd, ...derived, ...data }, request)\n\t}\n\n\t/**\n\t * Applies the CMCD request report data to the request. Called by the player\n\t * before sending the request.\n\t *\n\t * @param req - The request to apply the CMCD request report to.\n\t * @returns The request with the CMCD request report applied.\n\t *\n\t * @deprecated Use {@link CmcdReporter.createRequestReport} instead.\n\t */\n\tapplyRequestReport(req: HttpRequest): HttpRequest {\n\t\treturn this.createRequestReport(req) ?? req\n\t}\n\n\t/**\n\t * Checks if the request reporting is enabled.\n\t *\n\t * @returns `true` if the request reporting is enabled, `false` otherwise.\n\t */\n\tisRequestReportingEnabled(): boolean {\n\t\treturn !!this.config.enabledKeys?.length\n\t}\n\n\t/**\n\t * Creates a new request with the CMCD request report data applied. Called by the player\n\t * before sending the request.\n\t *\n\t * A reporter given a concrete `C` requires the request's `customData` to\n\t * satisfy it, so a request the configured transform could not read is\n\t * rejected here rather than reaching it; see\n\t * {@link CmcdReporterCustomData}.\n\t *\n\t * @typeParam R - The request being decorated. Its `customData` must satisfy\n\t * the reporter's `C`.\n\t *\n\t * @param request - The request to apply the CMCD request report to.\n\t * @param data - The data to apply to the request. This data only\n\t * applies to this request report. Persistent data\n\t * should be updated using `update()`.\n\t * @returns The request with the CMCD request report applied.\n\t */\n\tcreateRequestReport<R extends HttpRequest<CmcdReporterCustomData<C>> = HttpRequest<C>>(request: R, data?: Partial<Cmcd>): R & CmcdRequestReport<R['customData']> {\n\t\tconst { customData = {}, headers = {}, ...rest } = request\n\t\tconst report = {\n\t\t\t...rest,\n\t\t\theaders: {\n\t\t\t\t...headers,\n\t\t\t},\n\t\t\tcustomData: {\n\t\t\t\t...customData,\n\t\t\t\tcmcd: {},\n\t\t\t},\n\t\t} as R & CmcdRequestReport<R['customData']>\n\n\t\tif (!this.config.enabledKeys?.length || !report.url) {\n\t\t\treturn report\n\t\t}\n\n\t\tconst merged: Cmcd = { ...this.data, ...data }\n\t\tconst { transform } = this.config\n\t\tlet cmcdData: Cmcd | null = merged\n\n\t\tif (transform) {\n\t\t\t// The spread above is shallow, so nested values are still shared\n\t\t\t// with the persistent store.\n\t\t\tcopyReportValues(merged)\n\n\t\t\t// The caller's request is passed, not the internal clone, so a\n\t\t\t// transform cannot alter the outgoing report through it.\n\t\t\tcmcdData = transform(merged, request as CmcdTransformRequest<C>)\n\n\t\t\t// A cancelled report consumes neither a sequence number nor msd.\n\t\t\tif (cmcdData == null) {\n\t\t\t\treturn report\n\t\t\t}\n\t\t}\n\n\t\t// Reporter-owned fields are stamped after the transform runs.\n\t\tcmcdData.sn = this.requestTarget.sn++\n\n\t\tif (!isNaN(this.msd) && !this.requestTarget.msdSent) {\n\t\t\tcmcdData.msd = this.msd\n\t\t\tthis.requestTarget.msdSent = true\n\t\t}\n\n\t\tconst url = new URL(report.url)\n\t\tconst options = createEncodingOptions(CMCD_REQUEST_MODE, this.config, report.url)\n\n\t\tconst cmcd = report.customData.cmcd = prepareCmcdData(cmcdData, options)\n\n\t\tswitch (this.config.transmissionMode) {\n\t\t\tcase CMCD_QUERY:\n\t\t\t\tconst param = encodePreparedCmcd(cmcd)\n\t\t\t\tif (param) {\n\t\t\t\t\turl.searchParams.set(CMCD_PARAM, param)\n\t\t\t\t\treport.url = url.toString()\n\t\t\t\t}\n\t\t\t\tbreak\n\n\t\t\tcase CMCD_HEADERS:\n\t\t\t\tObject.assign(report.headers, toPreparedCmcdHeaders(cmcd, options.customHeaderMap))\n\t\t\t\tbreak\n\t\t}\n\n\t\treturn report\n\t}\n\n\t/**\n\t * Processes the event targets. Called by the reporter when an event occurs.\n\t *\n\t * @param flush - Whether to flush the event targets.\n\t */\n\tprivate processEventTargets(flush: boolean = false): void {\n\t\tlet reprocess = false\n\n\t\tthis.eventTargets.forEach((target, config) => {\n\t\t\tconst { queue } = target\n\n\t\t\tif (!queue.length) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (queue.length < config.batchSize && !flush) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst deleteCount = flush ? queue.length : config.batchSize\n\t\t\tconst events = queue.splice(0, deleteCount)\n\t\t\tthis.sendEventReport(config, events).catch(() => {\n\t\t\t\t// Re-queue events that failed to send\n\t\t\t\ttarget.queue.unshift(...events)\n\t\t\t})\n\n\t\t\treprocess ||= queue.length > 0\n\t\t})\n\n\t\tif (reprocess) {\n\t\t\tthis.processEventTargets()\n\t\t}\n\t}\n\n\t/**\n\t * Sends an event report. Called by the reporter when a batch is ready to be sent.\n\t *\n\t * @param config - The target config to send the event report to.\n\t * @param data - The data to send in the event report.\n\t */\n\tprivate async sendEventReport(config: CmcdEventReportConfigNormalized<C>, data: Cmcd[]): Promise<void> {\n\t\tconst options = createEncodingOptions(CMCD_EVENT_MODE, config)\n\t\tconst response = await this.requester({\n\t\t\turl: config.url,\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': CMCD_MIME_TYPE,\n\t\t\t},\n\t\t\tbody: data.map(item => encodeCmcd(item, options)).join('\\n') + '\\n',\n\t\t})\n\n\t\tconst { status } = response\n\n\t\tif (status === 410) {\n\t\t\tthis.disposeEventTarget(config)\n\t\t} else if (status === 429 || (status > 499 && status < 600)) {\n\t\t\tthrow new Error(`Event report failed with status ${status}`)\n\t\t}\n\t}\n\n\t/**\n\t * Cancels the time-interval timer for an event target and clears the stored id.\n\t * Safe to call when no timer is armed (clearInterval(undefined) is a no-op).\n\t */\n\tprivate disarmInterval(target: CmcdEventTarget): void {\n\t\tclearInterval(target.intervalId)\n\t\ttarget.intervalId = undefined\n\t}\n\n\t/**\n\t * Permanently removes an event target: cancels its timer and removes it from the\n\t * eventTargets map. Used when the collector signals the target is gone (HTTP 410).\n\t */\n\tprivate disposeEventTarget(config: CmcdEventReportConfigNormalized<C>): void {\n\t\tconst target = this.eventTargets.get(config)\n\t\tif (!target) {\n\t\t\treturn\n\t\t}\n\t\tthis.disarmInterval(target)\n\t\tthis.eventTargets.delete(config)\n\t}\n\n\t/**\n\t * Resets the session related data. Called when the session ID changes.\n\t */\n\tprivate resetSession(): void {\n\t\tthis.eventTargets.forEach(target => target.sn = 0)\n\t\tthis.requestTarget.sn = 0\n\t\tthis.lastEmitted = {}\n\t}\n}\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * Common Media Client Data Streaming Format\n *\n * @enum\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#streaming-format | CTA-5004-B Streaming Format}\n *\n * @public\n */\nexport const CmcdStreamingFormat = {\n\t/**\n\t * MPEG DASH\n\t */\n\tDASH: 'd',\n\n\t/**\n\t * HTTP Live Streaming (HLS)\n\t */\n\tHLS: 'h',\n\n\t/**\n\t * Smooth Streaming\n\t */\n\tSMOOTH: 's',\n\n\t/**\n\t * Other\n\t */\n\tOTHER: 'o',\n} as const\n\n/**\n * @public\n */\nexport type CmcdStreamingFormat = ValueOf<typeof CmcdStreamingFormat>;\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * Common Media Client Data Stream Type\n *\n * @enum\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#stream-type | CTA-5004-B Stream Type}\n *\n * @public\n */\nexport const CmcdStreamType = {\n\t/**\n\t * All segments are available – e.g., VOD\n\t */\n\tVOD: 'v',\n\n\t/**\n\t * Segments become available over time – e.g., LIVE\n\t */\n\tLIVE: 'l',\n\n\t/**\n\t * Low latency stream\n\t */\n\tLOW_LATENCY: 'll',\n} as const\n\n/**\n * @public\n */\nexport type CmcdStreamType = ValueOf<typeof CmcdStreamType>;\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * CMCD validation severity level: error.\n *\n * @public\n */\nexport const CMCD_VALIDATION_SEVERITY_ERROR = 'error' as const\n\n/**\n * CMCD validation severity level: warning.\n *\n * @public\n */\nexport const CMCD_VALIDATION_SEVERITY_WARNING = 'warning' as const\n\n/**\n * CMCD validation severity level.\n *\n * @public\n */\nexport const CmcdValidationSeverity = {\n\tERROR: CMCD_VALIDATION_SEVERITY_ERROR as typeof CMCD_VALIDATION_SEVERITY_ERROR,\n\tWARNING: CMCD_VALIDATION_SEVERITY_WARNING as typeof CMCD_VALIDATION_SEVERITY_WARNING,\n} as const\n\n/**\n * CMCD validation severity level.\n *\n * @public\n */\nexport type CmcdValidationSeverity = ValueOf<typeof CmcdValidationSeverity>;\n","import { CMCD_INNER_LIST_KEYS } from './CMCD_INNER_LIST_KEYS.ts'\nimport { CMCD_V2 } from './CMCD_V2.ts'\n\n/**\n * Up-convert V1 CMCD data to V2 format.\n *\n * - Wraps plain scalar values in arrays for inner-list keys.\n * - Wraps `nor` string in an array.\n *\n * If the data is already V2 (has `v: 2`), it is returned unchanged.\n *\n * @internal\n */\nexport function upConvertToV2(obj: Record<string, any>): Record<string, any> {\n\tif (obj['v'] === CMCD_V2) {\n\t\treturn obj\n\t}\n\n\tconst result: Record<string, any> = {}\n\n\tfor (const [key, value] of Object.entries(obj)) {\n\t\tif (value == null) {\n\t\t\tresult[key] = value\n\t\t\tcontinue\n\t\t}\n\n\t\tif (CMCD_INNER_LIST_KEYS.has(key) && !Array.isArray(value)) {\n\t\t\tresult[key] = [value]\n\t\t}\n\t\telse if (key === 'nor' && typeof value === 'string') {\n\t\t\tresult[key] = [value]\n\t\t}\n\t\telse {\n\t\t\tresult[key] = value\n\t\t}\n\t}\n\n\treturn result\n}\n","import type { SfBareItem } from '@svta/cml-structured-field-values'\nimport { decodeSfDict, SfItem, symbolToStr } from '@svta/cml-structured-field-values'\nimport type { Cmcd } from './Cmcd.ts'\nimport type { CmcdData } from './CmcdData.ts'\nimport type { CmcdDecodeOptions } from './CmcdDecodeOptions.ts'\nimport type { CmcdValue } from './CmcdValue.ts'\nimport { upConvertToV2 } from './upConvertToV2.ts'\n\n// Define the input type for reduceValue\ntype ReduceValueInput = SfBareItem | SfItem | ReduceValueInput[];\n\n// Define the output type for reduceValue - matches what CMCD values can be, including arrays\ntype ReduceValueOutput = CmcdValue | ReduceValueOutput[];\n\nfunction reduceValue(value: ReduceValueInput): ReduceValueOutput {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(reduceValue)\n\t}\n\n\tif (typeof value === 'symbol') {\n\t\treturn symbolToStr(value)\n\t}\n\n\tif (value instanceof SfItem && !value.params) {\n\t\treturn reduceValue(value.value)\n\t}\n\n\tif (typeof value === 'string') {\n\t\treturn value\n\t}\n\n\treturn value as ReduceValueOutput\n};\n\n/**\n * Decode a CMCD string to an object.\n *\n * @param cmcd - The CMCD string to decode.\n * @param options - Options for decoding.\n *\n * @returns The decoded CMCD object.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#payload-definition-for-headers-and-query-argument-transmission | CTA-5004-B Payload Definition}\n *\n * @public\n *\n * @example\n * {@includeCode ../test/decodeCmcd.test.ts#example}\n */\nexport function decodeCmcd(cmcd: string, options: CmcdDecodeOptions & { convertToLatest: true }): Cmcd\nexport function decodeCmcd<T extends CmcdData = CmcdData>(cmcd: string, options?: CmcdDecodeOptions): T\nexport function decodeCmcd(cmcd: string, options?: CmcdDecodeOptions): CmcdData | Cmcd {\n\tif (!cmcd) {\n\t\treturn {} as CmcdData\n\t}\n\n\tconst sfDict = decodeSfDict(cmcd)\n\n\tconst result: Record<string, unknown> = {}\n\tfor (const [key, item] of Object.entries(sfDict as Record<string, SfItem>)) {\n\t\tresult[key] = reduceValue(item.value)\n\t}\n\n\tif (options?.convertToLatest) {\n\t\treturn upConvertToV2(result) as Cmcd\n\t}\n\n\treturn result as CmcdData\n}\n","/**\n * Converts a record of header fields to a `Headers` instance if necessary.\n *\n * @param headers - A `Headers` instance or a plain record of header fields.\n * @returns A `Headers` instance.\n *\n * @internal\n */\nexport function ensureHeaders(headers: Record<string, string> | Headers): Headers {\n\treturn headers instanceof Headers ? headers : new Headers(headers)\n}\n","import type { Cmcd } from './Cmcd.ts'\nimport type { CmcdData } from './CmcdData.ts'\nimport type { CmcdDecodeOptions } from './CmcdDecodeOptions.ts'\nimport { CMCD_HEADER_FIELDS } from './CmcdHeaderField.ts'\nimport { decodeCmcd } from './decodeCmcd.ts'\nimport { ensureHeaders } from './ensureHeaders.ts'\nimport { upConvertToV2 } from './upConvertToV2.ts'\n\n/**\n * Decode CMCD data from request headers.\n *\n * @param headers - The request headers to decode.\n * @param options - Options for decoding.\n *\n * @returns The decoded CMCD data.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#header-field-definition | CTA-5004-B Header Field Definition}\n *\n * @public\n *\n * @example\n * {@includeCode ../test/fromCmcdHeaders.test.ts#example}\n */\nexport function fromCmcdHeaders(headers: Record<string, string> | Headers, options: CmcdDecodeOptions & { convertToLatest: true }): Cmcd\nexport function fromCmcdHeaders(headers: Record<string, string> | Headers, options?: CmcdDecodeOptions): CmcdData\nexport function fromCmcdHeaders(headers: Record<string, string> | Headers, options?: CmcdDecodeOptions): CmcdData | Cmcd {\n\tconst h = ensureHeaders(headers)\n\n\tconst result: Record<string, unknown> = {}\n\tfor (const field of CMCD_HEADER_FIELDS) {\n\t\tconst value = h.get(field)\n\t\tif (value) {\n\t\t\tObject.assign(result, decodeCmcd(value))\n\t\t}\n\t}\n\n\tif (options?.convertToLatest) {\n\t\treturn upConvertToV2(result) as Cmcd\n\t}\n\n\treturn result as CmcdData\n}\n","import { CMCD_PARAM } from './CMCD_PARAM.ts'\nimport type { Cmcd } from './Cmcd.ts'\nimport type { CmcdData } from './CmcdData.ts'\nimport type { CmcdDecodeOptions } from './CmcdDecodeOptions.ts'\nimport { decodeCmcd } from './decodeCmcd.ts'\n\n/**\n * Decode CMCD data from a query string.\n *\n * @param query - The query string to decode.\n * @param options - Options for decoding.\n *\n * @returns The decoded CMCD data.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#query-argument-definition | CTA-5004-B Query Argument Definition}\n *\n * @public\n *\n * @example\n * {@includeCode ../test/fromCmcdQuery.test.ts#example}\n */\nexport function fromCmcdQuery(query: string | URLSearchParams, options: CmcdDecodeOptions & { convertToLatest: true }): Cmcd\nexport function fromCmcdQuery(query: string | URLSearchParams, options?: CmcdDecodeOptions): CmcdData\nexport function fromCmcdQuery(query: string | URLSearchParams, options?: CmcdDecodeOptions): CmcdData | Cmcd {\n\tif (typeof query === 'string') {\n\t\tquery = new URLSearchParams(query)\n\t}\n\n\tconst value = query.get(CMCD_PARAM)\n\n\treturn decodeCmcd(value ?? '', options as CmcdDecodeOptions)\n}\n","import type { Cmcd } from './Cmcd.ts'\nimport type { CmcdData } from './CmcdData.ts'\nimport type { CmcdDecodeOptions } from './CmcdDecodeOptions.ts'\nimport { decodeCmcd } from './decodeCmcd.ts'\n\n/**\n * Decode CMCD data from a url encoded string.\n *\n * @param url - The url encoded string to decode.\n * @param options - Options for decoding.\n *\n * @returns The decoded CMCD data.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#query-argument-definition | CTA-5004-B Query Argument Definition}\n *\n * @public\n *\n * @example\n * {@includeCode ../test/fromCmcdUrl.test.ts#example}\n */\nexport function fromCmcdUrl(url: string, options: CmcdDecodeOptions & { convertToLatest: true }): Cmcd\nexport function fromCmcdUrl(url: string, options?: CmcdDecodeOptions): CmcdData\nexport function fromCmcdUrl(url: string, options?: CmcdDecodeOptions): CmcdData | Cmcd {\n\treturn decodeCmcd(decodeURIComponent(url.replace(/^CMCD=/, '')), options as CmcdDecodeOptions)\n}\n","import { CMCD_V2 } from './CMCD_V2.ts'\nimport type { CmcdData } from './CmcdData.ts'\nimport type { CmcdV1Data } from './CmcdData.ts'\n\n/**\n * Check if a CMCD data object is version 1.\n *\n * @param data - The CMCD data object to check.\n *\n * @returns `true` if the data is version 1, `false` otherwise.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/isCmcdV1Data.test.ts#example}\n */\nexport function isCmcdV1Data(data: CmcdData): data is CmcdV1Data {\n\treturn data.v !== CMCD_V2\n}\n","import { CMCD_V2 } from './CMCD_V2.ts'\nimport type { CmcdData } from './CmcdData.ts'\nimport type { CmcdV2Data } from './CmcdData.ts'\n\n/**\n * Check if a CMCD data object is version 2.\n *\n * @param data - The CMCD data object to check.\n *\n * @returns `true` if the data is version 2, `false` otherwise.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/isCmcdV2Data.test.ts#example}\n */\nexport function isCmcdV2Data(data: CmcdData): data is CmcdV2Data {\n\treturn data.v === CMCD_V2\n}\n","import { type SfBareItem, SfItem } from '@svta/cml-structured-field-values'\n\n/**\n * Convert a value to a CMCD value.\n *\n * @param value - The value to convert to a CMCD value.\n * @param params - The parameters to convert to a CMCD value.\n * @returns The CMCD value.\n *\n * @public\n */\nexport function toCmcdValue<V extends SfBareItem, P>(value: V, params?: P): SfItem<V, P> {\n\treturn new SfItem(value, params)\n}\n","import type { CmcdValidationResult } from './CmcdValidationResult.ts'\nimport { CMCD_VALIDATION_SEVERITY_ERROR } from './CmcdValidationSeverity.ts'\n\n/**\n * Merges multiple validation results into a single result.\n *\n * @internal\n */\nexport function mergeValidationResults(...results: CmcdValidationResult[]): CmcdValidationResult {\n\tconst issues = results.flatMap(r => r.issues)\n\treturn {\n\t\tvalid: issues.every(i => i.severity !== CMCD_VALIDATION_SEVERITY_ERROR),\n\t\tissues,\n\t}\n}\n","import { CMCD_V1 } from './CMCD_V1.ts'\nimport type { CmcdValidationOptions } from './CmcdValidationOptions.ts'\n\n/**\n * Resolves the CMCD version from explicit options, the payload's `v` key, or the default (v1).\n *\n * @internal\n */\nexport function resolveVersion(data: Record<string, unknown>, options?: CmcdValidationOptions): number {\n\tif (options?.version === 1 || options?.version === 2) {\n\t\treturn options.version\n\t}\n\n\tconst payloadVersion = data['v']\n\tif (payloadVersion === 1 || payloadVersion === 2) {\n\t\treturn payloadVersion\n\t}\n\n\treturn CMCD_V1\n}\n","import { CMCD_KEYS } from './CMCD_KEYS.ts'\nimport { CMCD_V1 } from './CMCD_V1.ts'\nimport { CMCD_V1_KEYS } from './CMCD_V1_KEYS.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\nimport type { CmcdValidationOptions } from './CmcdValidationOptions.ts'\nimport type { CmcdValidationResult } from './CmcdValidationResult.ts'\nimport { CMCD_VALIDATION_SEVERITY_ERROR } from './CmcdValidationSeverity.ts'\nimport { isCmcdCustomKey } from './isCmcdCustomKey.ts'\nimport { resolveVersion } from './resolveVersion.ts'\n\nconst CMCD_V1_KEY_SET: ReadonlySet<string> = /* @__PURE__ */ new Set(CMCD_V1_KEYS)\nconst CMCD_KEY_SET: ReadonlySet<string> = /* @__PURE__ */ new Set(CMCD_KEYS)\n\n/**\n * Validates that all keys in a CMCD payload are recognized spec keys or valid custom keys.\n *\n * @example\n * {@includeCode ../test/validateCmcdKeys.test.ts#example}\n *\n * @param data - The CMCD payload to validate.\n * @param options - Validation options.\n * @returns The validation result.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#reserved-keys | CTA-5004-B Reserved Keys}\n *\n * @public\n */\nexport function validateCmcdKeys(data: Record<string, unknown>, options?: CmcdValidationOptions): CmcdValidationResult {\n\tconst version = resolveVersion(data, options)\n\tconst validKeySet = version === CMCD_V1 ? CMCD_V1_KEY_SET : CMCD_KEY_SET\n\tconst issues: CmcdValidationResult['issues'] = []\n\n\tfor (const key of Object.keys(data)) {\n\t\tif (isCmcdCustomKey(key as CmcdKey)) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif (!validKeySet.has(key)) {\n\t\t\tissues.push({\n\t\t\t\tkey,\n\t\t\t\tmessage: `Unknown CMCD key \"${key}\" for version ${version}.`,\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t\t})\n\t\t}\n\t}\n\n\treturn {\n\t\tvalid: issues.length === 0,\n\t\tissues,\n\t}\n}\n","import { CMCD_EVENT_KEYS } from './CMCD_EVENT_KEYS.ts'\nimport { CMCD_RESPONSE_KEYS } from './CMCD_RESPONSE_KEYS.ts'\nimport { CMCD_V1 } from './CMCD_V1.ts'\nimport { CMCD_EVENT_CUSTOM_EVENT, CMCD_EVENT_ERROR, CMCD_EVENT_RESPONSE_RECEIVED } from './CmcdEventType.ts'\nimport { CMCD_STATE_EVENT_FIELDS } from './CMCD_STATE_EVENT_FIELDS.ts'\nimport { CMCD_EVENT_MODE, CMCD_REQUEST_MODE } from './CmcdReportingMode.ts'\nimport type { CmcdValidationIssue } from './CmcdValidationIssue.ts'\nimport type { CmcdValidationOptions } from './CmcdValidationOptions.ts'\nimport type { CmcdValidationResult } from './CmcdValidationResult.ts'\nimport { CMCD_VALIDATION_SEVERITY_ERROR, CMCD_VALIDATION_SEVERITY_WARNING } from './CmcdValidationSeverity.ts'\nimport { resolveVersion } from './resolveVersion.ts'\n\n/**\n * Validates the structural rules of a CMCD payload.\n *\n * @example\n * {@includeCode ../test/validateCmcdStructure.test.ts#example}\n *\n * @param data - The CMCD payload to validate.\n * @param options - Validation options.\n * @returns The validation result.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#data-payload-definition-what-data-to-send | CTA-5004-B Data Payload Definition}\n *\n * @public\n */\nexport function validateCmcdStructure(data: Record<string, unknown>, options?: CmcdValidationOptions): CmcdValidationResult {\n\tconst version = resolveVersion(data, options)\n\tconst issues: CmcdValidationIssue[] = []\n\n\t// Request mode checks\n\tif (options?.reportingMode === CMCD_REQUEST_MODE) {\n\t\tfor (const key of CMCD_EVENT_KEYS) {\n\t\t\tif (key in data) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey,\n\t\t\t\t\tmessage: `Event key \"${key}\" must not be present in request mode.`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\tfor (const key of CMCD_RESPONSE_KEYS) {\n\t\t\tif (key in data) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey,\n\t\t\t\t\tmessage: `Response key \"${key}\" must not be present in request mode.`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\t// Event mode checks\n\tif (options?.reportingMode === CMCD_EVENT_MODE) {\n\t\tif (!('e' in data)) {\n\t\t\tissues.push({\n\t\t\t\tkey: 'e',\n\t\t\t\tmessage: 'Event mode requires the \"e\" key to be present.',\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t})\n\t\t}\n\t\tif (!('ts' in data)) {\n\t\t\tissues.push({\n\t\t\t\tkey: 'ts',\n\t\t\t\tmessage: 'Event mode requires the \"ts\" key to be present.',\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t})\n\t\t}\n\t}\n\n\t// Custom event checks\n\tif ('e' in data) {\n\t\tif (data['e'] === CMCD_EVENT_CUSTOM_EVENT) {\n\t\t\tif (!('cen' in data)) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey: 'cen',\n\t\t\t\t\tmessage: 'Custom event (e=\"ce\") requires the \"cen\" key to be present.',\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif ('cen' in data) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey: 'cen',\n\t\t\t\t\tmessage: 'The \"cen\" key must only be present when e=\"ce\".',\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\t// Response-received key restriction and required url\n\t\tif (data['e'] === CMCD_EVENT_RESPONSE_RECEIVED) {\n\t\t\tif (!('url' in data)) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey: 'url',\n\t\t\t\t\tmessage: 'Response received event (e=\"rr\") requires the \"url\" key to be present.',\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor (const key of CMCD_RESPONSE_KEYS) {\n\t\t\t\tif (key in data) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Response key \"${key}\" must only be present when e=\"rr\".`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// State-change events require their associated field\n\t\tfor (const [eventType, requiredField] of CMCD_STATE_EVENT_FIELDS) {\n\t\t\tif (data['e'] === eventType && !(requiredField in data)) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey: requiredField,\n\t\t\t\t\tmessage: `State-change event (e=\"${eventType}\") requires the \"${requiredField}\" key to be present.`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\t// Error event requires ec\n\t\tif (data['e'] === CMCD_EVENT_ERROR && !('ec' in data)) {\n\t\t\tissues.push({\n\t\t\t\tkey: 'ec',\n\t\t\t\tmessage: 'Error event (e=\"e\") requires the \"ec\" key to be present.',\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t})\n\t\t}\n\t}\n\n\t// Version key checks\n\tif ('v' in data && data['v'] !== 1 && data['v'] !== 2) {\n\t\tissues.push({\n\t\t\tkey: 'v',\n\t\t\tmessage: `Unsupported CMCD version \"${String(data['v'])}\". Expected 1 or 2.`,\n\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t})\n\t}\n\telse if (version > 1 && !('v' in data)) {\n\t\tissues.push({\n\t\t\tkey: 'v',\n\t\t\tmessage: 'Version 2 payloads require the \"v\" key to be present.',\n\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t})\n\t}\n\telse if (version === CMCD_V1 && 'v' in data) {\n\t\tissues.push({\n\t\t\tkey: 'v',\n\t\t\tmessage: 'Version 1 payloads should omit the \"v\" key (v1 is the default).',\n\t\t\tseverity: CMCD_VALIDATION_SEVERITY_WARNING\n\t\t})\n\t}\n\n\treturn {\n\t\tvalid: issues.every(i => i.severity !== CMCD_VALIDATION_SEVERITY_ERROR),\n\t\tissues,\n\t}\n}\n","/**\n * CMCD key value type: inner list of numbers with token identifiers.\n *\n * @internal\n */\nexport const CMCD_KEY_TYPE_NUMBER_LIST = 'number[]' as const\n\n/**\n * CMCD key value type: inner list of strings.\n *\n * @internal\n */\nexport const CMCD_KEY_TYPE_STRING_LIST = 'string[]' as const\n\n/**\n * CMCD key value type: integer.\n *\n * @internal\n */\nexport const CMCD_KEY_TYPE_INTEGER = 'integer' as const\n\n/**\n * CMCD key value type: number (decimal).\n *\n * @internal\n */\nexport const CMCD_KEY_TYPE_NUMBER = 'number' as const\n\n/**\n * CMCD key value type: boolean.\n *\n * @internal\n */\nexport const CMCD_KEY_TYPE_BOOLEAN = 'boolean' as const\n\n/**\n * CMCD key value type: string.\n *\n * @internal\n */\nexport const CMCD_KEY_TYPE_STRING = 'string' as const\n\n/**\n * CMCD key value type: token.\n *\n * @internal\n */\nexport const CMCD_KEY_TYPE_TOKEN = 'token' as const\n\n/**\n * Maps each CMCD spec key to its expected value type for v2.\n * Keys that differ between v1 and v2 are handled by CMCD_V1_KEY_TYPE_OVERRIDES.\n *\n * @internal\n */\nexport const CMCD_KEY_TYPES: Record<string, string> = {\n\t// List keys (inner list of integers/numbers with token identifiers)\n\tab: CMCD_KEY_TYPE_NUMBER_LIST,\n\tbl: CMCD_KEY_TYPE_NUMBER_LIST,\n\tbr: CMCD_KEY_TYPE_NUMBER_LIST,\n\tbsa: CMCD_KEY_TYPE_NUMBER_LIST,\n\tbsd: CMCD_KEY_TYPE_NUMBER_LIST,\n\tbsda: CMCD_KEY_TYPE_NUMBER_LIST,\n\tlab: CMCD_KEY_TYPE_NUMBER_LIST,\n\tlb: CMCD_KEY_TYPE_NUMBER_LIST,\n\tmtp: CMCD_KEY_TYPE_NUMBER_LIST,\n\tpb: CMCD_KEY_TYPE_NUMBER_LIST,\n\ttab: CMCD_KEY_TYPE_NUMBER_LIST,\n\ttb: CMCD_KEY_TYPE_NUMBER_LIST,\n\ttbl: CMCD_KEY_TYPE_NUMBER_LIST,\n\ttpb: CMCD_KEY_TYPE_NUMBER_LIST,\n\n\t// String array keys (inner list of strings)\n\tec: CMCD_KEY_TYPE_STRING_LIST,\n\tnor: CMCD_KEY_TYPE_STRING_LIST,\n\n\t// Integer keys\n\td: CMCD_KEY_TYPE_INTEGER,\n\tdfa: CMCD_KEY_TYPE_INTEGER,\n\tdl: CMCD_KEY_TYPE_INTEGER,\n\tltc: CMCD_KEY_TYPE_INTEGER,\n\tmsd: CMCD_KEY_TYPE_INTEGER,\n\tpt: CMCD_KEY_TYPE_INTEGER,\n\trc: CMCD_KEY_TYPE_INTEGER,\n\trtp: CMCD_KEY_TYPE_INTEGER,\n\tsn: CMCD_KEY_TYPE_INTEGER,\n\tts: CMCD_KEY_TYPE_INTEGER,\n\tttfb: CMCD_KEY_TYPE_INTEGER,\n\tttfbb: CMCD_KEY_TYPE_INTEGER,\n\tttlb: CMCD_KEY_TYPE_INTEGER,\n\tv: CMCD_KEY_TYPE_INTEGER,\n\n\t// Number keys\n\tpr: CMCD_KEY_TYPE_NUMBER,\n\n\t// Boolean keys\n\tbg: CMCD_KEY_TYPE_BOOLEAN,\n\tbs: CMCD_KEY_TYPE_BOOLEAN,\n\tnr: CMCD_KEY_TYPE_BOOLEAN,\n\tsu: CMCD_KEY_TYPE_BOOLEAN,\n\n\t// String keys\n\tcdn: CMCD_KEY_TYPE_STRING,\n\tcen: CMCD_KEY_TYPE_STRING,\n\tcid: CMCD_KEY_TYPE_STRING,\n\tcmsdd: CMCD_KEY_TYPE_STRING,\n\tcmsds: CMCD_KEY_TYPE_STRING,\n\tcs: CMCD_KEY_TYPE_STRING,\n\th: CMCD_KEY_TYPE_STRING,\n\tnrr: CMCD_KEY_TYPE_STRING,\n\tsid: CMCD_KEY_TYPE_STRING,\n\tsmrt: CMCD_KEY_TYPE_STRING,\n\turl: CMCD_KEY_TYPE_STRING,\n\n\t// Token keys\n\te: CMCD_KEY_TYPE_TOKEN,\n\tot: CMCD_KEY_TYPE_TOKEN,\n\tsf: CMCD_KEY_TYPE_TOKEN,\n\tst: CMCD_KEY_TYPE_TOKEN,\n\tsta: CMCD_KEY_TYPE_TOKEN,\n}\n\n/**\n * Maps keys to their v1-specific types when they differ from v2.\n *\n * @internal\n */\nexport const CMCD_V1_KEY_TYPE_OVERRIDES: Record<string, string> = {\n\tbl: CMCD_KEY_TYPE_INTEGER,\n\tbr: CMCD_KEY_TYPE_NUMBER,\n\tmtp: CMCD_KEY_TYPE_INTEGER,\n\ttb: CMCD_KEY_TYPE_NUMBER,\n\tnor: CMCD_KEY_TYPE_STRING,\n}\n","/**\n * Maps CMCD keys to their maximum string length.\n *\n * @internal\n */\nexport const CMCD_STRING_LENGTH_LIMITS: Record<string, number> = {\n\tsid: 64,\n\tcid: 128,\n\tcdn: 128,\n\th: 128,\n\tcen: 64,\n}\n\n/**\n * Maximum length for custom key values.\n *\n * @internal\n */\nexport const CMCD_CUSTOM_KEY_VALUE_MAX_LENGTH = 64\n","/**\n * Maps token keys to their valid values.\n *\n * @internal\n */\nexport const CMCD_TOKEN_VALUES: Record<string, readonly string[]> = {\n\te: ['bc', 'ps', 'pr', 'e', 't', 'c', 'b', 'm', 'um', 'pe', 'pc', 'rr', 'as', 'ae', 'abs', 'abe', 'sk', 'ce'] as const,\n\tot: ['m', 'a', 'v', 'av', 'i', 'c', 'tt', 'k', 'o'] as const,\n\tsf: ['d', 'h', 's', 'o'] as const,\n\tst: ['v', 'l', 'll'] as const,\n\tsta: ['s', 'p', 'k', 'r', 'a', 'w', 'e', 'f', 'q', 'd'] as const,\n}\n","import { SfItem } from '@svta/cml-structured-field-values'\nimport { CMCD_KEY_TYPE_BOOLEAN, CMCD_KEY_TYPE_INTEGER, CMCD_KEY_TYPE_NUMBER, CMCD_KEY_TYPE_NUMBER_LIST, CMCD_KEY_TYPE_STRING, CMCD_KEY_TYPE_STRING_LIST, CMCD_KEY_TYPE_TOKEN, CMCD_KEY_TYPES, CMCD_V1_KEY_TYPE_OVERRIDES } from './CMCD_KEY_TYPES.ts'\nimport { CMCD_CUSTOM_KEY_VALUE_MAX_LENGTH, CMCD_STRING_LENGTH_LIMITS } from './CMCD_STRING_LENGTH_LIMITS.ts'\nimport { CMCD_TOKEN_VALUES } from './CMCD_TOKEN_VALUES.ts'\nimport { CMCD_V1 } from './CMCD_V1.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\nimport type { CmcdValidationIssue } from './CmcdValidationIssue.ts'\nimport type { CmcdValidationOptions } from './CmcdValidationOptions.ts'\nimport type { CmcdValidationResult } from './CmcdValidationResult.ts'\nimport { CMCD_VALIDATION_SEVERITY_ERROR, CMCD_VALIDATION_SEVERITY_WARNING } from './CmcdValidationSeverity.ts'\nimport { isCmcdCustomKey } from './isCmcdCustomKey.ts'\nimport { resolveVersion } from './resolveVersion.ts'\n\nconst HUNDRED_ROUNDING_KEYS = /* @__PURE__ */ new Set(['bl', 'dl', 'mtp', 'rtp', 'tbl'])\nconst INTEGER_ROUNDING_KEYS = /* @__PURE__ */ new Set(['br', 'd', 'tb'])\n\nfunction isFiniteNumber(value: unknown): value is number {\n\treturn typeof value === 'number' && Number.isFinite(value)\n}\n\nfunction validateListValue(key: string, value: unknown, issues: CmcdValidationIssue[]): void {\n\tif (!Array.isArray(value)) {\n\t\tissues.push({\n\t\t\tkey,\n\t\t\tmessage: `Key \"${key}\" must be an array.`,\n\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t})\n\t\treturn\n\t}\n\tfor (let i = 0; i < value.length; i++) {\n\t\tconst element = value[i]\n\t\tif (element instanceof SfItem) {\n\t\t\tif (!isFiniteNumber(element.value)) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey,\n\t\t\t\t\tmessage: `Key \"${key}\" array element [${i}] must be a finite number.`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\telse if (!isFiniteNumber(element)) {\n\t\t\tissues.push({\n\t\t\t\tkey,\n\t\t\t\tmessage: `Key \"${key}\" array element [${i}] must be a finite number.`,\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t})\n\t\t}\n\t}\n}\n\nfunction validateStringArrayValue(key: string, value: unknown, issues: CmcdValidationIssue[]): void {\n\tif (!Array.isArray(value)) {\n\t\tissues.push({\n\t\t\tkey,\n\t\t\tmessage: `Key \"${key}\" must be an array.`,\n\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t})\n\t\treturn\n\t}\n\tfor (let i = 0; i < value.length; i++) {\n\t\tconst element = value[i]\n\t\tif (element instanceof SfItem) {\n\t\t\tif (typeof element.value !== 'string') {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey,\n\t\t\t\t\tmessage: `Key \"${key}\" array element [${i}] must be a string.`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\telse if (typeof element !== 'string') {\n\t\t\tissues.push({\n\t\t\t\tkey,\n\t\t\t\tmessage: `Key \"${key}\" array element [${i}] must be a string.`,\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t})\n\t\t}\n\t}\n}\n\n/**\n * Validates that all values in a CMCD payload conform to the expected types and constraints.\n *\n * @example\n * {@includeCode ../test/validateCmcdValues.test.ts#example}\n *\n * @param data - The CMCD payload to validate.\n * @param options - Validation options.\n * @returns The validation result.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#reserved-keys | CTA-5004-B Reserved Keys}\n *\n * @public\n */\nexport function validateCmcdValues(data: Record<string, unknown>, options?: CmcdValidationOptions): CmcdValidationResult {\n\tconst version = resolveVersion(data, options)\n\tconst issues: CmcdValidationIssue[] = []\n\n\tfor (const [key, value] of Object.entries(data)) {\n\t\tif (isCmcdCustomKey(key as CmcdKey)) {\n\t\t\t// Custom key values must be string or token, max 64 chars\n\t\t\tif (typeof value !== 'string') {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey,\n\t\t\t\t\tmessage: `Custom key \"${key}\" value must be a string or token.`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t\telse if (value.length > CMCD_CUSTOM_KEY_VALUE_MAX_LENGTH) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey,\n\t\t\t\t\tmessage: `Custom key \"${key}\" value exceeds maximum length of ${CMCD_CUSTOM_KEY_VALUE_MAX_LENGTH}.`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// Version value check\n\t\tif (key === 'v') {\n\t\t\tif (value !== 1 && value !== 2) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey,\n\t\t\t\t\tmessage: `Key \"v\" must be 1 or 2.`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// Determine expected type\n\t\tlet expectedType = CMCD_KEY_TYPES[key]\n\t\tif (!expectedType) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif (version === CMCD_V1 && key in CMCD_V1_KEY_TYPE_OVERRIDES) {\n\t\t\texpectedType = CMCD_V1_KEY_TYPE_OVERRIDES[key]\n\t\t}\n\n\t\tswitch (expectedType) {\n\t\t\tcase CMCD_KEY_TYPE_INTEGER:\n\t\t\t\tif (!isFiniteNumber(value) || !Number.isInteger(value)) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Key \"${key}\" must be a finite integer.`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\telse if (HUNDRED_ROUNDING_KEYS.has(key) && (value as number) % 100 !== 0) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Key \"${key}\" should be rounded to the nearest 100.`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_WARNING\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tbreak\n\n\t\t\tcase CMCD_KEY_TYPE_NUMBER:\n\t\t\t\tif (!isFiniteNumber(value)) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Key \"${key}\" must be a finite number.`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\telse if (HUNDRED_ROUNDING_KEYS.has(key) && (value as number) % 100 !== 0) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Key \"${key}\" should be rounded to the nearest 100.`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_WARNING\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\telse if (INTEGER_ROUNDING_KEYS.has(key) && !Number.isInteger(value)) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Key \"${key}\" should be rounded to an integer.`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_WARNING\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tbreak\n\n\t\t\tcase CMCD_KEY_TYPE_BOOLEAN:\n\t\t\t\tif (typeof value !== 'boolean') {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Key \"${key}\" must be a boolean.`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tbreak\n\n\t\t\tcase CMCD_KEY_TYPE_STRING:\n\t\t\t\tif (typeof value !== 'string') {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Key \"${key}\" must be a string.`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\telse if (key in CMCD_STRING_LENGTH_LIMITS && value.length > CMCD_STRING_LENGTH_LIMITS[key]) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Key \"${key}\" exceeds maximum length of ${CMCD_STRING_LENGTH_LIMITS[key]}.`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tbreak\n\n\t\t\tcase CMCD_KEY_TYPE_TOKEN: {\n\t\t\t\tconst validValues = CMCD_TOKEN_VALUES[key]\n\t\t\t\tif (validValues && !validValues.includes(value as string)) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Key \"${key}\" has invalid token value \"${String(value)}\". Expected one of: ${validValues.join(', ')}.`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcase CMCD_KEY_TYPE_NUMBER_LIST:\n\t\t\t\tvalidateListValue(key, value, issues)\n\t\t\t\tbreak\n\n\t\t\tcase CMCD_KEY_TYPE_STRING_LIST:\n\t\t\t\tvalidateStringArrayValue(key, value, issues)\n\t\t\t\tbreak\n\t\t}\n\t}\n\n\treturn {\n\t\tvalid: issues.every(i => i.severity !== CMCD_VALIDATION_SEVERITY_ERROR),\n\t\tissues,\n\t}\n}\n","import type { CmcdValidationOptions } from './CmcdValidationOptions.ts'\nimport type { CmcdValidationResult } from './CmcdValidationResult.ts'\nimport { mergeValidationResults } from './mergeValidationResults.ts'\nimport { validateCmcdKeys } from './validateCmcdKeys.ts'\nimport { validateCmcdStructure } from './validateCmcdStructure.ts'\nimport { validateCmcdValues } from './validateCmcdValues.ts'\n\n/**\n * Validates a CMCD payload by checking keys, values, and structure.\n *\n * @example\n * {@includeCode ../test/validateCmcd.test.ts#example}\n *\n * @param data - The CMCD payload to validate.\n * @param options - Validation options.\n * @returns The validation result.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#data-payload-definition-what-data-to-send | CTA-5004-B Data Payload Definition}\n *\n * @public\n */\nexport function validateCmcd(data: Record<string, unknown>, options?: CmcdValidationOptions): CmcdValidationResult {\n\treturn mergeValidationResults(\n\t\tvalidateCmcdKeys(data, options),\n\t\tvalidateCmcdValues(data, options),\n\t\tvalidateCmcdStructure(data, options),\n\t)\n}\n","import type { CmcdData } from './CmcdData.ts'\nimport type { CmcdEventsValidationResult } from './CmcdEventsValidationResult.ts'\nimport { CMCD_EVENT_MODE } from './CmcdReportingMode.ts'\nimport type { CmcdValidationOptions } from './CmcdValidationOptions.ts'\nimport type { CmcdValidationResult } from './CmcdValidationResult.ts'\nimport { CMCD_VALIDATION_SEVERITY_ERROR } from './CmcdValidationSeverity.ts'\nimport { decodeCmcd } from './decodeCmcd.ts'\nimport { mergeValidationResults } from './mergeValidationResults.ts'\nimport { validateCmcd } from './validateCmcd.ts'\n\n/**\n * Validates a raw CMCD string as an event-mode payload.\n *\n * This function decodes the string internally and validates it with\n * `reportingMode` set to `'event'`. The input may contain multiple\n * newline-separated events (e.g. an `application/cmcd` POST body), in which\n * case each line is validated independently and the results are merged.\n *\n * @param cmcd - The raw CMCD-encoded string to validate. May contain\n * multiple newline-separated event lines.\n * @param options - Validation options (excluding `reportingMode`).\n * @returns The validation result including decoded data per event line.\n *\n * @example\n * {@includeCode ../test/validateCmcdEvents.test.ts#example}\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#body-definition | CTA-5004-B Body Definition}\n *\n * @public\n */\nexport function validateCmcdEvents(cmcd: string, options?: Omit<CmcdValidationOptions, 'reportingMode'>): CmcdEventsValidationResult {\n\tconst opts = { ...options, reportingMode: CMCD_EVENT_MODE } as const\n\tconst lines = cmcd.split(/\\r?\\n/).filter(line => line.length > 0)\n\n\tif (lines.length === 0) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tissues: [{\n\t\t\t\tmessage: 'Empty event mode payload. At least one event line is required.',\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t\t}],\n\t\t\tdata: [],\n\t\t}\n\t}\n\n\tconst decodedLines: CmcdData[] = []\n\tconst lineResults: CmcdValidationResult[] = []\n\n\tfor (let i = 0; i < lines.length; i++) {\n\t\ttry {\n\t\t\tconst data = decodeCmcd(lines[i])\n\t\t\tdecodedLines.push(data)\n\t\t\tlineResults.push(validateCmcd(data, opts))\n\t\t} catch {\n\t\t\tdecodedLines.push({} as CmcdData)\n\t\t\tlineResults.push({\n\t\t\t\tvalid: false,\n\t\t\t\tissues: [{\n\t\t\t\t\tmessage: `Failed to decode event line ${i + 1}: invalid structured field syntax.`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t\t\t}],\n\t\t\t})\n\t\t}\n\t}\n\n\tconst result = mergeValidationResults(...lineResults)\n\treturn { ...result, data: decodedLines }\n}\n","import type { HttpRequest } from '@svta/cml-utils'\nimport { CMCD_MIME_TYPE } from './CMCD_MIME_TYPE.ts'\nimport type { CmcdEventsValidationResult } from './CmcdEventsValidationResult.ts'\nimport type { CmcdValidationOptions } from './CmcdValidationOptions.ts'\nimport { CMCD_VALIDATION_SEVERITY_ERROR } from './CmcdValidationSeverity.ts'\nimport { ensureHeaders } from './ensureHeaders.ts'\nimport { validateCmcdEvents } from './validateCmcdEvents.ts'\n\n/**\n * Validates a full HTTP request as an event-mode payload.\n *\n * Accepts an {@link @svta/cml-utils!HttpRequest | HttpRequest} object.\n *\n * This function validates that the request uses the POST method and has\n * the correct `Content-Type` header (`application/cmcd`) in addition to\n * validating the body content via {@link validateCmcdEvents}.\n *\n * @param request - An `HttpRequest` to validate.\n * @param options - Validation options (excluding `reportingMode`).\n * @returns The validation result including decoded data per event line.\n *\n * @example {@includeCode ../test/validateCmcdEventReport.test.ts#example}\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#event-mode | CTA-5004-B Event Mode}\n *\n * @public\n */\nexport function validateCmcdEventReport(request: HttpRequest, options?: Omit<CmcdValidationOptions, 'reportingMode'>): CmcdEventsValidationResult {\n\tconst issues: CmcdEventsValidationResult['issues'] = []\n\n\tif (request.method !== 'POST') {\n\t\tissues.push({\n\t\t\tmessage: `Invalid HTTP method '${request.method ?? 'GET'}'. Event reports must use POST.`,\n\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t})\n\t}\n\n\tconst contentType = request.headers ? ensureHeaders(request.headers).get('Content-Type') : undefined\n\n\tif (!contentType) {\n\t\tissues.push({\n\t\t\tmessage: `Missing Content-Type header. Event reports must use '${CMCD_MIME_TYPE}'.`,\n\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t})\n\t} else {\n\t\tconst mediaType = contentType.split(';')[0].trim().toLowerCase()\n\t\tif (mediaType !== CMCD_MIME_TYPE) {\n\t\t\tissues.push({\n\t\t\t\tmessage: `Invalid Content-Type '${mediaType}'. Event reports must use '${CMCD_MIME_TYPE}'.`,\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t\t})\n\t\t}\n\t}\n\n\tconst body = request.body\n\tif (body === undefined || body === null) {\n\t\tissues.push({\n\t\t\tmessage: 'Missing request body. Event reports must include a body.',\n\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t})\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tissues,\n\t\t\tdata: [],\n\t\t}\n\t}\n\n\tif (typeof body !== 'string') {\n\t\tissues.push({\n\t\t\tmessage: 'Request body must be a string.',\n\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t})\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tissues,\n\t\t\tdata: [],\n\t\t}\n\t}\n\n\tconst bodyResult = validateCmcdEvents(body, options)\n\n\treturn {\n\t\tvalid: issues.length === 0 && bodyResult.valid,\n\t\tissues: [...issues, ...bodyResult.issues],\n\t\tdata: bodyResult.data,\n\t}\n}\n","import { CMCD_HEADER_MAP } from './CMCD_HEADER_MAP.ts'\nimport type { CmcdData } from './CmcdData.ts'\nimport type { CmcdDataValidationResult } from './CmcdDataValidationResult.ts'\nimport { type CmcdHeaderField, CMCD_HEADER_FIELDS } from './CmcdHeaderField.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\nimport { CMCD_REQUEST_MODE } from './CmcdReportingMode.ts'\nimport type { CmcdValidationOptions } from './CmcdValidationOptions.ts'\nimport type { CmcdValidationResult } from './CmcdValidationResult.ts'\nimport { CMCD_VALIDATION_SEVERITY_ERROR } from './CmcdValidationSeverity.ts'\nimport { decodeCmcd } from './decodeCmcd.ts'\nimport { ensureHeaders } from './ensureHeaders.ts'\nimport { isCmcdCustomKey } from './isCmcdCustomKey.ts'\nimport { mergeValidationResults } from './mergeValidationResults.ts'\nimport { validateCmcd } from './validateCmcd.ts'\n\n/**\n * Validates CMCD HTTP headers by checking shard placement and payload validity.\n *\n * This function accepts raw CMCD header strings, decodes each shard\n * internally, verifies that each key is placed in its correct header shard,\n * then merges all shards and runs full payload validation (keys, values, and\n * structure) on the merged data.\n *\n * @example\n * {@includeCode ../test/validateCmcdHeaders.test.ts#example}\n *\n * @param headers - A `Headers` instance or a record of CMCD header fields to their raw encoded string values.\n * @param options - Validation options (excluding `reportingMode`).\n * @returns The validation result including decoded data.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#header-field-definition | CTA-5004-B Header Field Definition}\n *\n * @public\n */\nexport function validateCmcdHeaders(headers: Record<string, string> | Headers, options?: Omit<CmcdValidationOptions, 'reportingMode'>): CmcdDataValidationResult {\n\tconst h = ensureHeaders(headers)\n\tconst issues: CmcdValidationResult['issues'] = []\n\tconst decoded: Partial<Record<CmcdHeaderField, Record<string, unknown>>> = {}\n\n\tfor (const headerField of CMCD_HEADER_FIELDS) {\n\t\tconst raw = h.get(headerField)\n\t\tif (!raw) {\n\t\t\tcontinue\n\t\t}\n\n\t\tlet shard: Record<string, unknown>\n\t\ttry {\n\t\t\tshard = decodeCmcd(raw)\n\t\t} catch {\n\t\t\tissues.push({\n\t\t\t\tkey: headerField,\n\t\t\t\tmessage: `Failed to decode \"${headerField}\" header: invalid structured field syntax.`,\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\t\tdecoded[headerField] = shard\n\n\t\tfor (const key of Object.keys(shard)) {\n\t\t\tif (isCmcdCustomKey(key as CmcdKey)) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconst expectedHeader = CMCD_HEADER_MAP[key as keyof typeof CMCD_HEADER_MAP]\n\t\t\tif (expectedHeader && expectedHeader !== headerField) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey,\n\t\t\t\t\tmessage: `Key \"${key}\" is in \"${headerField}\" but should be in \"${expectedHeader}\".`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\tconst shardResult: CmcdValidationResult = {\n\t\tvalid: issues.length === 0,\n\t\tissues,\n\t}\n\n\tconst merged: Record<string, unknown> = Object.assign({}, ...CMCD_HEADER_FIELDS.map(f => decoded[f]).filter(Boolean))\n\tconst payloadResult = validateCmcd(merged, { ...options, reportingMode: CMCD_REQUEST_MODE })\n\n\tconst result = mergeValidationResults(shardResult, payloadResult)\n\treturn { ...result, data: merged as CmcdData }\n}\n","import type { HttpRequest } from '@svta/cml-utils'\nimport { CMCD_PARAM } from './CMCD_PARAM.ts'\nimport type { CmcdData } from './CmcdData.ts'\nimport type { CmcdDataValidationResult } from './CmcdDataValidationResult.ts'\nimport { type CmcdHeaderField, CMCD_HEADER_FIELDS } from './CmcdHeaderField.ts'\nimport { CMCD_REQUEST_MODE } from './CmcdReportingMode.ts'\nimport type { CmcdValidationOptions } from './CmcdValidationOptions.ts'\nimport { CMCD_VALIDATION_SEVERITY_ERROR } from './CmcdValidationSeverity.ts'\nimport { decodeCmcd } from './decodeCmcd.ts'\nimport { ensureHeaders } from './ensureHeaders.ts'\nimport { validateCmcd } from './validateCmcd.ts'\nimport { validateCmcdHeaders } from './validateCmcdHeaders.ts'\n\n/**\n * Validates CMCD data from a request as a request-mode payload.\n *\n * Accepts a\n * {@link https://developer.mozilla.org/en-US/docs/Web/API/Request | Request}\n * object or an {@link @svta/cml-utils!HttpRequest | HttpRequest} object.\n *\n * The function checks for CMCD data in the HTTP headers first. If CMCD\n * headers are found, validation includes shard-placement checks via\n * {@link validateCmcdHeaders}. Otherwise, the CMCD query parameter is\n * extracted from the URL and validated.\n *\n * @param request - A `Request` or `HttpRequest` to validate.\n * @param options - Validation options (excluding `reportingMode`).\n * @returns The validation result including decoded data.\n *\n * @example\n * {@includeCode ../test/validateCmcdRequest.test.ts#example}\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#request-mode | CTA-5004-B Request Mode}\n *\n * @public\n */\nexport function validateCmcdRequest(request: Request | HttpRequest, options?: Omit<CmcdValidationOptions, 'reportingMode'>): CmcdDataValidationResult {\n\tconst headers = extractHeaderRecord(request.headers)\n\n\tif (headers) {\n\t\treturn validateCmcdHeaders(headers, options)\n\t}\n\n\tconst param = new URL(request.url).searchParams.get(CMCD_PARAM)\n\n\tif (!param) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tissues: [{\n\t\t\t\tmessage: 'No CMCD data found in request headers or query parameters.',\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t\t}],\n\t\t\tdata: {} as CmcdData,\n\t\t}\n\t}\n\n\tlet data: CmcdData\n\ttry {\n\t\tdata = decodeCmcd(param)\n\t} catch {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tissues: [{\n\t\t\t\tmessage: 'Failed to decode CMCD query parameter: invalid structured field syntax.',\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t\t}],\n\t\t\tdata: {} as CmcdData,\n\t\t}\n\t}\n\n\tconst result = validateCmcd(data, { ...options, reportingMode: CMCD_REQUEST_MODE })\n\treturn { ...result, data }\n}\n\nfunction extractHeaderRecord(headers: Headers | Record<string, string> | undefined): Partial<Record<CmcdHeaderField, string>> | undefined {\n\tif (!headers) {\n\t\treturn undefined\n\t}\n\n\tconst h = ensureHeaders(headers)\n\tconst result: Partial<Record<CmcdHeaderField, string>> = {}\n\tlet found = false\n\n\tfor (const field of CMCD_HEADER_FIELDS) {\n\t\tconst value = h.get(field)\n\n\t\tif (value) {\n\t\t\tresult[field] = value\n\t\t\tfound = true\n\t\t}\n\t}\n\n\treturn found ? result : undefined\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["CMCD_FORMATTER_MAP: Record<string, CmcdFormatter>","CMCD_STATE_EVENT_FIELDS: ReadonlyMap<CmcdEventType, CmcdKey>","CMCD_REQUEST_KEY_SET: ReadonlySet<string>","CMCD_RESPONSE_KEY_SET: ReadonlySet<string>","CMCD_EVENT_KEY_SET: ReadonlySet<string>","CMCD_INNER_LIST_KEYS: Set<string>","CMCD_V1_KEY_SET: ReadonlySet<string>","CMCD_V1_KEY_SET","filterMap: Record<string, (key: string) => boolean>","item: any","item","result: Record<string, any>","results: Cmcd","formatterOptions: CmcdFormatterOptions","CMCD_HEADER_FIELDS: readonly CmcdHeaderField[]","CMCD_HEADER_MAP: Record<CmcdRequestKey | 'nrr', CmcdHeaderField>","custom: Partial<Record<CmcdHeaderKey, CmcdHeaderField>>","CMCD_KEYS: CmcdKey[]","CMCD_REQUEST_PROVENANCE: unique symbol","headers: Record<string, string>","body: string | undefined","ProgressEventCtor: typeof ProgressEvent | typeof Event","#deliver","#eventTargetUrls","captured: CmcdRecordedReport","#reports","#onReport","#notifyWaiters","#waiters","#getMatching","#waitTimeout","#attached","#detachers","#waitFor","result: Record<string, any>","result: Record<string, unknown>","STATE_FIELDS: readonly StateFieldEntry[]","STATE_FIELDS_BY_EVENT: ReadonlyMap<CmcdEventType, StateFieldEntry>","CMCD_REQUIRED_EVENT_KEYS: ReadonlyMap<CmcdEventType, CmcdKey>","failure: { error: unknown; } | undefined","item: Cmcd","derived: Partial<Cmcd>","merged: Cmcd","cmcdData: Cmcd | null","result: Record<string, unknown>","CMCD_V1_KEY_SET: ReadonlySet<string>","CMCD_KEY_SET: ReadonlySet<string>","issues: CmcdValidationResult['issues']","issues: CmcdValidationIssue[]","CMCD_KEY_TYPES: Record<string, string>","CMCD_V1_KEY_TYPE_OVERRIDES: Record<string, string>","CMCD_STRING_LENGTH_LIMITS: Record<string, number>","CMCD_TOKEN_VALUES: Record<string, readonly string[]>","issues: CmcdValidationIssue[]","decodedLines: CmcdData[]","lineResults: CmcdValidationResult[]","issues: CmcdEventsValidationResult['issues']","issues: CmcdValidationResult['issues']","decoded: Partial<Record<CmcdHeaderField, Record<string, unknown>>>","shard: Record<string, unknown>","shardResult: CmcdValidationResult","merged: Record<string, unknown>","data: CmcdData","result: Partial<Record<CmcdHeaderField, string>>"],"sources":["../src/CMCD_FORMATTER_MAP.ts","../src/CMCD_V2.ts","../src/CmcdEventType.ts","../src/CMCD_STATE_EVENT_FIELDS.ts","../src/CmcdReportingMode.ts","../src/CMCD_EVENT_KEYS.ts","../src/CMCD_REQUEST_KEYS.ts","../src/isCmcdCustomKey.ts","../src/isCmcdRequestKey.ts","../src/CMCD_RESPONSE_KEYS.ts","../src/isCmcdResponseReceivedKey.ts","../src/isCmcdEventKey.ts","../src/CMCD_INNER_LIST_KEYS.ts","../src/CMCD_V1_KEYS.ts","../src/isCmcdV1Key.ts","../src/isTokenField.ts","../src/isValid.ts","../src/prepareCmcdData.ts","../src/CmcdHeaderField.ts","../src/CMCD_HEADER_MAP.ts","../src/groupCmcdHeaders.ts","../src/toPreparedCmcdHeaders.ts","../src/toCmcdHeaders.ts","../src/appendCmcdHeaders.ts","../src/CMCD_PARAM.ts","../src/encodePreparedCmcd.ts","../src/encodeCmcd.ts","../src/toCmcdUrl.ts","../src/toCmcdQuery.ts","../src/appendCmcdQuery.ts","../src/CMCD_DEFAULT_TIME_INTERVAL.ts","../src/CMCD_KEYS.ts","../src/CMCD_MIME_TYPE.ts","../src/CMCD_REQUEST_PROVENANCE.ts","../src/CMCD_V1.ts","../src/CmcdObjectType.ts","../src/CmcdPlayerState.ts","../src/CmcdRecordedReportMode.ts","../src/CmcdRecordedRequestType.ts","../src/createFetchTransport.ts","../src/createXhrTransport.ts","../src/CmcdReportRecorder.ts","../src/CmcdTransmissionMode.ts","../src/upConvertToV2.ts","../src/decodeCmcd.ts","../src/CmcdReporter.ts","../src/CmcdStreamingFormat.ts","../src/CmcdStreamType.ts","../src/CmcdValidationSeverity.ts","../src/ensureHeaders.ts","../src/fromCmcdHeaders.ts","../src/fromCmcdQuery.ts","../src/fromCmcdUrl.ts","../src/isCmcdV1Data.ts","../src/isCmcdV2Data.ts","../src/toCmcdValue.ts","../src/mergeValidationResults.ts","../src/resolveVersion.ts","../src/validateCmcdKeys.ts","../src/validateCmcdStructure.ts","../src/CMCD_KEY_TYPES.ts","../src/CMCD_STRING_LENGTH_LIMITS.ts","../src/CMCD_TOKEN_VALUES.ts","../src/validateCmcdValues.ts","../src/validateCmcd.ts","../src/validateCmcdEvents.ts","../src/validateCmcdEventReport.ts","../src/validateCmcdHeaders.ts","../src/validateCmcdRequest.ts"],"sourcesContent":["import { SfItem } from '@svta/cml-structured-field-values'\nimport { getBaseUrl, urlToRelativePath, type ValueOrArray } from '@svta/cml-utils'\nimport type { CmcdFormatter } from './CmcdFormatter.ts'\nimport type { CmcdFormatterOptions } from './CmcdFormatterOptions.ts'\nimport type { CmcdValue } from './CmcdValue.ts'\n\nconst roundValue = (value: CmcdValue): number | SfItem<number> => {\n\tif (value instanceof SfItem) {\n\t\treturn new SfItem(Math.round(value.value as number), value.params)\n\t}\n\treturn Math.round(value as number)\n}\n\nconst toRounded = (value: CmcdValue) => {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(roundValue)\n\t}\n\treturn roundValue(value)\n}\n\nconst toUrlSafe = (value: CmcdValue, options: CmcdFormatterOptions): ValueOrArray<string | SfItem<string>> => {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(item => toUrlSafe(item, options) as string)\n\t}\n\n\tif (value instanceof SfItem && typeof value.value === 'string') {\n\t\treturn new SfItem(toUrlSafe(value.value, options), value.params)\n\t}\n\telse {\n\t\tif (options.baseUrl) {\n\t\t\tvalue = urlToRelativePath(value as string, getBaseUrl(options.baseUrl))\n\t\t}\n\t\treturn options.version === 1 ? encodeURIComponent(value as string) : (value as string)\n\t}\n}\n\nconst hundredValue = (value: CmcdValue): number | SfItem<number> => {\n\tif (value instanceof SfItem) {\n\t\treturn new SfItem(Math.round((value.value as number) / 100) * 100, value.params)\n\t}\n\treturn Math.round((value as number) / 100) * 100\n}\n\nconst toHundred = (value: CmcdValue) => {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(hundredValue)\n\t}\n\treturn hundredValue(value)\n}\n\nconst nor = (value: CmcdValue, options: CmcdFormatterOptions) => {\n\tlet norValue = value\n\n\tif (options.version >= 2) {\n\t\tif (value instanceof SfItem && typeof value.value === 'string') {\n\t\t\tnorValue = new SfItem([value])\n\t\t}\n\t\telse if (typeof value === 'string') {\n\t\t\tnorValue = [value]\n\t\t}\n\t}\n\n\treturn toUrlSafe(norValue, options)\n}\n\n/**\n * The default formatters for CMCD values.\n *\n * @public\n */\nexport const CMCD_FORMATTER_MAP: Record<string, CmcdFormatter> = {\n\t/**\n\t * Bitrate (kbps) rounded integer\n\t */\n\tbr: toRounded,\n\n\t/**\n\t * Duration (milliseconds) rounded integer\n\t */\n\td: toRounded,\n\n\t/**\n\t * Buffer Length (milliseconds) rounded nearest 100ms\n\t */\n\tbl: toHundred,\n\n\t/**\n\t * Deadline (milliseconds) rounded nearest 100ms\n\t */\n\tdl: toHundred,\n\n\t/**\n\t * Measured Throughput (kbps) rounded nearest 100kbps\n\t */\n\tmtp: toHundred,\n\n\t/**\n\t * Next Object Request URL encoded\n\t */\n\tnor,\n\n\t/**\n\t * Requested maximum throughput (kbps) rounded nearest 100kbps\n\t */\n\trtp: toHundred,\n\n\t/**\n\t * Top Bitrate (kbps) rounded integer\n\t */\n\ttb: toRounded,\n} as const\n","/**\n * CMCD Version 2\n *\n * @public\n */\nexport const CMCD_V2 = 2 as const\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * CMCD event type for the 'bc' key (bitrate change).\n *\n * @public\n */\nexport const CMCD_EVENT_BITRATE_CHANGE = 'bc' as const\n\n/**\n * CMCD event type for the 'ps' key (play state change).\n *\n * @public\n */\nexport const CMCD_EVENT_PLAY_STATE = 'ps' as const\n\n/**\n * CMCD event type for the 'pr' key (playback rate change).\n *\n * @public\n */\nexport const CMCD_EVENT_PLAYBACK_RATE = 'pr' as const\n\n/**\n * CMCD event type for the 'e' key (error).\n *\n * @public\n */\nexport const CMCD_EVENT_ERROR = 'e' as const\n\n/**\n * CMCD event type for the 't' key (time interval).\n *\n * @public\n */\nexport const CMCD_EVENT_TIME_INTERVAL = 't' as const\n\n/**\n * CMCD event type for the 'c' key (content ID).\n *\n * @public\n */\nexport const CMCD_EVENT_CONTENT_ID = 'c' as const\n\n/**\n * CMCD event type for the 'b' key (backgrounded mode).\n *\n * @public\n */\nexport const CMCD_EVENT_BACKGROUNDED_MODE = 'b' as const\n\n/**\n * CMCD event type for the 'm' key (mute).\n *\n * @public\n */\nexport const CMCD_EVENT_MUTE = 'm' as const\n\n/**\n * CMCD event type for the 'um' key (unmute).\n *\n * @public\n */\nexport const CMCD_EVENT_UNMUTE = 'um' as const\n\n/**\n * CMCD event type for the 'pe' key (player expand).\n *\n * @public\n */\nexport const CMCD_EVENT_PLAYER_EXPAND = 'pe' as const\n\n/**\n * CMCD event type for the 'pc' key (player collapse).\n *\n * @public\n */\nexport const CMCD_EVENT_PLAYER_COLLAPSE = 'pc' as const\n\n/**\n * CMCD event type for the 'rr' key (response received).\n *\n * @public\n */\nexport const CMCD_EVENT_RESPONSE_RECEIVED = 'rr' as const\n\n/**\n * CMCD event type for the 'as' key (ad start).\n *\n * @public\n */\nexport const CMCD_EVENT_AD_START = 'as' as const\n\n/**\n * CMCD event type for the 'ae' key (ad end).\n *\n * @public\n */\nexport const CMCD_EVENT_AD_END = 'ae' as const\n\n/**\n * CMCD event type for the 'abs' key (ad break start).\n *\n * @public\n */\nexport const CMCD_EVENT_AD_BREAK_START = 'abs' as const\n\n/**\n * CMCD event type for the 'abe' key (ad break end).\n *\n * @public\n */\nexport const CMCD_EVENT_AD_BREAK_END = 'abe' as const\n\n/**\n * CMCD event type for the 'sk' key (skip).\n *\n * @public\n */\nexport const CMCD_EVENT_SKIP = 'sk' as const\n\n/**\n * CMCD event type for the 'ce' key (custom event).\n *\n * @public\n */\nexport const CMCD_EVENT_CUSTOM_EVENT = 'ce' as const\n\n/**\n * CMCD event types for the 'e' key (event mode).\n *\n * @enum\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#event | CTA-5004-B Event}\n *\n * @public\n */\nexport const CmcdEventType = {\n\t/**\n\t * A change in the bitrate.\n\t */\n\tBITRATE_CHANGE: CMCD_EVENT_BITRATE_CHANGE as typeof CMCD_EVENT_BITRATE_CHANGE,\n\n\t/**\n\t * A change in the player state.\n\t */\n\tPLAY_STATE: CMCD_EVENT_PLAY_STATE as typeof CMCD_EVENT_PLAY_STATE,\n\n\t/**\n\t * A change in the playback rate.\n\t */\n\tPLAYBACK_RATE: CMCD_EVENT_PLAYBACK_RATE as typeof CMCD_EVENT_PLAYBACK_RATE,\n\n\t/**\n\t * An error event.\n\t */\n\tERROR: CMCD_EVENT_ERROR as typeof CMCD_EVENT_ERROR,\n\n\t/**\n\t * A periodic report sent on a time interval.\n\t */\n\tTIME_INTERVAL: CMCD_EVENT_TIME_INTERVAL as typeof CMCD_EVENT_TIME_INTERVAL,\n\n\t/**\n\t * A change of the content ID.\n\t */\n\tCONTENT_ID: CMCD_EVENT_CONTENT_ID as typeof CMCD_EVENT_CONTENT_ID,\n\n\t/**\n\t * A change in the application's backgrounded state.\n\t */\n\tBACKGROUNDED_MODE: CMCD_EVENT_BACKGROUNDED_MODE as typeof CMCD_EVENT_BACKGROUNDED_MODE,\n\n\t/**\n\t * The player was muted.\n\t */\n\tMUTE: CMCD_EVENT_MUTE as typeof CMCD_EVENT_MUTE,\n\n\t/**\n\t * Player unmuted.\n\t */\n\tUNMUTE: CMCD_EVENT_UNMUTE as typeof CMCD_EVENT_UNMUTE,\n\n\t/**\n\t * The player view was expanded.\n\t */\n\tPLAYER_EXPAND: CMCD_EVENT_PLAYER_EXPAND as typeof CMCD_EVENT_PLAYER_EXPAND,\n\n\t/**\n\t * The player view was collapsed.\n\t */\n\tPLAYER_COLLAPSE: CMCD_EVENT_PLAYER_COLLAPSE as typeof CMCD_EVENT_PLAYER_COLLAPSE,\n\n\t/**\n\t * The receipt of a response.\n\t */\n\tRESPONSE_RECEIVED: CMCD_EVENT_RESPONSE_RECEIVED as typeof CMCD_EVENT_RESPONSE_RECEIVED,\n\n\t/**\n\t * The start of an ad.\n\t */\n\tAD_START: CMCD_EVENT_AD_START as typeof CMCD_EVENT_AD_START,\n\n\t/**\n\t * The end of an ad.\n\t */\n\tAD_END: CMCD_EVENT_AD_END as typeof CMCD_EVENT_AD_END,\n\n\t/**\n\t * The start of an ad break.\n\t */\n\tAD_BREAK_START: CMCD_EVENT_AD_BREAK_START as typeof CMCD_EVENT_AD_BREAK_START,\n\n\t/**\n\t * The end of an ad break.\n\t */\n\tAD_BREAK_END: CMCD_EVENT_AD_BREAK_END as typeof CMCD_EVENT_AD_BREAK_END,\n\n\t/**\n\t * The user skipped an ad.\n\t */\n\tSKIP: CMCD_EVENT_SKIP as typeof CMCD_EVENT_SKIP,\n\n\t/**\n\t * A custom event.\n\t */\n\tCUSTOM_EVENT: CMCD_EVENT_CUSTOM_EVENT as typeof CMCD_EVENT_CUSTOM_EVENT,\n} as const\n\n/**\n * @public\n */\nexport type CmcdEventType = ValueOf<typeof CmcdEventType>;\n","import {\n\tCMCD_EVENT_BACKGROUNDED_MODE,\n\tCMCD_EVENT_BITRATE_CHANGE,\n\tCMCD_EVENT_CONTENT_ID,\n\tCMCD_EVENT_PLAY_STATE,\n\tCMCD_EVENT_PLAYBACK_RATE,\n\ttype CmcdEventType,\n} from './CmcdEventType.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\n\n/**\n * Maps each state-change event type to the persistent field whose value\n * the event signals.\n *\n * Per CTA-5004-B, the state-change events `ps`, `pr`, `c`, `b`, `bc` are\n * state-transition markers and must carry the field whose value they signal.\n * Consumers force-include the field post-filter (`prepareCmcdData`), dedup\n * against its value (`CmcdReporter`), and check its presence in payloads\n * (`validateCmcdStructure`).\n *\n * Iteration order is load-bearing: `CmcdReporter.update()` fires state-change\n * events in map order when multiple tracked fields change in a single call.\n * Do not reorder entries without auditing reporter behavior.\n *\n * @internal\n */\nexport const CMCD_STATE_EVENT_FIELDS: ReadonlyMap<CmcdEventType, CmcdKey> = /* @__PURE__ */ new Map([\n\t[CMCD_EVENT_PLAY_STATE, 'sta'],\n\t[CMCD_EVENT_PLAYBACK_RATE, 'pr'],\n\t[CMCD_EVENT_CONTENT_ID, 'cid'],\n\t[CMCD_EVENT_BACKGROUNDED_MODE, 'bg'],\n\t[CMCD_EVENT_BITRATE_CHANGE, 'br'],\n])\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * CMCD event mode variable name.\n *\n * @public\n */\nexport const CMCD_EVENT_MODE = 'event' as const\n\n/**\n * CMCD request mode variable name.\n *\n * @public\n */\nexport const CMCD_REQUEST_MODE = 'request' as const\n\n/**\n * CMCD reporting mode types.\n *\n * @enum\n *\n * @public\n */\nexport const CmcdReportingMode = {\n\t/**\n\t * Request mode\n\t */\n\tREQUEST: CMCD_REQUEST_MODE as typeof CMCD_REQUEST_MODE,\n\n\t/**\n\t * Event mode\n\t */\n\tEVENT: CMCD_EVENT_MODE as typeof CMCD_EVENT_MODE,\n} as const\n\n/**\n * @public\n */\nexport type CmcdReportingMode = ValueOf<typeof CmcdReportingMode>;\n","/**\n * Defines the event-specific keys for CMCD (Common Media Client Data) version 2.\n *\n * @public\n */\nexport const CMCD_EVENT_KEYS = [\n\t'cen',\n\t'e',\n\t'h',\n\t'ts',\n] as const\n","/**\n * Defines the request-specific keys for CMCD (Common Media Client Data) version 2.\n *\n * @public\n */\nexport const CMCD_REQUEST_KEYS = [\n\t'ab',\n\t'bg',\n\t'bl',\n\t'br',\n\t'bs',\n\t'bsa',\n\t'bsd',\n\t'bsda',\n\t'cdn',\n\t'cid',\n\t'cs',\n\t'd',\n\t'dfa',\n\t'dl',\n\t'ec',\n\t'lab',\n\t'lb',\n\t'ltc',\n\t'msd',\n\t'mtp',\n\t'nor',\n\t'nr',\n\t'ot',\n\t'pb',\n\t'pr',\n\t'pt',\n\t'rtp',\n\t'sf',\n\t'sid',\n\t'sn',\n\t'st',\n\t'sta',\n\t'su',\n\t'tab',\n\t'tb',\n\t'tbl',\n\t'tpb',\n\t'v',\n] as const\n","import type { CmcdKey } from './CmcdKey.ts'\n\n// The CMCD custom-key charset restricted to RFC 8941 key serialization\n// (serializeKey): a lowercase first letter, then `a-z 0-9 . -`.\nconst CUSTOM_KEY_REGEX = /^[a-z][a-z0-9.-]*$/\n\n/**\n * Check if a key is a valid custom key: a lowercase first letter, then\n * characters from `a-z 0-9 . -`, with a hyphen that is neither the first\n * nor the last character. These are the CTA-5004-B custom-key rules\n * restricted to names that survive RFC 8941 key serialization.\n *\n * @param key - The key to check.\n *\n * @returns `true` if the key is a custom key, `false` otherwise.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/isCmcdCustomKey.test.ts#example}\n */\nexport function isCmcdCustomKey(key: CmcdKey): boolean {\n\t// The separator is checked outside the regex to keep matching linear (CodeQL js/polynomial-redos).\n\tconst separator = key.indexOf('-', 1)\n\treturn separator > 0 && separator < key.length - 1 && CUSTOM_KEY_REGEX.test(key)\n}\n","import { CMCD_REQUEST_KEYS } from './CMCD_REQUEST_KEYS.ts'\nimport type { Cmcd } from './Cmcd.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\nimport { isCmcdCustomKey } from './isCmcdCustomKey.ts'\n\nconst CMCD_REQUEST_KEY_SET: ReadonlySet<string> = /* @__PURE__ */ new Set(CMCD_REQUEST_KEYS)\n\n/**\n * Check if a key is a valid CMCD request key.\n *\n * @param key - The key to check.\n *\n * @returns `true` if the key is a valid CMCD request key, `false` otherwise.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/isCmcdRequestKey.test.ts#example}\n */\nexport function isCmcdRequestKey(key: string): key is keyof Cmcd {\n\treturn CMCD_REQUEST_KEY_SET.has(key) ||\n\t\tisCmcdCustomKey(key as CmcdKey)\n}\n","/**\n * CMCD v2 - Response-only and timing keys.\n *\n * @public\n */\nexport const CMCD_RESPONSE_KEYS = [\n\t'cmsdd',\n\t'cmsds',\n\t'rc',\n\t'smrt',\n\t'ttfb',\n\t'ttfbb',\n\t'ttlb',\n\t'url',\n] as const\n","import { CMCD_RESPONSE_KEYS } from './CMCD_RESPONSE_KEYS.ts'\nimport type { Cmcd } from './Cmcd.ts'\n\nconst CMCD_RESPONSE_KEY_SET: ReadonlySet<string> = /* @__PURE__ */ new Set(CMCD_RESPONSE_KEYS)\n\n/**\n * Check if a key is a valid CMCD response key.\n *\n * @param key - The key to check.\n *\n * @returns `true` if the key is a valid CMCD request key, `false` otherwise.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/isCmcdResponseReceivedKey.test.ts#example}\n */\nexport function isCmcdResponseReceivedKey(key: string): key is keyof Cmcd {\n\treturn CMCD_RESPONSE_KEY_SET.has(key)\n}\n","import { CMCD_EVENT_KEYS } from './CMCD_EVENT_KEYS.ts'\nimport type { Cmcd } from './Cmcd.ts'\nimport { isCmcdRequestKey } from './isCmcdRequestKey.ts'\nimport { isCmcdResponseReceivedKey } from './isCmcdResponseReceivedKey.ts'\n\nconst CMCD_EVENT_KEY_SET: ReadonlySet<string> = /* @__PURE__ */ new Set(CMCD_EVENT_KEYS)\n\n/**\n * Check if a key is a valid CMCD event key.\n *\n * @param key - The key to check.\n *\n * @returns `true` if the key is a valid CMCD event key, `false` otherwise.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/isCmcdEventKey.test.ts#example}\n */\nexport function isCmcdEventKey(key: string): key is keyof Cmcd {\n\treturn isCmcdRequestKey(key) ||\n\t\tisCmcdResponseReceivedKey(key) ||\n\t\tCMCD_EVENT_KEY_SET.has(key)\n}\n","/**\n * Keys that are inner lists in V2 but plain scalars in V1.\n *\n * Used by both encoding (down-conversion) and decoding (up-conversion).\n *\n * @internal\n */\nexport const CMCD_INNER_LIST_KEYS: Set<string> = new Set<string>([\n\t'ab', 'bl', 'br', 'bsa', 'bsd', 'bsda', 'lab', 'lb', 'mtp', 'pb', 'tab', 'tb', 'tbl', 'tpb',\n])\n","/**\n * Defines the keys for CMCD (Common Media Client Data) version 1.\n *\n * @public\n */\nexport const CMCD_V1_KEYS = [\n\t'bl',\n\t'br',\n\t'bs',\n\t'cid',\n\t'd',\n\t'dl',\n\t'mtp',\n\t'nor',\n\t'nrr',\n\t'ot',\n\t'pr',\n\t'rtp',\n\t'sf',\n\t'sid',\n\t'st',\n\t'su',\n\t'tb',\n\t'v',\n] as const\n","import { CMCD_V1_KEYS } from './CMCD_V1_KEYS.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\nimport { isCmcdCustomKey } from './isCmcdCustomKey.ts'\n\nconst CMCD_V1_KEY_SET: ReadonlySet<string> = /* @__PURE__ */ new Set(CMCD_V1_KEYS)\n\n/**\n * Filter function for CMCD v1 keys.\n *\n * @param key - The CMCD key to filter.\n *\n * @returns `true` if the key should be included, `false` otherwise.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/isCmcdV1Key.test.ts#example}\n */\nexport function isCmcdV1Key(key: string): key is CmcdKey {\n\treturn CMCD_V1_KEY_SET.has(key) || isCmcdCustomKey(key as CmcdKey)\n}\n","const TOKEN_FIELDS = /* @__PURE__ */ new Set(['ot', 'sf', 'st', 'e', 'sta'])\n\n/**\n * Checks if the given key is a token field.\n *\n * @param key - The key to check.\n *\n * @returns `true` if the key is a token field.\n *\n * @internal\n */\nexport function isTokenField(key: string): boolean {\n\treturn TOKEN_FIELDS.has(key)\n}\n","/**\n * Checks if the given value is valid\n *\n * @param value - The value to check.\n *\n * @returns `true` if the key is a value is valid.\n *\n * @internal\n */\nexport function isValid(value: unknown): boolean {\n\tif (typeof value === 'number') {\n\t\treturn Number.isFinite(value)\n\t}\n\n\treturn value != null && value !== '' && value !== false\n}\n","import { SfItem, SfToken } from '@svta/cml-structured-field-values'\nimport { CMCD_FORMATTER_MAP } from './CMCD_FORMATTER_MAP.ts'\nimport { CMCD_V2 } from './CMCD_V2.ts'\nimport type { Cmcd } from './Cmcd.ts'\nimport type { CmcdEncodeOptions } from './CmcdEncodeOptions.ts'\nimport { CMCD_EVENT_BACKGROUNDED_MODE, CMCD_EVENT_CUSTOM_EVENT, CMCD_EVENT_ERROR, CMCD_EVENT_PLAYBACK_RATE, CMCD_EVENT_RESPONSE_RECEIVED } from './CmcdEventType.ts'\nimport { CMCD_STATE_EVENT_FIELDS } from './CMCD_STATE_EVENT_FIELDS.ts'\nimport type { CmcdFormatterOptions } from './CmcdFormatterOptions.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\nimport type { CmcdVersion } from './CmcdVersion.ts'\nimport type { CmcdObjectType } from './CmcdObjectType.ts'\nimport { CMCD_EVENT_MODE, CMCD_REQUEST_MODE } from './CmcdReportingMode.ts'\nimport type { CmcdValue } from './CmcdValue.ts'\nimport { isCmcdEventKey } from './isCmcdEventKey.ts'\nimport { isCmcdRequestKey } from './isCmcdRequestKey.ts'\nimport { isCmcdResponseReceivedKey } from './isCmcdResponseReceivedKey.ts'\nimport { CMCD_INNER_LIST_KEYS } from './CMCD_INNER_LIST_KEYS.ts'\nimport { isCmcdV1Key } from './isCmcdV1Key.ts'\nimport { isTokenField } from './isTokenField.ts'\nimport { isValid } from './isValid.ts'\n\nconst filterMap: Record<string, (key: string) => boolean> = {\n\t[CMCD_EVENT_MODE]: isCmcdEventKey,\n\t[CMCD_REQUEST_MODE]: isCmcdRequestKey,\n}\n\n/**\n * Unwrap an inner list or SfItem value to a plain scalar.\n */\nfunction unwrapValue(value: any, ot?: CmcdObjectType): any {\n\tif (Array.isArray(value)) {\n\t\tlet item: any\n\n\t\tif (ot) {\n\t\t\titem = value.find(item => item.params?.ot === ot)\n\t\t}\n\n\t\tif (!item) {\n\t\t\titem = value[0]\n\t\t}\n\n\t\treturn unwrapValue(item)\n\t}\n\n\tif (value instanceof SfItem) {\n\t\treturn value.value\n\t}\n\n\treturn value\n}\n\n/**\n * Down-convert V2 CMCD data to V1 format.\n *\n * - Extracts `nrr` from `nor` SfItem `r` parameter.\n * - Unwraps inner-list values to plain scalars.\n */\nfunction downConvertToV1(obj: Record<string, any>): Record<string, any> {\n\tconst result: Record<string, any> = {}\n\n\tfor (const [key, value] of Object.entries(obj)) {\n\t\tif (value == null) {\n\t\t\tresult[key] = value\n\t\t\tcontinue\n\t\t}\n\n\t\tif (key === 'nor') {\n\t\t\tconst items = Array.isArray(value) ? value : [value]\n\t\t\tconst first = items[0]\n\n\t\t\tif (first instanceof SfItem) {\n\t\t\t\tresult['nor'] = first.value\n\t\t\t\tif (first.params?.r) {\n\t\t\t\t\tresult['nrr'] = first.params.r\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tresult['nor'] = first\n\t\t\t}\n\t\t}\n\t\telse if (CMCD_INNER_LIST_KEYS.has(key)) {\n\t\t\tresult[key] = unwrapValue(value, obj['ot'])\n\t\t}\n\t\telse {\n\t\t\tresult[key] = value\n\t\t}\n\t}\n\n\treturn result\n}\n\n/**\n * Convert a generic object to CMCD data.\n *\n * @param obj - The CMCD object to process.\n * @param options - Options for encoding.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/prepareCmcdData.test.ts#example}\n */\nexport function prepareCmcdData(obj: Record<string, any>, options: CmcdEncodeOptions = {}): Cmcd {\n\tconst results: Cmcd = {}\n\n\tif (obj == null || typeof obj !== 'object') {\n\t\treturn results\n\t}\n\n\tconst version = options.version || (obj['v'] as CmcdVersion) || CMCD_V2\n\tconst reportingMode = options.reportingMode || CMCD_REQUEST_MODE\n\n\t// Down-convert V2 data to V1 format if needed\n\tconst data = version === 1 ? downConvertToV1(obj) : obj\n\n\tconst keyFilter = version === 1 ? isCmcdV1Key : filterMap[reportingMode]\n\n\t// Filter keys based on the version, reporting mode and options. Every key\n\t// passing a filter is RFC 8941 serializable: standard keys by definition,\n\t// custom keys because isCmcdCustomKey enforces the serializable charset.\n\tlet keys = Object.keys(data).filter(keyFilter) as CmcdKey[]\n\n\tif (data['e'] && data['e'] !== CMCD_EVENT_RESPONSE_RECEIVED) {\n\t\tkeys = keys.filter(key => !isCmcdResponseReceivedKey(key))\n\t}\n\n\tconst filter = options.filter\n\tif (typeof filter === 'function') {\n\t\tkeys = keys.filter(filter)\n\t}\n\n\t// Ensure all required event keys are present before sorting\n\tconst isEventMode = reportingMode === CMCD_EVENT_MODE\n\n\tif (isEventMode) {\n\t\tconst eventType = data['e']\n\n\t\tif (!keys.includes('e') && eventType != null) {\n\t\t\tkeys.push('e')\n\t\t}\n\n\t\tif (!keys.includes('ts')) {\n\t\t\tkeys.push('ts')\n\t\t}\n\n\t\tif (!keys.includes('cen') && data['cen'] != null && eventType === CMCD_EVENT_CUSTOM_EVENT) {\n\t\t\tkeys.push('cen')\n\t\t}\n\n\t\tif (!keys.includes('ec') && data['ec'] != null && eventType === CMCD_EVENT_ERROR) {\n\t\t\tkeys.push('ec')\n\t\t}\n\n\t\tif (!keys.includes('url') && data['url'] != null && eventType === CMCD_EVENT_RESPONSE_RECEIVED) {\n\t\t\tkeys.push('url')\n\t\t}\n\n\t\tconst requiredField = eventType ? CMCD_STATE_EVENT_FIELDS.get(eventType) : undefined\n\t\tif (requiredField && data[requiredField] != null && !keys.includes(requiredField)) {\n\t\t\tkeys.push(requiredField)\n\t\t}\n\t}\n\n\tif (keys.length === 0) {\n\t\treturn results\n\t}\n\n\tif (version > 1 && !keys.includes('v')) {\n\t\tkeys.push('v')\n\t}\n\n\tconst formatterOptions: CmcdFormatterOptions = {\n\t\tversion,\n\t\treportingMode,\n\t\tbaseUrl: options.baseUrl,\n\t}\n\n\tkeys.sort()\n\n\tfor (const key of keys) {\n\t\tlet value = data[key] as CmcdValue\n\n\t\tconst formatter = options.formatters?.[key] ?? CMCD_FORMATTER_MAP[key]\n\t\tif (typeof formatter === 'function') {\n\t\t\tvalue = formatter(value, formatterOptions)\n\t\t}\n\n\t\t// Version should only be reported if not equal to 1.\n\t\tif (key === 'v') {\n\t\t\tif (version === 1) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\telse {\n\t\t\t\tvalue = version\n\t\t\t}\n\t\t}\n\n\t\t// Playback rate should only be sent if not equal to 1, except as\n\t\t// the value of a PLAYBACK_RATE state-change event (where pr=1 is\n\t\t// the data being reported, not a default to skip).\n\t\tif (key === 'pr' && value === 1 && !(isEventMode && data['e'] === CMCD_EVENT_PLAYBACK_RATE)) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Ensure a timestamp is set for event mode\n\t\tif (isEventMode && key === 'ts' && !Number.isFinite(value)) {\n\t\t\tvalue = Date.now()\n\t\t}\n\n\t\t// Ignore invalid values, except `bg: false` on a backgrounded-mode (e=b) state-\n\t\t// change event — the wire must carry `?0` per CTA-5004-B so the transition is\n\t\t// reportable. `bg` is the only state-change required field typed as boolean;\n\t\t// `false` on other required fields (e.g. `cid`, `sta`) is a caller bug and stays\n\t\t// stripped so the validator flags it.\n\t\tconst isBgFalseTransition = isEventMode\n\t\t\t&& value === false\n\t\t\t&& key === 'bg'\n\t\t\t&& data['e'] === CMCD_EVENT_BACKGROUNDED_MODE\n\t\tif (!isValid(value) && !isBgFalseTransition) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif (isTokenField(key) && typeof value === 'string') {\n\t\t\tvalue = new SfToken(value)\n\t\t}\n\n\t\t(results as any)[key] = value\n\t}\n\n\treturn results\n}\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * CMCD object header name.\n *\n * @public\n */\nexport const CMCD_OBJECT = 'CMCD-Object' as const\n\n/**\n * CMCD request header name.\n *\n * @public\n */\nexport const CMCD_REQUEST = 'CMCD-Request' as const\n\n/**\n * CMCD session header name.\n *\n * @public\n */\nexport const CMCD_SESSION = 'CMCD-Session' as const\n\n/**\n * CMCD status header name.\n *\n * @public\n */\nexport const CMCD_STATUS = 'CMCD-Status' as const\n\n/**\n * CMCD header fields.\n *\n *\n * @enum\n *\n * @public\n */\nexport const CmcdHeaderField = {\n\t/**\n\t * keys whose values vary with the object being requested.\n\t */\n\tOBJECT: CMCD_OBJECT as typeof CMCD_OBJECT,\n\n\t/**\n\t * keys whose values vary with each request.\n\t */\n\tREQUEST: CMCD_REQUEST as typeof CMCD_REQUEST,\n\n\t/**\n\t * keys whose values are expected to be invariant over the life of the session.\n\t */\n\tSESSION: CMCD_SESSION as typeof CMCD_SESSION,\n\n\t/**\n\t * keys whose values do not vary with every request or object.\n\t */\n\tSTATUS: CMCD_STATUS as typeof CMCD_STATUS,\n} as const\n\n/**\n * @public\n */\nexport type CmcdHeaderField = ValueOf<typeof CmcdHeaderField>;\n\n/**\n * All CMCD header fields as an array.\n *\n * @public\n */\nexport const CMCD_HEADER_FIELDS: readonly CmcdHeaderField[] = [CMCD_OBJECT, CMCD_REQUEST, CMCD_SESSION, CMCD_STATUS]\n","import { type CmcdHeaderField, CMCD_OBJECT, CMCD_REQUEST, CMCD_SESSION, CMCD_STATUS } from './CmcdHeaderField.ts'\nimport type { CmcdRequestKey } from './CmcdRequestKey.ts'\n\n/**\n * The map of CMCD keys to their appropriate header shard.\n *\n * Note: Event-only keys (e, ts, cen, h) and response-received keys\n * (rc, ttfb, ttlb, url, etc.) are intentionally absent. They are\n * transmitted via the event-mode POST body, not HTTP headers.\n *\n * @public\n */\nexport const CMCD_HEADER_MAP: Record<CmcdRequestKey | 'nrr', CmcdHeaderField> = {\n\t// Object\n\tab: CMCD_OBJECT,\n\tbr: CMCD_OBJECT,\n\td: CMCD_OBJECT,\n\tlab: CMCD_OBJECT,\n\tlb: CMCD_OBJECT,\n\tot: CMCD_OBJECT,\n\ttab: CMCD_OBJECT,\n\ttb: CMCD_OBJECT,\n\ttpb: CMCD_OBJECT,\n\n\t// Request\n\tbl: CMCD_REQUEST,\n\tcs: CMCD_REQUEST,\n\tdfa: CMCD_REQUEST,\n\tdl: CMCD_REQUEST,\n\tltc: CMCD_REQUEST,\n\tmtp: CMCD_REQUEST,\n\tnor: CMCD_REQUEST,\n\tnrr: CMCD_REQUEST,\n\tpb: CMCD_REQUEST,\n\tsn: CMCD_REQUEST,\n\tsta: CMCD_REQUEST,\n\tsu: CMCD_REQUEST,\n\ttbl: CMCD_REQUEST,\n\n\t// Session\n\tcid: CMCD_SESSION,\n\tmsd: CMCD_SESSION,\n\tsf: CMCD_SESSION,\n\tsid: CMCD_SESSION,\n\tst: CMCD_SESSION,\n\tv: CMCD_SESSION,\n\n\t// Status\n\tbg: CMCD_STATUS,\n\tbs: CMCD_STATUS,\n\tbsa: CMCD_STATUS,\n\tbsd: CMCD_STATUS,\n\tbsda: CMCD_STATUS,\n\tcdn: CMCD_STATUS,\n\tec: CMCD_STATUS,\n\tnr: CMCD_STATUS,\n\tpr: CMCD_STATUS,\n\tpt: CMCD_STATUS,\n\trtp: CMCD_STATUS,\n}\n","import type { Cmcd } from './Cmcd.ts'\nimport { CMCD_HEADER_MAP } from './CMCD_HEADER_MAP.ts'\nimport { CmcdHeaderField } from './CmcdHeaderField.ts'\nimport type { CmcdHeaderKey } from './CmcdHeaderKey.ts'\nimport type { CmcdHeaderMap } from './CmcdHeaderMap.ts'\nimport type { CmcdHeaderValue } from './CmcdHeaderValue.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\n\nfunction createHeaderMap(headerMap: Partial<CmcdHeaderMap>): Record<CmcdHeaderKey, CmcdHeaderField> {\n\treturn Object.keys(headerMap)\n\t\t.reduce((acc, field) => {\n\t\t\theaderMap[field as CmcdHeaderField]?.forEach(key => acc[key] = field as CmcdHeaderField)\n\t\t\treturn acc\n\t\t}, {} as Record<CmcdKey, CmcdHeaderField>)\n}\n\n/**\n * Group a CMCD data object into header shards\n *\n * @param cmcd - The CMCD data object to convert.\n * @param customHeaderMap - A map of CMCD header fields to custom CMCD keys.\n *\n * @returns The CMCD header shards.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#header-field-definition | CTA-5004-B Header Field Definition}\n *\n * @public\n */\nexport function groupCmcdHeaders(cmcd: Cmcd, customHeaderMap?: Partial<CmcdHeaderMap>): Record<CmcdHeaderField, CmcdHeaderValue> {\n\tconst result = {} as Record<CmcdHeaderField, CmcdHeaderValue>\n\n\tif (!cmcd) {\n\t\treturn result\n\t}\n\n\tconst keys = Object.keys(cmcd) as CmcdHeaderKey[]\n\tconst custom: Partial<Record<CmcdHeaderKey, CmcdHeaderField>> = customHeaderMap ? createHeaderMap(customHeaderMap) : {}\n\n\tfor (const key of keys) {\n\t\tconst field = CMCD_HEADER_MAP[key] || custom[key] || CmcdHeaderField.REQUEST\n\t\tconst data = result[field] ??= {};\n\t\t(data as Record<string, unknown>)[key] = (cmcd as Record<string, unknown>)[key]\n\t}\n\n\treturn result\n}\n","import { encodeSfDict } from '@svta/cml-structured-field-values'\nimport type { Cmcd } from './Cmcd.ts'\nimport type { CmcdHeaderField } from './CmcdHeaderField.ts'\nimport type { CmcdHeaderMap } from './CmcdHeaderMap.ts'\nimport type { CmcdHeaderValue } from './CmcdHeaderValue.ts'\nimport { groupCmcdHeaders } from './groupCmcdHeaders.ts'\n\n/**\n * Encode already-prepared CMCD data to CMCD header shards.\n *\n * @param data - The prepared CMCD data to encode.\n * @param customHeaderMap - A map of CMCD header fields to custom CMCD keys.\n * @returns The CMCD header shards.\n *\n * @internal\n */\nexport function toPreparedCmcdHeaders(data: Cmcd, customHeaderMap?: Partial<CmcdHeaderMap>): Record<CmcdHeaderField, string> {\n\tconst result = {} as Record<CmcdHeaderField, string>\n\tconst shards = groupCmcdHeaders(data, customHeaderMap)\n\n\tfor (const [field, value] of Object.entries(shards)) {\n\t\tconst shard = encodeSfDict(value as CmcdHeaderValue, { whitespace: false })\n\t\tif (shard) {\n\t\t\tresult[field as CmcdHeaderField] = shard\n\t\t}\n\t}\n\n\treturn result\n}\n","import type { Cmcd } from './Cmcd.ts'\nimport type { CmcdEncodeOptions } from './CmcdEncodeOptions.ts'\nimport type { CmcdHeaderField } from './CmcdHeaderField.ts'\nimport { prepareCmcdData } from './prepareCmcdData.ts'\nimport { toPreparedCmcdHeaders } from './toPreparedCmcdHeaders.ts'\n\n/**\n * Convert a CMCD data object to request headers\n *\n * @param cmcd - The CMCD data object to convert.\n * @param options - Options for encoding the CMCD object.\n *\n * @returns The CMCD header shards.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#header-field-definition | CTA-5004-B Header Field Definition}\n *\n * @public\n *\n * @example\n * {@includeCode ../test/toCmcdHeaders.test.ts#example}\n */\nexport function toCmcdHeaders(cmcd: Cmcd, options: CmcdEncodeOptions = {}): Record<CmcdHeaderField, string> {\n\tif (!cmcd) {\n\t\treturn {} as Record<CmcdHeaderField, string>\n\t}\n\n\treturn toPreparedCmcdHeaders(prepareCmcdData(cmcd, options), options?.customHeaderMap)\n}\n","import type { Cmcd } from './Cmcd.ts'\nimport type { CmcdEncodeOptions } from './CmcdEncodeOptions.ts'\nimport { toCmcdHeaders } from './toCmcdHeaders.ts'\n\n/**\n * Append CMCD query args to a header object.\n *\n * @param headers - The headers to append to.\n * @param cmcd - The CMCD object to append.\n * @param options - Encode options.\n *\n * @returns The headers with the CMCD header shards appended.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/appendCmcdHeaders.test.ts#example}\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#header-field-definition | CTA-5004-B Header Field Definition}\n */\nexport function appendCmcdHeaders(headers: Record<string, string>, cmcd: Cmcd, options?: CmcdEncodeOptions): Record<string, string> {\n\treturn Object.assign(headers, toCmcdHeaders(cmcd, options))\n}\n","/**\n * CMCD parameter name.\n *\n * @public\n */\nexport const CMCD_PARAM = 'CMCD'\n","import { encodeSfDict } from '@svta/cml-structured-field-values'\nimport type { Cmcd } from './Cmcd.ts'\n\n/**\n * Encode already-prepared CMCD data to a structured field dictionary string.\n *\n * @param data - The prepared CMCD data to encode.\n * @returns The encoded CMCD string.\n *\n * @internal\n */\nexport function encodePreparedCmcd(data: Cmcd): string {\n\treturn encodeSfDict(data, { whitespace: false })\n}\n","import type { Cmcd } from './Cmcd.ts'\nimport type { CmcdEncodeOptions } from './CmcdEncodeOptions.ts'\nimport { encodePreparedCmcd } from './encodePreparedCmcd.ts'\nimport { prepareCmcdData } from './prepareCmcdData.ts'\n\n/**\n * Encode a CMCD object to a string.\n *\n * @param cmcd - The CMCD object to encode.\n * @param options - Options for encoding.\n *\n * @returns The encoded CMCD string.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#payload-definition-for-headers-and-query-argument-transmission | CTA-5004-B Payload Definition}\n *\n * @public\n *\n * @example\n * {@includeCode ../test/encodeCmcd.test.ts#example}\n */\nexport function encodeCmcd(cmcd: Cmcd, options: CmcdEncodeOptions = {}): string {\n\tif (!cmcd) {\n\t\treturn ''\n\t}\n\n\treturn encodePreparedCmcd(prepareCmcdData(cmcd, options))\n}\n","import type { Cmcd } from './Cmcd.ts'\nimport type { CmcdEncodeOptions } from './CmcdEncodeOptions.ts'\nimport { encodeCmcd } from './encodeCmcd.ts'\n\n/**\n * Convert a CMCD data object to a URL encoded string.\n *\n * @param cmcd - The CMCD object to convert.\n * @param options - Options for encoding the CMCD object.\n *\n * @returns The URL encoded CMCD data.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#query-argument-definition | CTA-5004-B Query Argument Definition}\n *\n * @public\n */\nexport function toCmcdUrl(cmcd: Cmcd, options: CmcdEncodeOptions = {}): string {\n\tif (!cmcd) {\n\t\treturn ''\n\t}\n\n\tconst params = encodeCmcd(cmcd, options)\n\n\treturn encodeURIComponent(params)\n}\n","import { CMCD_PARAM } from './CMCD_PARAM.ts'\nimport type { Cmcd } from './Cmcd.ts'\nimport type { CmcdEncodeOptions } from './CmcdEncodeOptions.ts'\nimport { toCmcdUrl } from './toCmcdUrl.ts'\n\n/**\n * Convert a CMCD data object to a query arg.\n *\n * @param cmcd - The CMCD object to convert.\n * @param options - Options for encoding the CMCD object.\n *\n * @returns The CMCD query arg.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#query-argument-definition | CTA-5004-B Query Argument Definition}\n *\n * @public\n *\n * @example\n * {@includeCode ../test/toCmcdQuery.test.ts#example}\n */\nexport function toCmcdQuery(cmcd: Cmcd, options: CmcdEncodeOptions = {}): string {\n\tif (!cmcd) {\n\t\treturn ''\n\t}\n\n\tconst value = toCmcdUrl(cmcd, options)\n\n\treturn `${CMCD_PARAM}=${value}`\n}\n","import type { Cmcd } from './Cmcd.ts'\nimport type { CmcdEncodeOptions } from './CmcdEncodeOptions.ts'\nimport { toCmcdQuery } from './toCmcdQuery.ts'\n\nconst REGEX = /CMCD=[^&#]+/\n\n/**\n * Append CMCD query args to a URL.\n *\n * @param url - The URL to append to.\n * @param cmcd - The CMCD object to append.\n * @param options - Options for encoding the CMCD object.\n *\n * @returns The URL with the CMCD query args appended.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/appendCmcdQuery.test.ts#example}\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#query-argument-definition | CTA-5004-B Query Argument Definition}\n */\nexport function appendCmcdQuery(url: string, cmcd: Cmcd, options?: CmcdEncodeOptions): string {\n\tconst query = toCmcdQuery(cmcd, options)\n\tif (!query) {\n\t\treturn url\n\t}\n\n\tif (REGEX.test(url)) {\n\t\treturn url.replace(REGEX, query)\n\t}\n\n\tconst separator = url.includes('?') ? '&' : '?'\n\treturn `${url}${separator}${query}`\n}\n","/**\n * The default time interval in seconds when using using event mode\n *\n * @public\n */\nexport const CMCD_DEFAULT_TIME_INTERVAL = 30\n","import { CMCD_EVENT_KEYS } from './CMCD_EVENT_KEYS.ts'\nimport { CMCD_REQUEST_KEYS } from './CMCD_REQUEST_KEYS.ts'\nimport { CMCD_RESPONSE_KEYS } from './CMCD_RESPONSE_KEYS.ts'\nimport { CMCD_V1_KEYS } from './CMCD_V1_KEYS.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\n\n/**\n * A list of all CMCD keys.\n *\n * @public\n */\nexport const CMCD_KEYS: CmcdKey[] = /* @__PURE__ */ [\n\t...CMCD_V1_KEYS,\n\t...CMCD_REQUEST_KEYS,\n\t...CMCD_RESPONSE_KEYS,\n\t...CMCD_EVENT_KEYS,\n].filter((key, index, arr) => arr.indexOf(key) === index)\n","/**\n * CMCD MIME type for event report payloads.\n *\n * @public\n */\nexport const CMCD_MIME_TYPE = 'application/cmcd'\n","/**\n * The `customData` key under which `CmcdReporter.createRequestReport()`\n * stamps session provenance on every request it returns.\n *\n * The value is a frozen `CmcdRequestProvenance` record: `sid` names the\n * session that issued the request, `cid` is the content id in effect when\n * the request was issued, and `data` carries the request's per-call data\n * as an encoded CMCD string. `CmcdReporter.recordResponseReceived()` reads\n * the record to attribute a late response to its session and to rebuild\n * the request-time report keys.\n * Spread and `Object.assign` carry the record through ordinary request\n * clones, but `JSON.stringify` and structured clone drop symbol-keyed\n * properties: read the value before such a boundary and restore it\n * afterward. The record itself survives JSON, and attribution is by the\n * `sid` value rather than object identity, so a revived plain-object copy\n * attributes exactly. A record naming a `sid` the reporter does not retain\n * drops the response rather than relabeling it.\n *\n * Backed by the symbol registry so duplicated copies of this library in\n * one bundle interoperate. The registry key is stable across versions.\n *\n * @public\n */\nexport const CMCD_REQUEST_PROVENANCE: unique symbol = /* @__PURE__ */ Symbol.for('@svta/cml-cmcd/request-provenance')\n","/**\n * CMCD Version 1\n *\n * @public\n */\nexport const CMCD_V1 = 1 as const\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * Common Media Client Data Object Type\n *\n * @public\n *\n * @enum\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#object-type | CTA-5004-B Object Type}\n */\nexport const CmcdObjectType = {\n\t/**\n\t * text file, such as a manifest or playlist\n\t */\n\tMANIFEST: 'm',\n\n\t/**\n\t * audio only\n\t */\n\tAUDIO: 'a',\n\n\t/**\n\t * video only\n\t */\n\tVIDEO: 'v',\n\n\t/**\n\t * muxed audio and video\n\t */\n\tMUXED: 'av',\n\n\t/**\n\t * init segment\n\t */\n\tINIT: 'i',\n\n\t/**\n\t * caption or subtitle\n\t */\n\tCAPTION: 'c',\n\n\t/**\n\t * ISOBMFF timed text track\n\t */\n\tTIMED_TEXT: 'tt',\n\n\t/**\n\t * cryptographic key, license or certificate.\n\t */\n\tKEY: 'k',\n\n\t/**\n\t * other\n\t */\n\tOTHER: 'o',\n} as const\n\n/**\n * @public\n */\nexport type CmcdObjectType = ValueOf<typeof CmcdObjectType>;\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * CMCD v2 player states for the 'sta' key.\n *\n *\n * @enum\n *\n * @public\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#state | CTA-5004-B State}\n */\nexport const CmcdPlayerState = {\n\t/**\n\t * Starting: Initial startup of the player.\n\t */\n\tSTARTING: 's',\n\n\t/**\n\t * Playing: The player is actively rendering content.\n\t */\n\tPLAYING: 'p',\n\n\t/**\n\t * Seeking: The player is seeking to a new position.\n\t */\n\tSEEKING: 'k',\n\n\t/**\n\t * Rebuffering: The player is buffering data during playback.\n\t */\n\tREBUFFERING: 'r',\n\n\t/**\n\t * Paused: The player is paused.\n\t */\n\tPAUSED: 'a',\n\n\t/**\n\t * Waiting: The player is waiting for a user action or another event.\n\t */\n\tWAITING: 'w',\n\n\t/**\n\t * Ended: The media has finished playing.\n\t */\n\tENDED: 'e',\n\n\t/**\n\t * Fatal Error: The player has encountered a fatal error.\n\t */\n\tFATAL_ERROR: 'f',\n\n\t/**\n\t * Quit: User initiated end of playback before media asset completion.\n\t */\n\tQUIT: 'q',\n\n\t/**\n\t * Preloading: The player is loading assets ahead of starting in order to provide a fast startup. The expectation is that playback will commence at a future time.\n\t */\n\tPRELOADING: 'd',\n} as const\n\n/**\n * @public\n */\nexport type CmcdPlayerState = ValueOf<typeof CmcdPlayerState>;\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * CMCD query reporting mode — CMCD data carried as a `CMCD=` URL\n * query parameter.\n *\n * @public\n */\nexport const CMCD_RECORDED_REPORT_MODE_QUERY = 'query' as const\n\n/**\n * CMCD header reporting mode — CMCD data carried as `Cmcd-*` HTTP\n * headers.\n *\n * @public\n */\nexport const CMCD_RECORDED_REPORT_MODE_HEADER = 'header' as const\n\n/**\n * CMCD event reporting mode — CMCD data carried as a POST body to an\n * event-target URL.\n *\n * @public\n */\nexport const CMCD_RECORDED_REPORT_MODE_EVENT = 'event' as const\n\n/**\n * Reporting mode under which a captured report was observed by\n * `CmcdReportRecorder`.\n *\n * @enum\n *\n * @public\n */\nexport const CmcdRecordedReportMode = {\n\tQUERY: CMCD_RECORDED_REPORT_MODE_QUERY as typeof CMCD_RECORDED_REPORT_MODE_QUERY,\n\tHEADER: CMCD_RECORDED_REPORT_MODE_HEADER as typeof CMCD_RECORDED_REPORT_MODE_HEADER,\n\tEVENT: CMCD_RECORDED_REPORT_MODE_EVENT as typeof CMCD_RECORDED_REPORT_MODE_EVENT,\n} as const\n\n/**\n * @public\n */\nexport type CmcdRecordedReportMode = ValueOf<typeof CmcdRecordedReportMode>\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * Manifest or playlist request classification.\n *\n * @public\n */\nexport const CMCD_RECORDED_REQUEST_TYPE_MANIFEST = 'manifest' as const\n\n/**\n * Media segment request classification.\n *\n * @public\n */\nexport const CMCD_RECORDED_REQUEST_TYPE_SEGMENT = 'segment' as const\n\n/**\n * CMCD event-mode report request classification (POST to a URL in\n * `eventTargetUrls`).\n *\n * @public\n */\nexport const CMCD_RECORDED_REQUEST_TYPE_EVENT = 'event' as const\n\n/**\n * Fallback classification for requests the recorder did not recognize\n * as manifest, segment, or event.\n *\n * @public\n */\nexport const CMCD_RECORDED_REQUEST_TYPE_UNKNOWN = 'unknown' as const\n\n/**\n * Classification of a captured request, used by `CmcdReportRecorder`\n * for filtering.\n *\n * @enum\n *\n * @public\n */\nexport const CmcdRecordedRequestType = {\n\tMANIFEST: CMCD_RECORDED_REQUEST_TYPE_MANIFEST as typeof CMCD_RECORDED_REQUEST_TYPE_MANIFEST,\n\tSEGMENT: CMCD_RECORDED_REQUEST_TYPE_SEGMENT as typeof CMCD_RECORDED_REQUEST_TYPE_SEGMENT,\n\tEVENT: CMCD_RECORDED_REQUEST_TYPE_EVENT as typeof CMCD_RECORDED_REQUEST_TYPE_EVENT,\n\tUNKNOWN: CMCD_RECORDED_REQUEST_TYPE_UNKNOWN as typeof CMCD_RECORDED_REQUEST_TYPE_UNKNOWN,\n} as const\n\n/**\n * @public\n */\nexport type CmcdRecordedRequestType = ValueOf<typeof CmcdRecordedRequestType>\n","import type { HttpRequest } from '@svta/cml-utils'\nimport type { CmcdRequestDeliver, CmcdTransportAdapter } from './CmcdTransportAdapter.ts'\n\nasync function toHttpRequest(request: Request): Promise<HttpRequest> {\n\tconst headers: Record<string, string> = {}\n\trequest.headers.forEach((value, name) => {\n\t\theaders[name.toLowerCase()] = value\n\t})\n\n\tlet body: string | undefined\n\tif (request.body) {\n\t\ttry {\n\t\t\tbody = await request.text()\n\t\t} catch {\n\t\t\tbody = undefined\n\t\t}\n\t}\n\n\treturn {\n\t\turl: request.url,\n\t\tmethod: request.method,\n\t\theaders,\n\t\tbody,\n\t}\n}\n\n/**\n * Create a transport adapter that patches `globalThis.fetch` to capture\n * CMCD-bearing requests, normalizing each to `HttpRequest` (lowercase\n * headers, body read as UTF-8 string). Returns the adapter object\n * expected by `CmcdReportRecorder`.\n *\n * Bodies are read once via `Request.text()` for inspection. This is\n * safe for the body types CMCD reports use in practice (`string`,\n * `Blob`, `ArrayBuffer`, `FormData`, `URLSearchParams`), which can be\n * read by the wrapper and re-read by the underlying `fetch`. Passing\n * a `ReadableStream` as `init.body` is not supported — the stream is\n * consumed by the wrapper and the underlying `fetch` will receive an\n * already-disturbed stream.\n *\n * @public\n */\nexport function createFetchTransport(): CmcdTransportAdapter {\n\treturn {\n\t\tattach(deliver: CmcdRequestDeliver): () => void {\n\t\t\tconst origFetch = globalThis.fetch\n\n\t\t\tglobalThis.fetch = async (\n\t\t\t\tinput: RequestInfo | URL,\n\t\t\t\tinit?: RequestInit,\n\t\t\t): Promise<Response> => {\n\t\t\t\tconst inspect = input instanceof Request\n\t\t\t\t\t? input.clone()\n\t\t\t\t\t: new Request(input, init)\n\t\t\t\tconst httpRequest = await toHttpRequest(inspect)\n\t\t\t\tconst synthetic = deliver(httpRequest)\n\t\t\t\tif (synthetic) {\n\t\t\t\t\treturn synthetic\n\t\t\t\t}\n\t\t\t\treturn origFetch.call(globalThis, input as RequestInfo, init)\n\t\t\t}\n\n\t\t\treturn () => {\n\t\t\t\tglobalThis.fetch = origFetch\n\t\t\t}\n\t\t},\n\t}\n}\n","import type { HttpRequest } from '@svta/cml-utils'\nimport type { CmcdRequestDeliver, CmcdTransportAdapter } from './CmcdTransportAdapter.ts'\n\ntype XhrInstance = XMLHttpRequest & {\n\t_cmcdMethod?: string;\n\t_cmcdUrl?: string;\n\t_cmcdHeaders?: Record<string, string>;\n}\n\nasync function completeXhrWith(xhr: XhrInstance, response: Response): Promise<void> {\n\tconst text = await response.clone().text().catch(() => '')\n\tconst ProgressEventCtor: typeof ProgressEvent | typeof Event =\n\t\ttypeof ProgressEvent !== 'undefined' ? ProgressEvent : Event\n\n\tqueueMicrotask(() => {\n\t\ttry {\n\t\t\tObject.defineProperty(xhr, 'status', { value: response.status, configurable: true })\n\t\t\tObject.defineProperty(xhr, 'statusText', { value: response.statusText, configurable: true })\n\t\t\tObject.defineProperty(xhr, 'readyState', { value: 4, configurable: true })\n\t\t\tObject.defineProperty(xhr, 'responseURL', { value: xhr._cmcdUrl ?? '', configurable: true })\n\t\t\tObject.defineProperty(xhr, 'response', { value: text, configurable: true })\n\t\t\tObject.defineProperty(xhr, 'responseText', { value: text, configurable: true })\n\n\t\t\tif (typeof xhr.onload === 'function') {\n\t\t\t\txhr.onload.call(xhr, new ProgressEventCtor('load') as ProgressEvent<EventTarget>)\n\t\t\t}\n\t\t\tif (typeof xhr.onloadend === 'function') {\n\t\t\t\txhr.onloadend.call(xhr, new ProgressEventCtor('loadend') as ProgressEvent<EventTarget>)\n\t\t\t}\n\t\t} catch {\n\t\t\t// MockXhr may not allow defineProperty on some properties;\n\t\t\t// for shim simplicity we set them directly as a fallback.\n\t\t\tconst target = xhr as unknown as Record<string, unknown>\n\t\t\ttarget['status'] = response.status\n\t\t\ttarget['statusText'] = response.statusText\n\t\t\ttarget['readyState'] = 4\n\t\t\ttarget['responseURL'] = xhr._cmcdUrl ?? ''\n\t\t\ttarget['response'] = text\n\t\t\ttarget['responseText'] = text\n\t\t\tif (typeof xhr.onload === 'function') {\n\t\t\t\txhr.onload.call(xhr as unknown as XMLHttpRequest, new ProgressEventCtor('load') as ProgressEvent<EventTarget>)\n\t\t\t}\n\t\t\tif (typeof xhr.onloadend === 'function') {\n\t\t\t\txhr.onloadend.call(xhr as unknown as XMLHttpRequest, new ProgressEventCtor('loadend') as ProgressEvent<EventTarget>)\n\t\t\t}\n\t\t}\n\t})\n}\n\n/**\n * Create a transport adapter that patches `XMLHttpRequest.prototype` to\n * capture CMCD-bearing requests. Returns the adapter object expected by\n * `CmcdReportRecorder`.\n *\n * @public\n */\nexport function createXhrTransport(): CmcdTransportAdapter {\n\treturn {\n\t\tattach(deliver: CmcdRequestDeliver): () => void {\n\t\t\tconst Xhr = globalThis.XMLHttpRequest\n\t\t\tif (!Xhr) {\n\t\t\t\treturn () => { /* no XHR to detach */ }\n\t\t\t}\n\t\t\tconst origOpen = Xhr.prototype.open\n\t\t\tconst origSetRequestHeader = Xhr.prototype.setRequestHeader\n\t\t\tconst origSend = Xhr.prototype.send\n\n\t\t\tXhr.prototype.open = function (this: XhrInstance, method: string, url: string | URL): void {\n\t\t\t\tthis._cmcdMethod = method\n\t\t\t\tthis._cmcdUrl = typeof url === 'string' ? url : url.toString()\n\t\t\t\tthis._cmcdHeaders = {}\n\t\t\t\t// eslint-disable-next-line prefer-rest-params\n\t\t\t\treturn origOpen.apply(this, arguments as unknown as Parameters<typeof origOpen>)\n\t\t\t}\n\n\t\t\tXhr.prototype.setRequestHeader = function (this: XhrInstance, name: string, value: string): void {\n\t\t\t\tif (this._cmcdHeaders) {\n\t\t\t\t\tthis._cmcdHeaders[name.toLowerCase()] = value\n\t\t\t\t}\n\t\t\t\treturn origSetRequestHeader.apply(this, [name, value])\n\t\t\t}\n\n\t\t\tXhr.prototype.send = function (this: XhrInstance, body?: Document | XMLHttpRequestBodyInit | null): void {\n\t\t\t\tconst httpRequest: HttpRequest = {\n\t\t\t\t\turl: this._cmcdUrl ?? '',\n\t\t\t\t\tmethod: (this._cmcdMethod ?? 'GET').toUpperCase(),\n\t\t\t\t\theaders: this._cmcdHeaders ?? {},\n\t\t\t\t\tbody: (typeof Document !== 'undefined' && body instanceof Document ? undefined : body as BodyInit | null | undefined) ?? undefined,\n\t\t\t\t}\n\n\t\t\t\tconst synthetic = deliver(httpRequest)\n\n\t\t\t\tif (synthetic) {\n\t\t\t\t\tcompleteXhrWith(this, synthetic)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\treturn origSend.apply(this, [body])\n\t\t\t}\n\n\t\t\treturn () => {\n\t\t\t\tXhr.prototype.open = origOpen\n\t\t\t\tXhr.prototype.setRequestHeader = origSetRequestHeader\n\t\t\t\tXhr.prototype.send = origSend\n\t\t\t}\n\t\t},\n\t}\n}\n","import type { HttpRequest } from '@svta/cml-utils'\nimport { CMCD_PARAM } from './CMCD_PARAM.ts'\nimport type { CmcdRecordedReport } from './CmcdRecordedReport.ts'\nimport type { CmcdRecordedReportMode } from './CmcdRecordedReportMode.ts'\nimport type { CmcdReportRecorderOptions } from './CmcdReportRecorderOptions.ts'\nimport type { CmcdReportRecorderWaitOptions } from './CmcdReportRecorderWaitOptions.ts'\nimport { CmcdRecordedRequestType } from './CmcdRecordedRequestType.ts'\nimport { createFetchTransport } from './createFetchTransport.ts'\nimport { createXhrTransport } from './createXhrTransport.ts'\n\nconst MANIFEST_EXTENSIONS = /\\.(m3u8|mpd)(\\?|$|\\/)/i\nconst SEGMENT_EXTENSIONS = /\\.(m4s|m4v|m4a|mp4|ts|aac)(\\?|$|\\/)/i\n\nfunction classifyUrl(url: string, isEventTarget: boolean): CmcdRecordedRequestType {\n\tif (isEventTarget) {\n\t\treturn CmcdRecordedRequestType.EVENT\n\t}\n\tif (MANIFEST_EXTENSIONS.test(url)) {\n\t\treturn CmcdRecordedRequestType.MANIFEST\n\t}\n\tif (SEGMENT_EXTENSIONS.test(url)) {\n\t\treturn CmcdRecordedRequestType.SEGMENT\n\t}\n\treturn CmcdRecordedRequestType.UNKNOWN\n}\n\nfunction hasCmcdHeader(headers: Record<string, string> | undefined): boolean {\n\tif (!headers) {\n\t\treturn false\n\t}\n\tfor (const name in headers) {\n\t\tif (name.toLowerCase().startsWith('cmcd-')) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunction detectReportingMode(\n\turl: string,\n\theaders: Record<string, string> | undefined,\n\tisEventTarget: boolean,\n): CmcdRecordedReportMode | null {\n\tif (isEventTarget) {\n\t\treturn 'event'\n\t}\n\tif (hasCmcdHeader(headers)) {\n\t\treturn 'header'\n\t}\n\treturn url.includes(`${CMCD_PARAM}=`) ? 'query' : null\n}\n\ntype CmcdReportWaiter = {\n\ttype: CmcdRecordedRequestType | undefined\n\tcount: number\n\tresolve: (r: CmcdRecordedReport[]) => void\n\treject: (e: Error) => void\n}\n\n/**\n * Test helper that records CMCD-bearing reports across XHR and fetch\n * transports for assertion in e2e tests. Each captured request is\n * normalized to {@link @svta/cml-utils!HttpRequest | HttpRequest} so\n * tests are identical regardless of which transport the player uses.\n *\n * @example\n * {@includeCode ../test/CmcdReportRecorder.test.ts#example}\n *\n * @public\n */\nexport class CmcdReportRecorder {\n\t#reports: CmcdRecordedReport[] = []\n\t#detachers: (() => void)[] = []\n\t#attached = false\n\t#eventTargetUrls: readonly string[] = []\n\t#waiters = new Map<ReturnType<typeof setTimeout>, CmcdReportWaiter>()\n\t#onReport: ((report: CmcdRecordedReport) => void) | undefined\n\t#waitTimeout = 15000\n\n\treadonly #deliver = (request: HttpRequest): Response | undefined => {\n\t\tconst url = request.url\n\t\tconst method = (request.method ?? 'GET').toUpperCase()\n\t\tconst isEventTarget = method === 'POST' && this.#eventTargetUrls.some((t) => url.startsWith(t))\n\n\t\tconst reportingMode = detectReportingMode(url, request.headers, isEventTarget)\n\t\tif (reportingMode === null) {\n\t\t\treturn undefined\n\t\t}\n\n\t\tconst captured: CmcdRecordedReport = {\n\t\t\trequest,\n\t\t\ttype: classifyUrl(url, isEventTarget),\n\t\t\treportingMode,\n\t\t\ttimestamp: Date.now(),\n\t\t}\n\t\tthis.#reports.push(captured)\n\t\tif (this.#onReport) {\n\t\t\ttry {\n\t\t\t\tthis.#onReport(captured)\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error('CmcdReportRecorder onReport listener threw:', err)\n\t\t\t}\n\t\t}\n\t\tthis.#notifyWaiters()\n\n\t\treturn isEventTarget ? new Response(null, { status: 204 }) : undefined\n\t}\n\n\t#getMatching(type: CmcdRecordedRequestType | undefined): CmcdRecordedReport[] {\n\t\treturn type === undefined\n\t\t\t? [...this.#reports]\n\t\t\t: this.#reports.filter((r) => r.type === type)\n\t}\n\n\t#notifyWaiters(): void {\n\t\tfor (const [timer, waiter] of this.#waiters) {\n\t\t\tconst matching = this.#getMatching(waiter.type)\n\t\t\tif (matching.length >= waiter.count) {\n\t\t\t\tclearTimeout(timer)\n\t\t\t\tthis.#waiters.delete(timer)\n\t\t\t\twaiter.resolve(matching)\n\t\t\t}\n\t\t}\n\t}\n\n\t#waitFor(\n\t\ttype: CmcdRecordedRequestType | undefined,\n\t\toptions: CmcdReportRecorderWaitOptions,\n\t): Promise<CmcdRecordedReport[]> {\n\t\tconst count = options.count ?? 1\n\t\tconst timeout = options.timeout ?? this.#waitTimeout\n\n\t\tconst matching = this.#getMatching(type)\n\t\tif (matching.length >= count) {\n\t\t\treturn Promise.resolve(matching)\n\t\t}\n\n\t\treturn new Promise<CmcdRecordedReport[]>((resolve, reject) => {\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tthis.#waiters.delete(timer)\n\t\t\t\tconst current = this.#getMatching(type)\n\t\t\t\treject(new Error(\n\t\t\t\t\t`Timeout waiting for ${count} ${type ?? 'any'} CMCD report(s). Got ${current.length}. Total recorded: ${this.#reports.length}.`,\n\t\t\t\t))\n\t\t\t}, timeout)\n\n\t\t\tthis.#waiters.set(timer, { type, count, resolve, reject })\n\t\t})\n\t}\n\n\t/**\n\t * Install transport patches and begin recording CMCD reports.\n\t * No-op if already attached — the previously supplied options are\n\t * retained and the new `options` argument is silently ignored.\n\t * Call `detach()` first if you need to re-attach with different\n\t * options.\n\t *\n\t * @public\n\t */\n\tattach(options: CmcdReportRecorderOptions = {}): void {\n\t\tif (this.#attached) {\n\t\t\treturn\n\t\t}\n\t\tthis.#attached = true\n\t\tthis.#eventTargetUrls = options.eventTargetUrls ?? []\n\t\tthis.#onReport = options.onReport\n\t\tthis.#waitTimeout = options.waitTimeout ?? 15000\n\n\t\tconst transports = options.transports ?? [createXhrTransport(), createFetchTransport()]\n\t\tfor (const transport of transports) {\n\t\t\tthis.#detachers.push(transport.attach(this.#deliver))\n\t\t}\n\t}\n\n\t/**\n\t * Remove transport patches and stop recording. Rejects any pending\n\t * wait promises with `Error('Recorder detached while waiting')`.\n\t *\n\t * @public\n\t */\n\tdetach(): void {\n\t\tif (!this.#attached) {\n\t\t\treturn\n\t\t}\n\t\tfor (const detacher of this.#detachers) {\n\t\t\tdetacher()\n\t\t}\n\t\tthis.#detachers = []\n\t\tthis.#attached = false\n\t\tthis.#eventTargetUrls = []\n\t\tthis.#onReport = undefined\n\n\t\tfor (const [timer, waiter] of this.#waiters) {\n\t\t\tclearTimeout(timer)\n\t\t\twaiter.reject(new Error('Recorder detached while waiting'))\n\t\t}\n\t\tthis.#waiters.clear()\n\t}\n\n\t/**\n\t * Discard all recorded reports. Does not affect the attached state.\n\t *\n\t * @public\n\t */\n\tclear(): void {\n\t\tthis.#reports = []\n\t}\n\n\t/**\n\t * Return a defensive copy of all recorded reports.\n\t *\n\t * @public\n\t */\n\tgetReports(): CmcdRecordedReport[] {\n\t\treturn [...this.#reports]\n\t}\n\n\t/**\n\t * Wait until at least `count` reports of any type are recorded.\n\t * Resolves with all matching reports; rejects with a diagnostic error\n\t * on timeout. `count` defaults to 1; `timeout` falls back to the\n\t * recorder's `waitTimeout` option (default 15000 ms).\n\t *\n\t * @public\n\t */\n\twaitForReports(options: CmcdReportRecorderWaitOptions = {}): Promise<CmcdRecordedReport[]> {\n\t\treturn this.#waitFor(undefined, options)\n\t}\n\n\t/**\n\t * Wait until at least `count` manifest reports are recorded.\n\t * Resolves with all matching reports; rejects with a diagnostic error\n\t * on timeout. `count` defaults to 1; `timeout` falls back to the\n\t * recorder's `waitTimeout` option (default 15000 ms).\n\t *\n\t * @public\n\t */\n\twaitForManifest(options: CmcdReportRecorderWaitOptions = {}): Promise<CmcdRecordedReport[]> {\n\t\treturn this.#waitFor(CmcdRecordedRequestType.MANIFEST, options)\n\t}\n\n\t/**\n\t * Wait until at least `count` segment reports are recorded.\n\t * Resolves with all matching reports; rejects with a diagnostic error\n\t * on timeout. `count` defaults to 1; `timeout` falls back to the\n\t * recorder's `waitTimeout` option (default 15000 ms).\n\t *\n\t * @public\n\t */\n\twaitForSegments(options: CmcdReportRecorderWaitOptions = {}): Promise<CmcdRecordedReport[]> {\n\t\treturn this.#waitFor(CmcdRecordedRequestType.SEGMENT, options)\n\t}\n\n\t/**\n\t * Wait until at least `count` event-mode reports are recorded.\n\t * Resolves with all matching reports; rejects with a diagnostic error\n\t * on timeout. `count` defaults to 1; `timeout` falls back to the\n\t * recorder's `waitTimeout` option (default 15000 ms).\n\t *\n\t * @public\n\t */\n\twaitForEvents(options: CmcdReportRecorderWaitOptions = {}): Promise<CmcdRecordedReport[]> {\n\t\treturn this.#waitFor(CmcdRecordedRequestType.EVENT, options)\n\t}\n}\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * CMCD `query` transmission mode.\n *\n * @public\n */\nexport const CMCD_QUERY = 'query' as const\n\n/**\n * CMCD `headers` transmission mode.\n *\n * @public\n */\nexport const CMCD_HEADERS = 'headers' as const\n\n/**\n * CMCD `json` transmission mode.\n *\n * @public\n *\n * @deprecated JSON transmission mode is deprecated and will be removed in future versions.\n */\nexport const CMCD_JSON = 'json' as const\n\n/**\n * CMCD transmission modes.\n *\n * @enum\n *\n * @public\n */\nexport const CmcdTransmissionMode = {\n\t/**\n\t * JSON\n\t *\n\t * @deprecated JSON transmission mode is deprecated and will be removed in future versions.\n\t */\n\tJSON: CMCD_JSON as typeof CMCD_JSON,\n\n\t/**\n\t * Query string\n\t */\n\tQUERY: CMCD_QUERY as typeof CMCD_QUERY,\n\n\t/**\n\t * Request headers\n\t */\n\tHEADERS: CMCD_HEADERS as typeof CMCD_HEADERS,\n\n} as const\n\n/**\n * @public\n */\nexport type CmcdTransmissionMode = ValueOf<typeof CmcdTransmissionMode>;\n","import { CMCD_INNER_LIST_KEYS } from './CMCD_INNER_LIST_KEYS.ts'\nimport { CMCD_V2 } from './CMCD_V2.ts'\n\n/**\n * Up-convert V1 CMCD data to V2 format.\n *\n * - Wraps plain scalar values in arrays for inner-list keys.\n * - Wraps `nor` string in an array.\n *\n * If the data is already V2 (has `v: 2`), it is returned unchanged.\n *\n * @internal\n */\nexport function upConvertToV2(obj: Record<string, any>): Record<string, any> {\n\tif (obj['v'] === CMCD_V2) {\n\t\treturn obj\n\t}\n\n\tconst result: Record<string, any> = {}\n\n\tfor (const [key, value] of Object.entries(obj)) {\n\t\tif (value == null) {\n\t\t\tresult[key] = value\n\t\t\tcontinue\n\t\t}\n\n\t\tif (CMCD_INNER_LIST_KEYS.has(key) && !Array.isArray(value)) {\n\t\t\tresult[key] = [value]\n\t\t}\n\t\telse if (key === 'nor' && typeof value === 'string') {\n\t\t\tresult[key] = [value]\n\t\t}\n\t\telse {\n\t\t\tresult[key] = value\n\t\t}\n\t}\n\n\treturn result\n}\n","import type { SfBareItem } from '@svta/cml-structured-field-values'\nimport { decodeSfDict, SfItem, symbolToStr } from '@svta/cml-structured-field-values'\nimport type { Cmcd } from './Cmcd.ts'\nimport type { CmcdData } from './CmcdData.ts'\nimport type { CmcdDecodeOptions } from './CmcdDecodeOptions.ts'\nimport type { CmcdValue } from './CmcdValue.ts'\nimport { upConvertToV2 } from './upConvertToV2.ts'\n\n// Define the input type for reduceValue\ntype ReduceValueInput = SfBareItem | SfItem | ReduceValueInput[];\n\n// Define the output type for reduceValue - matches what CMCD values can be, including arrays\ntype ReduceValueOutput = CmcdValue | ReduceValueOutput[];\n\nfunction reduceValue(value: ReduceValueInput, useSymbol: boolean | undefined): ReduceValueOutput {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(item => reduceValue(item, useSymbol))\n\t}\n\n\t// Tokens reduce to plain strings unless the caller opted into\n\t// preservation, where the parser's own representation passes through:\n\t// a registry symbol, or an SfToken when `useSymbol` is `false`. Both\n\t// re-encode as bare tokens, so preserved output round-trips.\n\tif (typeof value === 'symbol') {\n\t\treturn useSymbol === undefined ? symbolToStr(value) : (value as unknown as ReduceValueOutput)\n\t}\n\n\tif (value instanceof SfItem) {\n\t\t// Params are data: an item that carries them stays an SfItem, with\n\t\t// its value reduced the same way a bare member's would be. Only\n\t\t// param-less wrappers unwrap.\n\t\treturn value.params\n\t\t\t? new SfItem(reduceValue(value.value, useSymbol), value.params)\n\t\t\t: reduceValue(value.value, useSymbol)\n\t}\n\n\treturn value as ReduceValueOutput\n};\n\n/**\n * Decode a CMCD string to an object.\n *\n * @param cmcd - The CMCD string to decode.\n * @param options - Options for decoding.\n *\n * @returns The decoded CMCD object.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#payload-definition-for-headers-and-query-argument-transmission | CTA-5004-B Payload Definition}\n *\n * @public\n *\n * @example\n * {@includeCode ../test/decodeCmcd.test.ts#example}\n */\nexport function decodeCmcd(cmcd: string, options: CmcdDecodeOptions & { convertToLatest: true }): Cmcd\nexport function decodeCmcd<T extends CmcdData = CmcdData>(cmcd: string, options?: CmcdDecodeOptions): T\nexport function decodeCmcd(cmcd: string, options?: CmcdDecodeOptions): CmcdData | Cmcd {\n\tif (!cmcd) {\n\t\treturn {} as CmcdData\n\t}\n\n\tconst sfDict = decodeSfDict(cmcd, options)\n\n\t// Each dictionary member is reduced whole, not via `item.value`, so\n\t// member-level and inner-list-level params survive decoding.\n\tconst result: Record<string, unknown> = {}\n\tfor (const [key, item] of Object.entries(sfDict as Record<string, SfItem>)) {\n\t\tresult[key] = reduceValue(item, options?.useSymbol)\n\t}\n\n\tif (options?.convertToLatest) {\n\t\treturn upConvertToV2(result) as Cmcd\n\t}\n\n\treturn result as CmcdData\n}\n","import type { HttpRequest, HttpResponse } from '@svta/cml-utils'\nimport { uuid } from '@svta/cml-utils'\nimport { CMCD_DEFAULT_TIME_INTERVAL } from './CMCD_DEFAULT_TIME_INTERVAL.ts'\nimport { CMCD_MIME_TYPE } from './CMCD_MIME_TYPE.ts'\nimport { CMCD_PARAM } from './CMCD_PARAM.ts'\nimport { CMCD_REQUEST_PROVENANCE } from './CMCD_REQUEST_PROVENANCE.ts'\nimport { CMCD_V2 } from './CMCD_V2.ts'\nimport type { Cmcd } from './Cmcd.ts'\nimport type { CmcdEncodeOptions } from './CmcdEncodeOptions.ts'\nimport type { CmcdEventReportConfig } from './CmcdEventReportConfig.ts'\nimport { CMCD_EVENT_CUSTOM_EVENT, CMCD_EVENT_ERROR, CMCD_EVENT_RESPONSE_RECEIVED, CMCD_EVENT_TIME_INTERVAL, CmcdEventType } from './CmcdEventType.ts'\nimport { CMCD_STATE_EVENT_FIELDS } from './CMCD_STATE_EVENT_FIELDS.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\nimport type { CmcdObjectTypeList } from './CmcdObjectTypeList.ts'\nimport type { CmcdReportConfig } from './CmcdReportConfig.ts'\nimport type { CmcdReporterConfig } from './CmcdReporterConfig.ts'\nimport type { CmcdReporterCustomData } from './CmcdReporterCustomData.ts'\nimport type { CmcdRequestProvenance } from './CmcdRequestProvenance.ts'\nimport type { CmcdRequestReportConfig } from './CmcdRequestReportConfig.ts'\nimport type { CmcdReportingMode } from './CmcdReportingMode.ts'\nimport { CMCD_EVENT_MODE, CMCD_REQUEST_MODE } from './CmcdReportingMode.ts'\nimport type { CmcdRequestReport } from './CmcdRequestReport.ts'\nimport type { CmcdTransformRequest } from './CmcdTransformRequest.ts'\nimport { CMCD_HEADERS, CMCD_QUERY } from './CmcdTransmissionMode.ts'\nimport type { CmcdVersion } from './CmcdVersion.ts'\nimport { decodeCmcd } from './decodeCmcd.ts'\nimport { encodeCmcd } from './encodeCmcd.ts'\nimport { encodePreparedCmcd } from './encodePreparedCmcd.ts'\nimport { prepareCmcdData } from './prepareCmcdData.ts'\nimport { toPreparedCmcdHeaders } from './toPreparedCmcdHeaders.ts'\n\ntype CmcdReportConfigNormalized = CmcdReportConfig & {\n\tversion: CmcdVersion;\n}\n\ntype CmcdEventReportConfigNormalized<C> = CmcdEventReportConfig<C> & CmcdReportConfigNormalized & {\n\tevents: CmcdEventType[];\n\tinterval: number;\n\tbatchSize: number;\n}\n\ntype CmcdReporterConfigNormalized<C> = CmcdReporterConfig<C> & CmcdReportConfigNormalized & {\n\tsid: string;\n\teventTargets: CmcdEventReportConfigNormalized<C>[];\n\tsessionRetention: number;\n}\n\nfunction createEncodingOptions(reportingMode: CmcdReportingMode, config: CmcdReportConfig & Pick<CmcdRequestReportConfig, 'customHeaderMap'>, baseUrl?: string): CmcdEncodeOptions {\n\tconst enabledKeySet = new Set(config.enabledKeys ?? [])\n\n\treturn {\n\t\tversion: config.version || CMCD_V2,\n\t\treportingMode,\n\t\tfilter: (key: CmcdKey) => enabledKeySet.has(key),\n\t\tbaseUrl,\n\t\tcustomHeaderMap: config.customHeaderMap,\n\t}\n}\n\n/**\n * Tracked state field for dedup + auto-trigger.\n */\ntype StateField = 'sta' | 'pr' | 'cid' | 'bg' | 'br'\n\n/**\n * One row in the STATE_FIELDS dispatch table.\n *\n * `snapshot` captures the value stored in `lastEmitted` for dedup\n * comparisons. Reference types must clone so the baseline doesn't\n * share a reference with the caller's input, which would let in-place\n * mutation silently poison the dedup state.\n */\ntype StateFieldEntry = {\n\tfield: StateField\n\tevent: CmcdEventType\n\tequal: (a: unknown, b: unknown) => boolean\n\tsnapshot: (v: unknown) => unknown\n}\n\n/**\n * Deep equality for CmcdObjectTypeList (used for `br` dedup).\n *\n * Order-sensitive: arrays with the same elements in different positions\n * are treated as different. Players that construct `br` consistently\n * get correct dedup; shuffling produces spurious emits, which is the\n * safer failure mode.\n */\nfunction cmcdObjectTypeListEqual(a: CmcdObjectTypeList, b: CmcdObjectTypeList): boolean {\n\tif (a === b) return true\n\tif (a.length !== b.length) return false\n\n\tfor (let i = 0; i < a.length; i++) {\n\t\tconst ai = a[i]\n\t\tconst bi = b[i]\n\t\tif (ai === bi) continue\n\t\tif (typeof ai === 'number' || typeof bi === 'number') return false\n\n\t\t// Both are SfItem<number, ExclusiveRecord<CmcdObjectType, boolean>>\n\t\tif (ai.value !== bi.value) return false\n\n\t\t// ExclusiveRecord: params (when defined) has exactly one key\n\t\tconst ap = ai.params\n\t\tconst bp = bi.params\n\t\tconst ak = ap && Object.keys(ap)[0]\n\t\tconst bk = bp && Object.keys(bp)[0]\n\t\tif (ak !== bk) return false\n\t\tif (ak !== undefined && bk !== undefined && ap && bp && ap[ak as keyof typeof ap] !== bp[bk as keyof typeof bp]) return false\n\t}\n\n\treturn true\n}\n\nconst equal = Object.is\nconst identity = <T>(v: T): T => v\n\n/**\n * Maps each tracked state field to its event type and equality function.\n * Order matters: `update()` fires events in this order for multi-field updates.\n */\nconst STATE_FIELDS: readonly StateFieldEntry[] = /* @__PURE__ */ Array.from(\n\tCMCD_STATE_EVENT_FIELDS,\n\t([event, field]): StateFieldEntry => {\n\t\tif (field === 'br') {\n\t\t\treturn {\n\t\t\t\tevent,\n\t\t\t\tfield,\n\t\t\t\tequal: (a, b) => (a === undefined || b === undefined) ? a === b : cmcdObjectTypeListEqual(a as CmcdObjectTypeList, b as CmcdObjectTypeList),\n\t\t\t\tsnapshot: (v) => (v as CmcdObjectTypeList).slice(),\n\t\t\t}\n\t\t}\n\t\treturn { event, field: field as StateField, equal, snapshot: identity }\n\t},\n)\n\nconst STATE_FIELDS_BY_EVENT: ReadonlyMap<CmcdEventType, StateFieldEntry> = /* @__PURE__ */ new Map(\n\t/* @__PURE__ */ STATE_FIELDS.map(e => [e.event, e]),\n)\n\n/**\n * Maps each event type to the key CTA-5004-B requires beyond `e` and `ts`.\n * Built from the state-change table plus the three event types whose\n * required key rides the caller's per-event data.\n */\nconst CMCD_REQUIRED_EVENT_KEYS: ReadonlyMap<CmcdEventType, CmcdKey> = /* @__PURE__ */ new Map([\n\t.../* @__PURE__ */ CMCD_STATE_EVENT_FIELDS,\n\t[CMCD_EVENT_CUSTOM_EVENT, 'cen'] as const,\n\t[CMCD_EVENT_ERROR, 'ec'] as const,\n\t[CMCD_EVENT_RESPONSE_RECEIVED, 'url'] as const,\n])\n\n/**\n * Whether a required key's value will survive report preparation.\n *\n * This is `isValid` minus its `false` exclusion, plus an empty-array check.\n * `false` must count as usable because `bg: false` is a legitimate value on a\n * backgrounded-mode event, which the encoder emits as `?0`; treating it as\n * unusable would let restoration silently revert a transform that cleared it.\n * Empty strings, empty lists and non-finite numbers are dropped downstream, so\n * a transform substituting one leaves the report short a required key.\n */\nfunction isUsableRequiredValue(value: unknown): boolean {\n\tif (value == null || value === '') {\n\t\treturn false\n\t}\n\n\tif (typeof value === 'number') {\n\t\treturn Number.isFinite(value)\n\t}\n\n\treturn !Array.isArray(value) || value.length > 0\n}\n\n/**\n * Copies an `SfItem`-shaped value and its `params` record.\n *\n * The prototype is preserved because `prepareCmcdData`, the formatter map,\n * validation, and the structured-field encoder all branch on\n * `instanceof SfItem`. A plain spread (and `structuredClone`) would return a\n * prototype-less object and silently change what goes on the wire.\n */\nfunction copyItemValue(value: unknown): unknown {\n\tif (value === null || typeof value !== 'object') {\n\t\treturn value\n\t}\n\n\tconst copy = Object.assign(Object.create(Object.getPrototypeOf(value)), value) as { params?: unknown; }\n\n\tif (copy.params !== null && typeof copy.params === 'object') {\n\t\tcopy.params = { ...copy.params }\n\t}\n\n\treturn copy\n}\n\n/**\n * Copies the nested values of a report in place so a transform cannot mutate\n * the reporter's persistent data, or another target's report for the same\n * event, by mutating an array or an `SfItem` it was handed.\n *\n * Complete for the CMCD value space rather than best-effort: `CmcdValue` and\n * `CmcdCustomValue` admit only primitives, `SfItem<primitive>`, and arrays of\n * those, and `SfItem.params` is a flat record. Called where a transform is\n * configured, on the ended session's store at archival (detaching the frozen\n * snapshot from caller-held references), and on the request's stored\n * player-facing view.\n */\nfunction copyReportValues(data: Cmcd): Cmcd {\n\tconst record = data as Record<string, unknown>\n\n\tfor (const key in record) {\n\t\tconst value = record[key]\n\n\t\tif (Array.isArray(value)) {\n\t\t\tconst copy = new Array(value.length)\n\n\t\t\tfor (let i = 0; i < value.length; i++) {\n\t\t\t\tcopy[i] = copyItemValue(value[i])\n\t\t\t}\n\n\t\t\trecord[key] = copy\n\t\t}\n\t\telse if (value !== null && typeof value === 'object') {\n\t\t\trecord[key] = copyItemValue(value)\n\t\t}\n\t}\n\n\treturn data\n}\n\n/**\n * Decodes the per-call data snapshot a provenance record carries into\n * fresh, encodable report data: tokens revive as `SfToken` and\n * params-bearing items as `SfItem` (`useSymbol: false`), so every value\n * keeps its wire type through re-encoding. Only called in\n * `recordResponseReceived()`. Returns an empty object when the record is\n * absent, carries no snapshot, or the snapshot does not parse (a value\n * this reporter did not write); the response then reports its derived keys\n * over the session's data alone.\n */\nfunction decodeSnapshot(provenance: unknown): Cmcd {\n\tconst encoded = (provenance !== null && typeof provenance === 'object')\n\t\t? (provenance as { data?: unknown; }).data\n\t\t: undefined\n\n\tif (typeof encoded !== 'string' || !encoded) {\n\t\treturn {}\n\t}\n\n\ttry {\n\t\treturn decodeCmcd(encoded, { useSymbol: false }) as Cmcd\n\t}\n\tcatch {\n\t\treturn {}\n\t}\n}\n\n/**\n * Mints a session's frozen base provenance record: the issuing `sid`, and\n * the `cid` in effect at mint time. `update()` re-mints on every `cid`\n * change, so requests issued before a mid-session content change keep the\n * `cid` they were issued under while later requests carry the new one.\n */\nfunction mintProvenance(sid: string, cid: string | undefined): CmcdRequestProvenance {\n\treturn Object.freeze(typeof cid === 'string' && cid ? { sid, cid } : { sid })\n}\n\nfunction defaultRequester(request: HttpRequest): Promise<{ status: number; }> {\n\tconst { url, ...init } = request\n\treturn fetch(url, init)\n}\n\nfunction createCmcdReporterConfig<C>(config: Partial<CmcdReporterConfig<C>>): CmcdReporterConfigNormalized<C> {\n\t// Apply top-level config defaults\n\tconst {\n\t\tversion = CMCD_V2,\n\t\teventTargets = [],\n\t\tsid = uuid(),\n\t\ttransmissionMode = CMCD_QUERY,\n\t\t...rest\n\t} = config\n\n\t// Type-checked, never type-coerced: a numeric string or boolean falls\n\t// back to the default instead of converting, and a Symbol must not\n\t// throw under Math.floor's ToNumber.\n\tconst retention = config.sessionRetention\n\tconst sessionRetention = typeof retention === 'number' ? Math.floor(retention) : NaN\n\n\treturn {\n\t\t...rest,\n\t\tversion,\n\t\ttransmissionMode,\n\t\tsid,\n\t\tsessionRetention: sessionRetention >= 0 ? sessionRetention : 2,\n\t\t// Apply target config defaults\n\t\teventTargets: eventTargets.reduce((acc, target) => {\n\t\t\tif (target?.url && target.events?.length) {\n\t\t\t\tacc.push({\n\t\t\t\t\tversion: target.version || CMCD_V2,\n\t\t\t\t\tenabledKeys: target.enabledKeys?.slice() || [],\n\t\t\t\t\turl: target.url,\n\t\t\t\t\tevents: target.events.slice(),\n\t\t\t\t\tinterval: target.interval ?? CMCD_DEFAULT_TIME_INTERVAL,\n\t\t\t\t\tbatchSize: target.batchSize || 1,\n\t\t\t\t\ttransform: target.transform,\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn acc\n\t\t}, [] as CmcdEventReportConfigNormalized<C>[]),\n\t}\n}\n\ntype CmcdTarget = {\n\tsn: number;\n\tmsdSent: boolean;\n}\n\ntype CmcdEventTarget = CmcdTarget & {\n\t/**\n\t * Finished, encoded report lines awaiting send. Reports are encoded at\n\t * enqueue, so a value that cannot serialize throws inside the recording\n\t * call, and a queued line is immune to later mutation of the values it\n\t * was built from.\n\t */\n\tqueue: string[];\n\tdisposed: boolean;\n}\n\n/**\n * The state owned by one session (one `sid`). Everything CTA-5004-B scopes\n * to the session lives here, so a report that belongs to an earlier session\n * (a response completing after a `sid` change, a re-queued batch) is built\n * from and accounted against its own session rather than the current one.\n */\ntype CmcdSession<C> = {\n\tsid: string;\n\t/**\n\t * Frozen base provenance record for this session: its `sid` and the\n\t * `cid` in effect when the record was minted. Stamped under\n\t * {@link CMCD_REQUEST_PROVENANCE} on every request the reporter\n\t * returns; a request created with per-call data carries a per-request\n\t * record extending it with that data encoded. Re-minted by `update()`\n\t * whenever the session's `cid` changes, so records are request-time\n\t * truth: already-issued requests keep the record they were stamped\n\t * with. Attribution reads the record's `sid`; see `resolveSession()`.\n\t */\n\tprovenance: CmcdRequestProvenance;\n\tdata: Cmcd;\n\tmsd: number;\n\tlastEmitted: Partial<Pick<Cmcd, StateField>>;\n\teventTargets: Map<CmcdEventReportConfigNormalized<C>, CmcdEventTarget>;\n\trequestTarget: CmcdTarget;\n}\n\n/**\n * The CMCD reporter.\n *\n * `C` describes the player's own `customData`, which the reporter passes\n * through to each configured `transform`. It is inferred from the\n * configuration, so annotating a single `transform` types the request in every\n * other one; the default leaves `customData` values `unknown`.\n *\n * @typeParam C - The shape of the player's `customData`. Defaults to\n * `Record<string, unknown>`.\n *\n * @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}\n *\n * @public\n */\nexport class CmcdReporter<C = Record<string, unknown>> {\n\tprivate timeOrigin = performance.timeOrigin || performance.timing?.fetchStart || Date.now() - performance.now()\n\tprivate config: CmcdReporterConfigNormalized<C>\n\n\t/**\n\t * Retained sessions keyed by `sid`, insertion-ordered oldest first, the\n\t * current session last. The ended-session count is capped by\n\t * `config.sessionRetention`. CTA-5004-B expects a `sid` to be unique\n\t * per playback session; a reused one replaces its retained namesake at\n\t * the newest position (see `startSession()`).\n\t */\n\tprivate sessions = new Map<string, CmcdSession<C>>()\n\tprivate session: CmcdSession<C>\n\n\t/**\n\t * Armed time-interval timers by target config. Timers outlive session\n\t * changes (their callbacks report into whichever session is current at\n\t * fire time), so they live on the reporter rather than the session.\n\t */\n\tprivate intervals = new Map<CmcdEventReportConfigNormalized<C>, ReturnType<typeof setInterval>>()\n\tprivate started = false\n\n\tprivate requester: (request: HttpRequest) => Promise<{ status: number; }>\n\n\t/**\n\t * Creates a new CMCD reporter.\n\t *\n\t * @param config - The configuration for the CMCD reporter.\n\t * @param requester - The function to use to send the request.\n\t * The default is a simple wrapper around the\n\t * native `fetch` API.\n\t */\n\tconstructor(config: Partial<CmcdReporterConfig<C>>, requester: (request: HttpRequest) => Promise<{ status: number; }> = defaultRequester) {\n\t\tthis.config = createCmcdReporterConfig(config)\n\t\tthis.session = this.createSession(this.config.sid, {\n\t\t\tcid: this.config.cid,\n\t\t\tv: this.config.version,\n\t\t})\n\t\tthis.sessions.set(this.session.sid, this.session)\n\t\tthis.requester = requester\n\t}\n\n\t/**\n\t * Creates the state for a new session: fresh counters, gates, queues and\n\t * dedup baseline for every configured target.\n\t */\n\tprivate createSession(sid: string, data: Cmcd): CmcdSession<C> {\n\t\tconst eventTargets = new Map<CmcdEventReportConfigNormalized<C>, CmcdEventTarget>()\n\n\t\tfor (const target of this.config.eventTargets) {\n\t\t\teventTargets.set(target, {\n\t\t\t\tsn: 0,\n\t\t\t\tmsdSent: false,\n\t\t\t\tqueue: [],\n\t\t\t\tdisposed: false,\n\t\t\t})\n\t\t}\n\n\t\treturn {\n\t\t\tsid,\n\t\t\t// Frozen because it is handed out on every returned request; the\n\t\t\t// sid value, not the record's identity, is what attributes.\n\t\t\tprovenance: mintProvenance(sid, data.cid),\n\t\t\tdata,\n\t\t\tmsd: NaN,\n\t\t\tlastEmitted: {},\n\t\t\teventTargets,\n\t\t\trequestTarget: {\n\t\t\t\tsn: 0,\n\t\t\t\tmsdSent: false,\n\t\t\t},\n\t\t}\n\t}\n\n\t/**\n\t * Starts the CMCD reporter. Called by the player when the reporter is enabled.\n\t *\n\t * Note: This fires an initial time-interval event immediately (synchronously)\n\t * before the first interval elapses. Ensure CMCD data (sid, cid, etc.) is\n\t * populated before calling start().\n\t */\n\tstart(): void {\n\t\tthis.started = true\n\n\t\t// The initial time-interval event is fired synchronously per target, so a\n\t\t// throwing transform must not abort the loop: later targets would never\n\t\t// have their intervals armed and would report nothing for the session,\n\t\t// and a retried start() would fail on the same target again. Same\n\t\t// continue-then-rethrow contract as `emitEvent()`.\n\t\tlet failure: { error: unknown; } | undefined\n\n\t\t// The fan-out is pinned to the session that was current when start()\n\t\t// was called: a transform can synchronously rotate the session, and\n\t\t// pairing the new session with the old session's targets would let a\n\t\t// report consume another session's sequence numbers.\n\t\tconst session = this.session\n\n\t\tsession.eventTargets.forEach((target, config) => {\n\t\t\t// Disarm any existing timer so repeated start() calls do not leak intervals.\n\t\t\tthis.disarmInterval(config)\n\n\t\t\t// A target disposed via HTTP 410 stays silent for the rest of the\n\t\t\t// session. Armed before the initial event so a throwing transform\n\t\t\t// leaves the timer in the same state a successful start() would,\n\t\t\t// rather than silently disabling the target.\n\t\t\tif (target.disposed || !this.armInterval(config)) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tthis.recordTargetEvent(session, target, config, CMCD_EVENT_TIME_INTERVAL)\n\t\t\t\tthis.processEventTargets()\n\t\t\t}\n\t\t\tcatch (error) {\n\t\t\t\tfailure ??= { error }\n\t\t\t}\n\t\t})\n\n\t\tif (failure) {\n\t\t\tthrow failure.error\n\t\t}\n\t}\n\n\t/**\n\t * Arms the time-interval timer for an event target when its config calls\n\t * for one. Returns whether a timer was armed. The callback reports into\n\t * whichever session is current when it fires.\n\t */\n\tprivate armInterval(config: CmcdEventReportConfigNormalized<C>): boolean {\n\t\t// If the interval is 0 or the TIME_INTERVAL event is not enabled, do not start the interval.\n\t\tif (config.interval === 0 || !config.events.includes(CMCD_EVENT_TIME_INTERVAL)) {\n\t\t\treturn false\n\t\t}\n\n\t\tthis.intervals.set(config, setInterval(() => {\n\t\t\tconst session = this.session\n\t\t\tconst target = session.eventTargets.get(config)\n\n\t\t\tif (target) {\n\t\t\t\tthis.recordTargetEvent(session, target, config, CMCD_EVENT_TIME_INTERVAL)\n\t\t\t\tthis.processEventTargets()\n\t\t\t}\n\t\t}, config.interval * 1000))\n\n\t\treturn true\n\t}\n\n\t/**\n\t * Stops the CMCD reporter. Called by the player when the reporter is disabled.\n\t *\n\t * @param flush - Whether to flush the event targets.\n\t */\n\tstop(flush: boolean = false): void {\n\t\tthis.started = false\n\n\t\tif (flush) {\n\t\t\tthis.flush()\n\t\t}\n\n\t\tfor (const config of this.config.eventTargets) {\n\t\t\tthis.disarmInterval(config)\n\t\t}\n\t}\n\n\t/**\n\t * Forces the sending of all event reports, regardless of the batch size or interval.\n\t * Useful for sending outstanding reports when the player is destroyed or a playback\n\t * session ends.\n\t */\n\tflush(): void {\n\t\tthis.processEventTargets(true)\n\t}\n\n\t/**\n\t * Updates the CMCD data.\n\t *\n\t * Called by the player when data changes. For tracked state fields\n\t * (`sta`, `pr`, `cid`, `bg`, `br`), if the new value differs from the\n\t * last-reported value (the value most recently emitted on the wire for\n\t * that field), the corresponding state-change event is automatically\n\t * fired. Comparing against the last-reported value (rather than the\n\t * previous persisted value) ensures the first state-change event in a\n\t * new session always emits, even when the persisted value didn't change\n\t * across the `sid` boundary.\n\t *\n\t * Multi-field updates fire multiple events in the order: `sta` → `pr` →\n\t * `cid` → `bg` → `br`. The order of keys in the input object does not\n\t * affect the firing order.\n\t *\n\t * To attach snapshot context (e.g., `bl`, `mtp`, `pt`, `ltc`) to a\n\t * state-change event, ensure those fields are in the reporter's data\n\t * before the state field changes. Either include them alongside the\n\t * state field in the same `update()` call, or persist them via earlier\n\t * `update()` calls — auto-fired events emit whatever is currently in\n\t * the persistent data store. This is also how to keep `TIME_INTERVAL`\n\t * reports useful — those events draw from the persistent data store\n\t * with no caller hook for per-event data, so fields the player wants\n\t * in periodic reports must be kept fresh here.\n\t *\n\t * A `sid` change resets the dedup baseline.\n\t *\n\t * `sid` and `msd` are session-owned: the reporter tracks them itself and\n\t * stamps them onto every outgoing report, so this method is the only way\n\t * to change them. A per-call value on {@link CmcdReporter.recordEvent},\n\t * {@link CmcdReporter.createRequestReport}, or\n\t * {@link CmcdReporter.recordResponseReceived} has no effect; response\n\t * attribution is by the provenance record alone.\n\t * `msd` must be a finite number of milliseconds between `0` and\n\t * `999_999_999_999_999` (the RFC 8941 integer maximum); it is rounded to\n\t * the nearest integer, and invalid values are ignored.\n\t *\n\t * @param data - The data to update.\n\t */\n\tupdate(data: Partial<Cmcd>): void {\n\t\tif (data.sid && data.sid !== this.session.sid) {\n\t\t\tthis.startSession(data.sid)\n\t\t}\n\n\t\tconst session = this.session\n\t\tconst { msd } = data\n\n\t\t// CTA-5004-B defines msd as integer milliseconds, sent once per session.\n\t\t// 0 is a valid instant-start value; anything non-finite or negative is\n\t\t// ignored so it can neither reach the wire nor consume the send gate.\n\t\t// The rounded value must also fit an RFC 8941 structured-field integer\n\t\t// (at most 999_999_999_999_999), or serialization throws after the\n\t\t// gate is already consumed.\n\t\tif (typeof msd === 'number' && Number.isFinite(msd) && msd >= 0) {\n\t\t\tconst rounded = Math.round(msd)\n\n\t\t\tif (rounded <= 999_999_999_999_999) {\n\t\t\t\tsession.msd = rounded\n\t\t\t}\n\t\t}\n\n\t\t// sid and msd are session-owned: tracked in their own fields, stripped\n\t\t// from the persistent store, and stamped onto each report at queue time.\n\t\tsession.data = { ...session.data, ...data, sid: undefined, msd: undefined }\n\n\t\t// A cid change re-mints the session's base provenance record, so a\n\t\t// request issued from here on carries the new cid while requests\n\t\t// already in flight keep the one they were issued under. Their late\n\t\t// responses then report the content the request was actually about.\n\t\tif (session.data.cid !== session.provenance.cid) {\n\t\t\tsession.provenance = mintProvenance(session.sid, session.data.cid)\n\t\t}\n\n\t\t// Auto-trigger state-change events for any tracked field whose value\n\t\t// differs from the last wire-emitted value. Comparing against lastEmitted\n\t\t// (not the pre-merge value) ensures correctness after a session change,\n\t\t// and unifies the comparison basis with recordEvent's internal dedup.\n\t\tfor (const entry of STATE_FIELDS) {\n\t\t\tif (entry.field in data && !entry.equal(session.data[entry.field], session.lastEmitted[entry.field])) {\n\t\t\t\tthis.recordEvent(entry.event)\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Starts a new session: the current one is archived in place for stale\n\t * attribution, a fresh one takes over, ended sessions are drained, and\n\t * the oldest are evicted beyond the configured retention.\n\t *\n\t * The data store is carried over, and the archived snapshot is frozen:\n\t * the ended session's value graph is detached first, so nested values\n\t * the caller handed to `update()` can no longer mutate it, and the new\n\t * session starts from a shallow copy of the detached graph, so `cid`,\n\t * `br`, custom keys and the rest survive a `sid` change as they always\n\t * have. Sessions are keyed by `sid`, which CTA-5004-B expects to be\n\t * unique per playback session: reusing one replaces the retained\n\t * namesake, whose remaining state dies as if evicted and whose late\n\t * responses relabel onto the replacement.\n\t */\n\tprivate startSession(sid: string): void {\n\t\tthis.session.data = copyReportValues({ ...this.session.data })\n\t\tthis.session = this.createSession(sid, { ...this.session.data })\n\n\t\t// Map.set keeps an existing key's insertion position, so a reused\n\t\t// sid must be deleted first: re-inserting at the newest position\n\t\t// keeps oldest-first eviction from ever reaching the current\n\t\t// session, and ages out genuinely older sessions ahead of it.\n\t\tthis.sessions.delete(sid)\n\t\tthis.sessions.set(sid, this.session)\n\n\t\t// Drain ended sessions before eviction can destroy their queues: a\n\t\t// partial batch the ended session could never fill again leaves now.\n\t\tthis.processEventTargets()\n\n\t\t// An evicted session's unsent queues die with it, and its stale\n\t\t// responses drop, because its sid no longer names a retained\n\t\t// session. The current session was inserted last, so oldest-first\n\t\t// eviction never reaches it, and `Infinity` retention never evicts.\n\t\tfor (const key of this.sessions.keys()) {\n\t\t\tif (this.sessions.size <= this.config.sessionRetention + 1) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tthis.sessions.delete(key)\n\t\t}\n\n\t\t// Timers keep ticking across session changes. Configs whose timer was\n\t\t// disarmed by a 410 in the previous session re-arm here, because the\n\t\t// new session's targets are fresh; the immediate report start() fires\n\t\t// is not repeated.\n\t\tif (this.started) {\n\t\t\tfor (const config of this.config.eventTargets) {\n\t\t\t\tif (!this.intervals.has(config)) {\n\t\t\t\t\tthis.armInterval(config)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Records an event. Called by the player when an event occurs.\n\t *\n\t * For state-change events (`PLAY_STATE`, `PLAYBACK_RATE`, `CONTENT_ID`,\n\t * `BACKGROUNDED_MODE`, `BITRATE_CHANGE`), this method:\n\t * 1. Persists the dedup field from `data` (if present) into the reporter's\n\t * persistent data store — equivalent to a write-through `update()`.\n\t * 2. Drops the event entirely if the dedup field has no value after the\n\t * write-through (never set, or cleared via `update({ field: undefined })`).\n\t * State-change events without their required field would violate CTA-5004-B.\n\t * 3. Suppresses the event if the field's current value matches the\n\t * last-emitted value (no state transition).\n\t *\n\t * For all other event types, the event is always emitted.\n\t *\n\t * For state-change events, prefer {@link CmcdReporter.update} — including\n\t * for snapshot enrichment via a combined call like\n\t * `update({ sta: 'p', bl: [3000], mtp: [8500] })`. Calling `recordEvent()`\n\t * for a state-change event after `update()` has already auto-fired it\n\t * silently drops the second call's `data`, because dedup suppresses the\n\t * second emission.\n\t *\n\t * Use `recordEvent()` directly for events whose payload is intrinsic to\n\t * the event call — `CUSTOM_EVENT` with `cen`, `ERROR` with `ec`,\n\t * ad-lifecycle events, `MUTE`/`UNMUTE`, `PLAYER_EXPAND`/`PLAYER_COLLAPSE`,\n\t * `SKIP`. For `RESPONSE_RECEIVED`, prefer\n\t * {@link CmcdReporter.recordResponseReceived}, which derives the\n\t * per-response fields automatically.\n\t *\n\t * @param type - The type of event to record.\n\t * @param data - Additional data to record with the event. This data\n\t * only applies to this event report, except for the dedup\n\t * field of a state-change event, which is also persisted\n\t * into the reporter's data store. Session-owned keys\n\t * (`sid`, `msd`) supplied here are ignored; the reporter\n\t * stamps its own values.\n\t */\n\trecordEvent(type: CmcdEventType, data: Partial<Cmcd> = {}): void {\n\t\tthis.emitEvent(this.session, type, data)\n\t}\n\n\t/**\n\t * Records an event across every configured target of a session, applying\n\t * state-change dedup once before per-target fan-out.\n\t *\n\t * @param session - The session the event belongs to. Everything the event\n\t * touches (data store, dedup baseline, counters, queues)\n\t * is that session's; only `recordResponseReceived()` ever\n\t * passes an archived one.\n\t * @param type - The type of event to record.\n\t * @param data - Additional data to record with the event.\n\t * @param request - The media request that triggered the event, when\n\t * one exists. Only `recordResponseReceived()`\n\t * populates this; it is threaded through to each\n\t * target's `transform`.\n\t */\n\tprivate emitEvent(session: CmcdSession<C>, type: CmcdEventType, data: Partial<Cmcd>, request?: HttpRequest): void {\n\t\tconst entry = STATE_FIELDS_BY_EVENT.get(type)\n\t\tif (entry) {\n\t\t\tconst field = entry.field\n\t\t\tconst incoming = data[field]\n\n\t\t\tif (incoming !== undefined) {\n\t\t\t\tObject.assign(session.data, { [field]: incoming })\n\t\t\t}\n\n\t\t\tconst current = session.data[field]\n\n\t\t\t// Never emit a state-change event with a missing required field — per\n\t\t\t// CTA-5004-B these events must carry their dedup field. Catches both\n\t\t\t// \"no value ever set\" and \"previous value was cleared to undefined\".\n\t\t\tif (current === undefined) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (entry.equal(current, session.lastEmitted[field])) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tObject.assign(session.lastEmitted, { [field]: entry.snapshot(current) })\n\t\t}\n\n\t\t// A throwing transform must not abort the fan-out. The dedup baseline\n\t\t// above is already committed and is never rolled back, so aborting here\n\t\t// would strand the transition: targets after the throwing one would\n\t\t// never receive it, and the caller's retry would be deduped away.\n\t\tlet failure: { error: unknown; } | undefined\n\n\t\tsession.eventTargets.forEach((target, config) => {\n\t\t\ttry {\n\t\t\t\tthis.recordTargetEvent(session, target, config, type, data, request)\n\t\t\t}\n\t\t\tcatch (error) {\n\t\t\t\tfailure ??= { error }\n\t\t\t}\n\t\t})\n\n\t\tthis.processEventTargets()\n\n\t\t// Surfaced only once every target has had its turn and the queues have\n\t\t// been processed. Transforms must not throw; this makes the violation\n\t\t// visible without letting it starve unrelated targets.\n\t\tif (failure) {\n\t\t\tthrow failure.error\n\t\t}\n\t}\n\n\t/**\n\t * Records an event for a target. Called by the reporter when an event occurs.\n\t *\n\t * @param target - The target to record the event for.\n\t * @param config - The configuration for the target.\n\t * @param type - The type of event to record.\n\t * @param data - Additional data to record with the event. This data\n\t * only applies to this event report. Persistent data should\n\t * be updated using `update()`.\n\t * @param request - The media request that triggered the event, when\n\t * one exists. Passed to the target's `transform`.\n\t */\n\tprivate recordTargetEvent(session: CmcdSession<C>, target: CmcdEventTarget, config: CmcdEventReportConfigNormalized<C>, type: CmcdEventType, data: Partial<Cmcd> = {}, request?: HttpRequest): void {\n\t\tif (target.disposed || !config.events.includes(type)) {\n\t\t\treturn\n\t\t}\n\n\t\t// The session's sid is stamped over any per-call value here so a\n\t\t// transform sees the session identity the report will carry.\n\t\tconst item: Cmcd = {\n\t\t\t...session.data,\n\t\t\t...data,\n\t\t\tsid: session.sid,\n\t\t\te: type,\n\t\t\tts: data.ts ?? Date.now(),\n\t\t}\n\n\t\tconst { transform } = config\n\n\t\tif (!transform) {\n\t\t\tthis.queueTargetEvent(session, target, config, item, type)\n\t\t\treturn\n\t\t}\n\n\t\t// The spread above is shallow, so nested values are still shared with\n\t\t// the persistent store and with sibling targets' inputs; a transform\n\t\t// gets its own detached copy so in-place mutation reaches neither.\n\t\tcopyReportValues(item)\n\n\t\t// Captured so a transform cannot strip a key the event requires.\n\t\t// `CmcdKey` spans custom keys too, so index through a record view.\n\t\tconst requiredKey = CMCD_REQUIRED_EVENT_KEYS.get(type)\n\t\tconst requiredValue = requiredKey ? (item as Record<string, unknown>)[requiredKey] : undefined\n\t\tconst ts = item.ts\n\n\t\tconst report = transform(item, request)\n\n\t\t// A cancelled report consumes neither a sequence number nor msd.\n\t\tif (report == null) {\n\t\t\treturn\n\t\t}\n\n\t\t// Restore, never fabricate: a required key that was already absent (or\n\t\t// already unusable) before the transform ran was a caller bug, not a\n\t\t// transform bug. Removal and substitution are both covered, because a\n\t\t// value the encoder drops leaves the report just as invalid as a missing\n\t\t// one.\n\t\tif (!isUsableRequiredValue(report.ts)) {\n\t\t\treport.ts = ts\n\t\t}\n\n\t\tif (requiredKey && isUsableRequiredValue(requiredValue) && !isUsableRequiredValue((report as Record<string, unknown>)[requiredKey])) {\n\t\t\tObject.assign(report, { [requiredKey]: requiredValue })\n\t\t}\n\n\t\tthis.queueTargetEvent(session, target, config, report, type)\n\t}\n\n\t/**\n\t * Stamps the reporter-owned fields on a finished event report, encodes it,\n\t * and pushes the wire line to the target's queue.\n\t *\n\t * Called after any transform has run, so a transform cannot bypass the\n\t * target's `events` filter via `e`, break `sn` continuity, or substitute\n\t * the session identity carried by `sid` and `msd`. Encoding here means a\n\t * report that cannot serialize throws inside the recording call that\n\t * produced it, instead of rejecting the batch send and re-queueing\n\t * forever.\n\t *\n\t * @param target - The target to queue the report for.\n\t * @param config - The configuration for the target.\n\t * @param report - The finished report data.\n\t * @param type - The type of event being reported.\n\t */\n\tprivate queueTargetEvent(session: CmcdSession<C>, target: CmcdEventTarget, config: CmcdEventReportConfigNormalized<C>, report: Cmcd, type: CmcdEventType): void {\n\t\treport.e = type\n\t\treport.sn = target.sn++\n\t\treport.sid = session.sid\n\n\t\t// msd may only ride a report through the once-per-target gate, and only\n\t\t// when the target's key filter will retain it (msd is never force-added\n\t\t// at encode time): consuming the gate for a report that filters msd out\n\t\t// would silently drop it for the session. A value smuggled in via\n\t\t// per-call data or a transform is stripped, so the gate stays the\n\t\t// single source of once-per-session semantics.\n\t\tif (!isNaN(session.msd) && !target.msdSent && config.enabledKeys?.includes('msd')) {\n\t\t\treport.msd = session.msd\n\t\t\ttarget.msdSent = true\n\t\t}\n\t\telse {\n\t\t\tdelete report.msd\n\t\t}\n\n\t\ttarget.queue.push(encodeCmcd(report, createEncodingOptions(CMCD_EVENT_MODE, config)))\n\t}\n\n\t/**\n\t * Records a response-received event. Called by the player when a media\n\t * request response has been fully received.\n\t *\n\t * This method automatically derives the `rr` event keys from the\n\t *\n\t * - `url` - the original requested URL (before any redirects)\n\t * - `rc` - the HTTP response status code\n\t * - `ts` - the request initiation time (from `resourceTiming.startTime`)\n\t * - `ttfb` - time to first byte (from `resourceTiming.responseStart`)\n\t * - `ttlb` - time to last byte (from `resourceTiming.duration`)\n\t *\n\t * Additional keys like `ttfbb`, `cmsdd`, `cmsds`, and `smrt` can be\n\t * supplied via the `data` parameter if the player has access to them.\n\t *\n\t * The request's `customData` is generic, so a player can pass a request\n\t * carrying its own taxonomy (e.g. `{ requestType: 'segment' }`) without a\n\t * cast. The reporter reads only the provenance record that\n\t * {@link CmcdReporter.createRequestReport} writes there; every other key\n\t * is left untouched and stays visible to an event target's `transform`\n\t * via its `request` argument.\n\t *\n\t * A reporter given a concrete `C` requires the request to satisfy it, so a\n\t * request the configured transforms could not read is rejected here rather\n\t * than reaching them; see {@link CmcdReporterCustomData}.\n\t *\n\t * The event is attributed to the session that issued the request, and to\n\t * nothing else: the provenance record that\n\t * {@link CmcdReporter.createRequestReport} stored on the request's\n\t * `customData` (under {@link CMCD_REQUEST_PROVENANCE}) selects the\n\t * session by its `sid`, or the response is dropped rather than\n\t * relabeled. There is no other key: a record lost to a serialization\n\t * boundary (and not restored; see the bridge notes on\n\t * {@link CMCD_REQUEST_PROVENANCE}) and a session no longer retained\n\t * (see `CmcdReporterConfig.sessionRetention`) both drop, and a per-call\n\t * `data.sid` cannot substitute. The record is honored wherever its\n\t * `sid` resolves: a request decorated by another reporter configured\n\t * with the same session attributes here, as does a hand-built record.\n\t * A response that completes after a `sid` change reports under its own\n\t * retained session, with that session's data snapshot and sequence\n\t * numbers.\n\t *\n\t * Request-time report keys come from the record's encoded per-call\n\t * `data` snapshot, decoded fresh per response, and the record's `cid`\n\t * reports in place of the session's current one, so a response that\n\t * completes after a mid-session content change keeps the meaning it\n\t * had when its request was issued.\n\t *\n\t * @typeParam RD - The `customData` this request carries. Defaults to the\n\t * reporter's own `C`.\n\t *\n\t * @param response - The HTTP response received.\n\t * @param data - Additional CMCD data to include with the event.\n\t * Values provided here override any auto-derived values.\n\t * Session-owned keys (`sid`, `msd`) supplied here are\n\t * ignored; attribution is by the provenance record alone.\n\t */\n\trecordResponseReceived<RD extends CmcdReporterCustomData<C> = C>(response: HttpResponse<HttpRequest<RD & { cmcd?: Cmcd; [CMCD_REQUEST_PROVENANCE]?: CmcdRequestProvenance }>>, data: Partial<Cmcd> = {}): void {\n\t\tconst { request } = response\n\n\t\tconst url = data.url ?? request?.url\n\n\t\tif (!url) {\n\t\t\treturn\n\t\t}\n\n\t\t// Attribution is by the provenance record alone: its sid names a\n\t\t// retained session, or the response is dropped rather than relabeled.\n\t\tconst provenance = request.customData?.[CMCD_REQUEST_PROVENANCE]\n\t\tconst session = this.resolveSession(provenance)\n\n\t\tif (!session) {\n\t\t\treturn\n\t\t}\n\n\t\t// Request-time report data comes from the per-call snapshot on the\n\t\t// same record, decoded fresh per response, never from the\n\t\t// player-facing `customData.cmcd` object: the snapshot is\n\t\t// reporter-written bytes, immune to caller mutation and lossless\n\t\t// across any boundary the record is carried over.\n\t\tconst cmcd = decodeSnapshot(provenance)\n\n\t\t// The record's cid is the content the request was issued under. It\n\t\t// overrides the session store's current value so a response landing\n\t\t// after a mid-session content change keeps its meaning, and it\n\t\t// yields to the decoded snapshot and per-call data above it.\n\t\tconst { cid } = provenance as { cid?: unknown; }\n\n\t\tconst urlObj = new URL(url)\n\t\turlObj.searchParams.delete(CMCD_PARAM)\n\n\t\tconst derived: Partial<Cmcd> = {\n\t\t\turl: urlObj.toString(),\n\t\t\trc: response.status,\n\t\t}\n\n\t\tconst timing = response.resourceTiming\n\n\t\tif (timing) {\n\t\t\tif (timing.startTime != null) {\n\t\t\t\tderived.ts = Math.round(this.timeOrigin + timing.startTime)\n\n\t\t\t\tif (timing.responseStart != null) {\n\t\t\t\t\tderived.ttfb = Math.round(timing.responseStart - timing.startTime)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (timing.duration != null) {\n\t\t\t\tderived.ttlb = Math.round(timing.duration)\n\t\t\t}\n\t\t}\n\n\t\tthis.emitEvent(session, CMCD_EVENT_RESPONSE_RECEIVED, {\n\t\t\t...(typeof cid === 'string' && cid ? { cid } : undefined),\n\t\t\t...cmcd,\n\t\t\t...derived,\n\t\t\t...data,\n\t\t}, request)\n\t}\n\n\t/**\n\t * Resolves the session a response belongs to: the provenance record's\n\t * `sid` names one of this reporter's retained sessions, or the response\n\t * is dropped. There is no other key — a record that was lost, or that\n\t * names an evicted or never-seen `sid`, resolves nothing, and\n\t * attributing it anywhere else would relabel it. The `sid` is read\n\t * structurally, so a JSON-revived copy of a record attributes exactly,\n\t * and a hand-built record naming a retained session is honored.\n\t */\n\tprivate resolveSession(provenance: unknown): CmcdSession<C> | undefined {\n\t\tif (provenance === null || typeof provenance !== 'object') {\n\t\t\treturn undefined\n\t\t}\n\n\t\tconst { sid } = provenance as { sid?: unknown; }\n\n\t\treturn typeof sid === 'string' ? this.sessions.get(sid) : undefined\n\t}\n\n\t/**\n\t * Applies the CMCD request report data to the request. Called by the player\n\t * before sending the request.\n\t *\n\t * @param req - The request to apply the CMCD request report to.\n\t * @returns The request with the CMCD request report applied.\n\t *\n\t * @deprecated Use {@link CmcdReporter.createRequestReport} instead.\n\t */\n\tapplyRequestReport(req: HttpRequest): HttpRequest {\n\t\treturn this.createRequestReport(req) ?? req\n\t}\n\n\t/**\n\t * Checks if the request reporting is enabled.\n\t *\n\t * @returns `true` if the request reporting is enabled, `false` otherwise.\n\t */\n\tisRequestReportingEnabled(): boolean {\n\t\treturn !!this.config.enabledKeys?.length\n\t}\n\n\t/**\n\t * The provenance record to stamp on a returned request: the session's\n\t * frozen base record, extended with the caller's per-call data encoded\n\t * as a CMCD string when there is any. Requests without per-call data\n\t * share the base record, so decoration stays a single property write.\n\t * The snapshot never contains reporter-stamped fields, and a value that\n\t * cannot encode contributes no snapshot rather than failing the\n\t * request; its response still attributes and reports derived keys over\n\t * session data, matching `decodeSnapshot()`'s tolerance on the read\n\t * side.\n\t */\n\tprivate createRequestProvenance(data: Partial<Cmcd> | undefined, baseUrl: string | undefined): CmcdRequestProvenance {\n\t\tconst base = this.session.provenance\n\n\t\tif (!data) {\n\t\t\treturn base\n\t\t}\n\n\t\ttry {\n\t\t\tconst encoded = encodeCmcd(data as Cmcd, {\n\t\t\t\tversion: this.config.version,\n\t\t\t\treportingMode: CMCD_REQUEST_MODE,\n\t\t\t\tbaseUrl,\n\t\t\t})\n\n\t\t\treturn encoded ? Object.freeze({ ...base, data: encoded }) : base\n\t\t}\n\t\tcatch {\n\t\t\treturn base\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new request with the CMCD request report data applied. Called by the player\n\t * before sending the request.\n\t *\n\t * A reporter given a concrete `C` requires the request's `customData` to\n\t * satisfy it, so a request the configured transform could not read is\n\t * rejected here rather than reaching it; see\n\t * {@link CmcdReporterCustomData}.\n\t *\n\t * @typeParam R - The request being decorated. Its `customData` must satisfy\n\t * the reporter's `C`.\n\t *\n\t * @param request - The request to apply the CMCD request report to.\n\t * @param data - The data to apply to the request. This data only\n\t * applies to this request report. Persistent data\n\t * should be updated using `update()`.\n\t * @returns The request with the CMCD request report applied.\n\t */\n\tcreateRequestReport<R extends HttpRequest<CmcdReporterCustomData<C>> = HttpRequest<C>>(request: R, data?: Partial<Cmcd>): R & CmcdRequestReport<R['customData']> {\n\t\tconst { customData = {}, headers = {}, ...rest } = request\n\t\tconst report = {\n\t\t\t...rest,\n\t\t\theaders: {\n\t\t\t\t...headers,\n\t\t\t},\n\t\t\tcustomData: {\n\t\t\t\t...customData,\n\t\t\t\tcmcd: {},\n\t\t\t\t// Session provenance rides every returned request, including\n\t\t\t\t// ones this method does not decorate (request reporting\n\t\t\t\t// disabled, or a transform cancels below): the request was\n\t\t\t\t// still issued by this session, and its response still needs\n\t\t\t\t// attribution. The per-call data is captured on the record\n\t\t\t\t// here, before any early return, key filter, or transform\n\t\t\t\t// can lose it, so a late response reports the caller's own\n\t\t\t\t// request-time inputs.\n\t\t\t\t[CMCD_REQUEST_PROVENANCE]: this.createRequestProvenance(data, request.url),\n\t\t\t},\n\t\t} as R & CmcdRequestReport<R['customData']>\n\n\t\tif (!this.config.enabledKeys?.length || !report.url) {\n\t\t\treturn report\n\t\t}\n\n\t\t// Request reports are always current-session. The session's sid is\n\t\t// stamped over any per-call value here so a transform sees the\n\t\t// session identity the report will carry.\n\t\tconst session = this.session\n\t\tconst merged: Cmcd = { ...session.data, ...data, sid: session.sid }\n\t\tconst { transform } = this.config\n\t\tlet cmcdData: Cmcd | null = merged\n\n\t\tif (transform) {\n\t\t\t// The spread above is shallow, so nested values are still shared\n\t\t\t// with the persistent store.\n\t\t\tcopyReportValues(merged)\n\n\t\t\t// The caller's request is passed, not the internal clone, so a\n\t\t\t// transform cannot alter the outgoing report through it.\n\t\t\tcmcdData = transform(merged, request as CmcdTransformRequest<C>)\n\n\t\t\t// A cancelled report consumes neither a sequence number nor msd.\n\t\t\tif (cmcdData == null) {\n\t\t\t\treturn report\n\t\t\t}\n\t\t}\n\n\t\t// Reporter-owned fields are stamped after the transform runs.\n\t\tcmcdData.sn = session.requestTarget.sn++\n\t\tcmcdData.sid = session.sid\n\n\t\t// msd may only ride a report through the once-per-session gate; a value\n\t\t// smuggled in via per-call data or the transform is stripped, so the\n\t\t// gate stays the single source of once-per-session semantics. The gate\n\t\t// is consumed after preparation, and only if the key filter retained\n\t\t// msd, so a filtered-out msd is not silently dropped for the session.\n\t\tconst sendMsd = !isNaN(session.msd) && !session.requestTarget.msdSent\n\n\t\tif (sendMsd) {\n\t\t\tcmcdData.msd = session.msd\n\t\t}\n\t\telse {\n\t\t\tdelete cmcdData.msd\n\t\t}\n\n\t\tconst url = new URL(report.url)\n\t\tconst options = createEncodingOptions(CMCD_REQUEST_MODE, this.config, report.url)\n\n\t\t// The player-facing view is detached from the persistent store:\n\t\t// prepareCmcdData builds a fresh object but copies values by\n\t\t// reference, and players read this object to identify requests, so a\n\t\t// shared array would leak mutation into the store. The reporter never\n\t\t// reads it back; the response path works from the encoded snapshot on\n\t\t// the provenance record.\n\t\tconst cmcd = report.customData.cmcd = copyReportValues(prepareCmcdData(cmcdData, options))\n\n\t\tif (sendMsd && cmcd.msd !== undefined) {\n\t\t\tsession.requestTarget.msdSent = true\n\t\t}\n\n\t\tconst encoded = encodePreparedCmcd(cmcd)\n\n\t\tswitch (this.config.transmissionMode) {\n\t\t\tcase CMCD_QUERY:\n\t\t\t\tif (encoded) {\n\t\t\t\t\turl.searchParams.set(CMCD_PARAM, encoded)\n\t\t\t\t\treport.url = url.toString()\n\t\t\t\t}\n\t\t\t\tbreak\n\n\t\t\tcase CMCD_HEADERS:\n\t\t\t\tObject.assign(report.headers, toPreparedCmcdHeaders(cmcd, options.customHeaderMap))\n\t\t\t\tbreak\n\t\t}\n\n\t\treturn report\n\t}\n\n\t/**\n\t * Processes the event targets. Called by the reporter when an event occurs.\n\t *\n\t * @param flush - Whether to flush the event targets.\n\t */\n\tprivate processEventTargets(flush: boolean = false): void {\n\t\tlet reprocess = false\n\n\t\t// Oldest session first, so an archived session's late reports leave\n\t\t// ahead of current traffic.\n\t\tthis.sessions.forEach((session) => {\n\t\t\t// An archived session receives no further regular events, so its\n\t\t\t// queues could never fill a batch again; its remainders are always\n\t\t\t// drain-eligible, preserving the pre-existing behavior of unsent\n\t\t\t// old-sid events draining after a session change.\n\t\t\tconst drain = flush || session !== this.session\n\n\t\t\tsession.eventTargets.forEach((target, config) => {\n\t\t\t\tconst { queue } = target\n\n\t\t\t\t// A disposed target's queue can be non-empty again if a failed\n\t\t\t\t// batch was re-queued after disposal; it must stay unsent.\n\t\t\t\tif (target.disposed || !queue.length) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif (queue.length < config.batchSize && !drain) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tconst deleteCount = drain ? queue.length : config.batchSize\n\t\t\t\tconst events = queue.splice(0, deleteCount)\n\t\t\t\tthis.sendEventReport(session, config, events).catch(() => {\n\t\t\t\t\t// Re-queue events that failed to send. The target belongs\n\t\t\t\t\t// to the batch's own session, so a failure after a session\n\t\t\t\t\t// change re-queues there, never into the current session.\n\t\t\t\t\ttarget.queue.unshift(...events)\n\t\t\t\t})\n\n\t\t\t\treprocess ||= queue.length > 0\n\t\t\t})\n\t\t})\n\n\t\tif (reprocess) {\n\t\t\tthis.processEventTargets()\n\t\t}\n\t}\n\n\t/**\n\t * Sends an event report. Called by the reporter when a batch is ready to be sent.\n\t *\n\t * @param config - The target config to send the event report to.\n\t * @param data - The encoded report lines to send in the event report.\n\t */\n\tprivate async sendEventReport(session: CmcdSession<C>, config: CmcdEventReportConfigNormalized<C>, data: string[]): Promise<void> {\n\t\tconst response = await this.requester({\n\t\t\turl: config.url,\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': CMCD_MIME_TYPE,\n\t\t\t},\n\t\t\tbody: data.join('\\n') + '\\n',\n\t\t})\n\n\t\tconst { status } = response\n\n\t\tif (status === 410) {\n\t\t\t// CTA-5004-B scopes 410 suppression to \"the remainder of the\n\t\t\t// current session\". The batch's own session is disposed, so a\n\t\t\t// delayed 410 that lands after a session change silences the\n\t\t\t// session that sent it, never the one that replaced it.\n\t\t\tthis.disposeEventTarget(session, config)\n\t\t} else if (status === 429 || (status > 499 && status < 600)) {\n\t\t\tthrow new Error(`Event report failed with status ${status}`)\n\t\t}\n\t}\n\n\t/**\n\t * Cancels the time-interval timer for an event target config and clears the\n\t * stored id. Safe to call when no timer is armed (clearInterval(undefined)\n\t * is a no-op).\n\t */\n\tprivate disarmInterval(config: CmcdEventReportConfigNormalized<C>): void {\n\t\tclearInterval(this.intervals.get(config))\n\t\tthis.intervals.delete(config)\n\t}\n\n\t/**\n\t * Silences an event target URL for the remainder of its session: drops the\n\t * queues and blocks further enqueues for every config in the session that\n\t * reports to the URL, per CTA-5004-B's per-target-URL suppression scope,\n\t * and cancels their timers when the session is the live one. Used when the\n\t * collector signals the target is gone (HTTP 410). A session started after\n\t * the disposal is unaffected, since it gets fresh target state.\n\t */\n\tprivate disposeEventTarget(session: CmcdSession<C>, config: CmcdEventReportConfigNormalized<C>): void {\n\t\tsession.eventTargets.forEach((target, sibling) => {\n\t\t\tif (sibling.url !== config.url || target.disposed) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\ttarget.disposed = true\n\t\t\ttarget.queue.length = 0\n\n\t\t\t// The timer belongs to the live session only; an archived session's\n\t\t\t// disposal is bookkeeping and must not silence current reporting.\n\t\t\tif (session === this.session) {\n\t\t\t\tthis.disarmInterval(sibling)\n\t\t\t}\n\t\t})\n\t}\n}\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * Common Media Client Data Streaming Format\n *\n * @enum\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#streaming-format | CTA-5004-B Streaming Format}\n *\n * @public\n */\nexport const CmcdStreamingFormat = {\n\t/**\n\t * MPEG DASH\n\t */\n\tDASH: 'd',\n\n\t/**\n\t * HTTP Live Streaming (HLS)\n\t */\n\tHLS: 'h',\n\n\t/**\n\t * Smooth Streaming\n\t */\n\tSMOOTH: 's',\n\n\t/**\n\t * Other\n\t */\n\tOTHER: 'o',\n} as const\n\n/**\n * @public\n */\nexport type CmcdStreamingFormat = ValueOf<typeof CmcdStreamingFormat>;\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * Common Media Client Data Stream Type\n *\n * @enum\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#stream-type | CTA-5004-B Stream Type}\n *\n * @public\n */\nexport const CmcdStreamType = {\n\t/**\n\t * All segments are available – e.g., VOD\n\t */\n\tVOD: 'v',\n\n\t/**\n\t * Segments become available over time – e.g., LIVE\n\t */\n\tLIVE: 'l',\n\n\t/**\n\t * Low latency stream\n\t */\n\tLOW_LATENCY: 'll',\n} as const\n\n/**\n * @public\n */\nexport type CmcdStreamType = ValueOf<typeof CmcdStreamType>;\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * CMCD validation severity level: error.\n *\n * @public\n */\nexport const CMCD_VALIDATION_SEVERITY_ERROR = 'error' as const\n\n/**\n * CMCD validation severity level: warning.\n *\n * @public\n */\nexport const CMCD_VALIDATION_SEVERITY_WARNING = 'warning' as const\n\n/**\n * CMCD validation severity level.\n *\n * @public\n */\nexport const CmcdValidationSeverity = {\n\tERROR: CMCD_VALIDATION_SEVERITY_ERROR as typeof CMCD_VALIDATION_SEVERITY_ERROR,\n\tWARNING: CMCD_VALIDATION_SEVERITY_WARNING as typeof CMCD_VALIDATION_SEVERITY_WARNING,\n} as const\n\n/**\n * CMCD validation severity level.\n *\n * @public\n */\nexport type CmcdValidationSeverity = ValueOf<typeof CmcdValidationSeverity>;\n","/**\n * Converts a record of header fields to a `Headers` instance if necessary.\n *\n * @param headers - A `Headers` instance or a plain record of header fields.\n * @returns A `Headers` instance.\n *\n * @internal\n */\nexport function ensureHeaders(headers: Record<string, string> | Headers): Headers {\n\treturn headers instanceof Headers ? headers : new Headers(headers)\n}\n","import type { Cmcd } from './Cmcd.ts'\nimport type { CmcdData } from './CmcdData.ts'\nimport type { CmcdDecodeOptions } from './CmcdDecodeOptions.ts'\nimport { CMCD_HEADER_FIELDS } from './CmcdHeaderField.ts'\nimport { decodeCmcd } from './decodeCmcd.ts'\nimport { ensureHeaders } from './ensureHeaders.ts'\nimport { upConvertToV2 } from './upConvertToV2.ts'\n\n/**\n * Decode CMCD data from request headers.\n *\n * @param headers - The request headers to decode.\n * @param options - Options for decoding.\n *\n * @returns The decoded CMCD data.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#header-field-definition | CTA-5004-B Header Field Definition}\n *\n * @public\n *\n * @example\n * {@includeCode ../test/fromCmcdHeaders.test.ts#example}\n */\nexport function fromCmcdHeaders(headers: Record<string, string> | Headers, options: CmcdDecodeOptions & { convertToLatest: true }): Cmcd\nexport function fromCmcdHeaders(headers: Record<string, string> | Headers, options?: CmcdDecodeOptions): CmcdData\nexport function fromCmcdHeaders(headers: Record<string, string> | Headers, options?: CmcdDecodeOptions): CmcdData | Cmcd {\n\tconst h = ensureHeaders(headers)\n\n\tconst result: Record<string, unknown> = {}\n\tfor (const field of CMCD_HEADER_FIELDS) {\n\t\tconst value = h.get(field)\n\t\tif (value) {\n\t\t\tObject.assign(result, decodeCmcd(value))\n\t\t}\n\t}\n\n\tif (options?.convertToLatest) {\n\t\treturn upConvertToV2(result) as Cmcd\n\t}\n\n\treturn result as CmcdData\n}\n","import { CMCD_PARAM } from './CMCD_PARAM.ts'\nimport type { Cmcd } from './Cmcd.ts'\nimport type { CmcdData } from './CmcdData.ts'\nimport type { CmcdDecodeOptions } from './CmcdDecodeOptions.ts'\nimport { decodeCmcd } from './decodeCmcd.ts'\n\n/**\n * Decode CMCD data from a query string.\n *\n * @param query - The query string to decode.\n * @param options - Options for decoding.\n *\n * @returns The decoded CMCD data.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#query-argument-definition | CTA-5004-B Query Argument Definition}\n *\n * @public\n *\n * @example\n * {@includeCode ../test/fromCmcdQuery.test.ts#example}\n */\nexport function fromCmcdQuery(query: string | URLSearchParams, options: CmcdDecodeOptions & { convertToLatest: true }): Cmcd\nexport function fromCmcdQuery(query: string | URLSearchParams, options?: CmcdDecodeOptions): CmcdData\nexport function fromCmcdQuery(query: string | URLSearchParams, options?: CmcdDecodeOptions): CmcdData | Cmcd {\n\tif (typeof query === 'string') {\n\t\tquery = new URLSearchParams(query)\n\t}\n\n\tconst value = query.get(CMCD_PARAM)\n\n\treturn decodeCmcd(value ?? '', options as CmcdDecodeOptions)\n}\n","import type { Cmcd } from './Cmcd.ts'\nimport type { CmcdData } from './CmcdData.ts'\nimport type { CmcdDecodeOptions } from './CmcdDecodeOptions.ts'\nimport { decodeCmcd } from './decodeCmcd.ts'\n\n/**\n * Decode CMCD data from a url encoded string.\n *\n * @param url - The url encoded string to decode.\n * @param options - Options for decoding.\n *\n * @returns The decoded CMCD data.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#query-argument-definition | CTA-5004-B Query Argument Definition}\n *\n * @public\n *\n * @example\n * {@includeCode ../test/fromCmcdUrl.test.ts#example}\n */\nexport function fromCmcdUrl(url: string, options: CmcdDecodeOptions & { convertToLatest: true }): Cmcd\nexport function fromCmcdUrl(url: string, options?: CmcdDecodeOptions): CmcdData\nexport function fromCmcdUrl(url: string, options?: CmcdDecodeOptions): CmcdData | Cmcd {\n\treturn decodeCmcd(decodeURIComponent(url.replace(/^CMCD=/, '')), options as CmcdDecodeOptions)\n}\n","import { CMCD_V2 } from './CMCD_V2.ts'\nimport type { CmcdData } from './CmcdData.ts'\nimport type { CmcdV1Data } from './CmcdData.ts'\n\n/**\n * Check if a CMCD data object is version 1.\n *\n * @param data - The CMCD data object to check.\n *\n * @returns `true` if the data is version 1, `false` otherwise.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/isCmcdV1Data.test.ts#example}\n */\nexport function isCmcdV1Data(data: CmcdData): data is CmcdV1Data {\n\treturn data.v !== CMCD_V2\n}\n","import { CMCD_V2 } from './CMCD_V2.ts'\nimport type { CmcdData } from './CmcdData.ts'\nimport type { CmcdV2Data } from './CmcdData.ts'\n\n/**\n * Check if a CMCD data object is version 2.\n *\n * @param data - The CMCD data object to check.\n *\n * @returns `true` if the data is version 2, `false` otherwise.\n *\n * @public\n *\n * @example\n * {@includeCode ../test/isCmcdV2Data.test.ts#example}\n */\nexport function isCmcdV2Data(data: CmcdData): data is CmcdV2Data {\n\treturn data.v === CMCD_V2\n}\n","import { type SfBareItem, SfItem } from '@svta/cml-structured-field-values'\n\n/**\n * Convert a value to a CMCD value.\n *\n * @param value - The value to convert to a CMCD value.\n * @param params - The parameters to convert to a CMCD value.\n * @returns The CMCD value.\n *\n * @public\n */\nexport function toCmcdValue<V extends SfBareItem, P>(value: V, params?: P): SfItem<V, P> {\n\treturn new SfItem(value, params)\n}\n","import type { CmcdValidationResult } from './CmcdValidationResult.ts'\nimport { CMCD_VALIDATION_SEVERITY_ERROR } from './CmcdValidationSeverity.ts'\n\n/**\n * Merges multiple validation results into a single result.\n *\n * @internal\n */\nexport function mergeValidationResults(...results: CmcdValidationResult[]): CmcdValidationResult {\n\tconst issues = results.flatMap(r => r.issues)\n\treturn {\n\t\tvalid: issues.every(i => i.severity !== CMCD_VALIDATION_SEVERITY_ERROR),\n\t\tissues,\n\t}\n}\n","import { CMCD_V1 } from './CMCD_V1.ts'\nimport type { CmcdValidationOptions } from './CmcdValidationOptions.ts'\n\n/**\n * Resolves the CMCD version from explicit options, the payload's `v` key, or the default (v1).\n *\n * @internal\n */\nexport function resolveVersion(data: Record<string, unknown>, options?: CmcdValidationOptions): number {\n\tif (options?.version === 1 || options?.version === 2) {\n\t\treturn options.version\n\t}\n\n\tconst payloadVersion = data['v']\n\tif (payloadVersion === 1 || payloadVersion === 2) {\n\t\treturn payloadVersion\n\t}\n\n\treturn CMCD_V1\n}\n","import { CMCD_KEYS } from './CMCD_KEYS.ts'\nimport { CMCD_V1 } from './CMCD_V1.ts'\nimport { CMCD_V1_KEYS } from './CMCD_V1_KEYS.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\nimport type { CmcdValidationOptions } from './CmcdValidationOptions.ts'\nimport type { CmcdValidationResult } from './CmcdValidationResult.ts'\nimport { CMCD_VALIDATION_SEVERITY_ERROR } from './CmcdValidationSeverity.ts'\nimport { isCmcdCustomKey } from './isCmcdCustomKey.ts'\nimport { resolveVersion } from './resolveVersion.ts'\n\nconst CMCD_V1_KEY_SET: ReadonlySet<string> = /* @__PURE__ */ new Set(CMCD_V1_KEYS)\nconst CMCD_KEY_SET: ReadonlySet<string> = /* @__PURE__ */ new Set(CMCD_KEYS)\n\n/**\n * Validates that all keys in a CMCD payload are recognized spec keys or valid custom keys.\n *\n * @example\n * {@includeCode ../test/validateCmcdKeys.test.ts#example}\n *\n * @param data - The CMCD payload to validate.\n * @param options - Validation options.\n * @returns The validation result.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#reserved-keys | CTA-5004-B Reserved Keys}\n *\n * @public\n */\nexport function validateCmcdKeys(data: Record<string, unknown>, options?: CmcdValidationOptions): CmcdValidationResult {\n\tconst version = resolveVersion(data, options)\n\tconst validKeySet = version === CMCD_V1 ? CMCD_V1_KEY_SET : CMCD_KEY_SET\n\tconst issues: CmcdValidationResult['issues'] = []\n\n\tfor (const key of Object.keys(data)) {\n\t\tif (isCmcdCustomKey(key as CmcdKey)) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif (!validKeySet.has(key)) {\n\t\t\tissues.push({\n\t\t\t\tkey,\n\t\t\t\tmessage: `Unknown CMCD key \"${key}\" for version ${version}.`,\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t\t})\n\t\t}\n\t}\n\n\treturn {\n\t\tvalid: issues.length === 0,\n\t\tissues,\n\t}\n}\n","import { CMCD_EVENT_KEYS } from './CMCD_EVENT_KEYS.ts'\nimport { CMCD_RESPONSE_KEYS } from './CMCD_RESPONSE_KEYS.ts'\nimport { CMCD_V1 } from './CMCD_V1.ts'\nimport { CMCD_EVENT_CUSTOM_EVENT, CMCD_EVENT_ERROR, CMCD_EVENT_RESPONSE_RECEIVED } from './CmcdEventType.ts'\nimport { CMCD_STATE_EVENT_FIELDS } from './CMCD_STATE_EVENT_FIELDS.ts'\nimport { CMCD_EVENT_MODE, CMCD_REQUEST_MODE } from './CmcdReportingMode.ts'\nimport type { CmcdValidationIssue } from './CmcdValidationIssue.ts'\nimport type { CmcdValidationOptions } from './CmcdValidationOptions.ts'\nimport type { CmcdValidationResult } from './CmcdValidationResult.ts'\nimport { CMCD_VALIDATION_SEVERITY_ERROR, CMCD_VALIDATION_SEVERITY_WARNING } from './CmcdValidationSeverity.ts'\nimport { resolveVersion } from './resolveVersion.ts'\n\n/**\n * Validates the structural rules of a CMCD payload.\n *\n * @example\n * {@includeCode ../test/validateCmcdStructure.test.ts#example}\n *\n * @param data - The CMCD payload to validate.\n * @param options - Validation options.\n * @returns The validation result.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#data-payload-definition-what-data-to-send | CTA-5004-B Data Payload Definition}\n *\n * @public\n */\nexport function validateCmcdStructure(data: Record<string, unknown>, options?: CmcdValidationOptions): CmcdValidationResult {\n\tconst version = resolveVersion(data, options)\n\tconst issues: CmcdValidationIssue[] = []\n\n\t// Request mode checks\n\tif (options?.reportingMode === CMCD_REQUEST_MODE) {\n\t\tfor (const key of CMCD_EVENT_KEYS) {\n\t\t\tif (key in data) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey,\n\t\t\t\t\tmessage: `Event key \"${key}\" must not be present in request mode.`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\tfor (const key of CMCD_RESPONSE_KEYS) {\n\t\t\tif (key in data) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey,\n\t\t\t\t\tmessage: `Response key \"${key}\" must not be present in request mode.`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\t// Event mode checks\n\tif (options?.reportingMode === CMCD_EVENT_MODE) {\n\t\tif (!('e' in data)) {\n\t\t\tissues.push({\n\t\t\t\tkey: 'e',\n\t\t\t\tmessage: 'Event mode requires the \"e\" key to be present.',\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t})\n\t\t}\n\t\tif (!('ts' in data)) {\n\t\t\tissues.push({\n\t\t\t\tkey: 'ts',\n\t\t\t\tmessage: 'Event mode requires the \"ts\" key to be present.',\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t})\n\t\t}\n\t}\n\n\t// Custom event checks\n\tif ('e' in data) {\n\t\tif (data['e'] === CMCD_EVENT_CUSTOM_EVENT) {\n\t\t\tif (!('cen' in data)) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey: 'cen',\n\t\t\t\t\tmessage: 'Custom event (e=\"ce\") requires the \"cen\" key to be present.',\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif ('cen' in data) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey: 'cen',\n\t\t\t\t\tmessage: 'The \"cen\" key must only be present when e=\"ce\".',\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\t// Response-received key restriction and required url\n\t\tif (data['e'] === CMCD_EVENT_RESPONSE_RECEIVED) {\n\t\t\tif (!('url' in data)) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey: 'url',\n\t\t\t\t\tmessage: 'Response received event (e=\"rr\") requires the \"url\" key to be present.',\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor (const key of CMCD_RESPONSE_KEYS) {\n\t\t\t\tif (key in data) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Response key \"${key}\" must only be present when e=\"rr\".`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// State-change events require their associated field\n\t\tfor (const [eventType, requiredField] of CMCD_STATE_EVENT_FIELDS) {\n\t\t\tif (data['e'] === eventType && !(requiredField in data)) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey: requiredField,\n\t\t\t\t\tmessage: `State-change event (e=\"${eventType}\") requires the \"${requiredField}\" key to be present.`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\t// Error event requires ec\n\t\tif (data['e'] === CMCD_EVENT_ERROR && !('ec' in data)) {\n\t\t\tissues.push({\n\t\t\t\tkey: 'ec',\n\t\t\t\tmessage: 'Error event (e=\"e\") requires the \"ec\" key to be present.',\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t})\n\t\t}\n\t}\n\n\t// Version key checks\n\tif ('v' in data && data['v'] !== 1 && data['v'] !== 2) {\n\t\tissues.push({\n\t\t\tkey: 'v',\n\t\t\tmessage: `Unsupported CMCD version \"${String(data['v'])}\". Expected 1 or 2.`,\n\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t})\n\t}\n\telse if (version > 1 && !('v' in data)) {\n\t\tissues.push({\n\t\t\tkey: 'v',\n\t\t\tmessage: 'Version 2 payloads require the \"v\" key to be present.',\n\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t})\n\t}\n\telse if (version === CMCD_V1 && 'v' in data) {\n\t\tissues.push({\n\t\t\tkey: 'v',\n\t\t\tmessage: 'Version 1 payloads should omit the \"v\" key (v1 is the default).',\n\t\t\tseverity: CMCD_VALIDATION_SEVERITY_WARNING\n\t\t})\n\t}\n\n\treturn {\n\t\tvalid: issues.every(i => i.severity !== CMCD_VALIDATION_SEVERITY_ERROR),\n\t\tissues,\n\t}\n}\n","/**\n * CMCD key value type: inner list of numbers with token identifiers.\n *\n * @internal\n */\nexport const CMCD_KEY_TYPE_NUMBER_LIST = 'number[]' as const\n\n/**\n * CMCD key value type: inner list of strings.\n *\n * @internal\n */\nexport const CMCD_KEY_TYPE_STRING_LIST = 'string[]' as const\n\n/**\n * CMCD key value type: integer.\n *\n * @internal\n */\nexport const CMCD_KEY_TYPE_INTEGER = 'integer' as const\n\n/**\n * CMCD key value type: number (decimal).\n *\n * @internal\n */\nexport const CMCD_KEY_TYPE_NUMBER = 'number' as const\n\n/**\n * CMCD key value type: boolean.\n *\n * @internal\n */\nexport const CMCD_KEY_TYPE_BOOLEAN = 'boolean' as const\n\n/**\n * CMCD key value type: string.\n *\n * @internal\n */\nexport const CMCD_KEY_TYPE_STRING = 'string' as const\n\n/**\n * CMCD key value type: token.\n *\n * @internal\n */\nexport const CMCD_KEY_TYPE_TOKEN = 'token' as const\n\n/**\n * Maps each CMCD spec key to its expected value type for v2.\n * Keys that differ between v1 and v2 are handled by CMCD_V1_KEY_TYPE_OVERRIDES.\n *\n * @internal\n */\nexport const CMCD_KEY_TYPES: Record<string, string> = {\n\t// List keys (inner list of integers/numbers with token identifiers)\n\tab: CMCD_KEY_TYPE_NUMBER_LIST,\n\tbl: CMCD_KEY_TYPE_NUMBER_LIST,\n\tbr: CMCD_KEY_TYPE_NUMBER_LIST,\n\tbsa: CMCD_KEY_TYPE_NUMBER_LIST,\n\tbsd: CMCD_KEY_TYPE_NUMBER_LIST,\n\tbsda: CMCD_KEY_TYPE_NUMBER_LIST,\n\tlab: CMCD_KEY_TYPE_NUMBER_LIST,\n\tlb: CMCD_KEY_TYPE_NUMBER_LIST,\n\tmtp: CMCD_KEY_TYPE_NUMBER_LIST,\n\tpb: CMCD_KEY_TYPE_NUMBER_LIST,\n\ttab: CMCD_KEY_TYPE_NUMBER_LIST,\n\ttb: CMCD_KEY_TYPE_NUMBER_LIST,\n\ttbl: CMCD_KEY_TYPE_NUMBER_LIST,\n\ttpb: CMCD_KEY_TYPE_NUMBER_LIST,\n\n\t// String array keys (inner list of strings)\n\tec: CMCD_KEY_TYPE_STRING_LIST,\n\tnor: CMCD_KEY_TYPE_STRING_LIST,\n\n\t// Integer keys\n\td: CMCD_KEY_TYPE_INTEGER,\n\tdfa: CMCD_KEY_TYPE_INTEGER,\n\tdl: CMCD_KEY_TYPE_INTEGER,\n\tltc: CMCD_KEY_TYPE_INTEGER,\n\tmsd: CMCD_KEY_TYPE_INTEGER,\n\tpt: CMCD_KEY_TYPE_INTEGER,\n\trc: CMCD_KEY_TYPE_INTEGER,\n\trtp: CMCD_KEY_TYPE_INTEGER,\n\tsn: CMCD_KEY_TYPE_INTEGER,\n\tts: CMCD_KEY_TYPE_INTEGER,\n\tttfb: CMCD_KEY_TYPE_INTEGER,\n\tttfbb: CMCD_KEY_TYPE_INTEGER,\n\tttlb: CMCD_KEY_TYPE_INTEGER,\n\tv: CMCD_KEY_TYPE_INTEGER,\n\n\t// Number keys\n\tpr: CMCD_KEY_TYPE_NUMBER,\n\n\t// Boolean keys\n\tbg: CMCD_KEY_TYPE_BOOLEAN,\n\tbs: CMCD_KEY_TYPE_BOOLEAN,\n\tnr: CMCD_KEY_TYPE_BOOLEAN,\n\tsu: CMCD_KEY_TYPE_BOOLEAN,\n\n\t// String keys\n\tcdn: CMCD_KEY_TYPE_STRING,\n\tcen: CMCD_KEY_TYPE_STRING,\n\tcid: CMCD_KEY_TYPE_STRING,\n\tcmsdd: CMCD_KEY_TYPE_STRING,\n\tcmsds: CMCD_KEY_TYPE_STRING,\n\tcs: CMCD_KEY_TYPE_STRING,\n\th: CMCD_KEY_TYPE_STRING,\n\tnrr: CMCD_KEY_TYPE_STRING,\n\tsid: CMCD_KEY_TYPE_STRING,\n\tsmrt: CMCD_KEY_TYPE_STRING,\n\turl: CMCD_KEY_TYPE_STRING,\n\n\t// Token keys\n\te: CMCD_KEY_TYPE_TOKEN,\n\tot: CMCD_KEY_TYPE_TOKEN,\n\tsf: CMCD_KEY_TYPE_TOKEN,\n\tst: CMCD_KEY_TYPE_TOKEN,\n\tsta: CMCD_KEY_TYPE_TOKEN,\n}\n\n/**\n * Maps keys to their v1-specific types when they differ from v2.\n *\n * @internal\n */\nexport const CMCD_V1_KEY_TYPE_OVERRIDES: Record<string, string> = {\n\tbl: CMCD_KEY_TYPE_INTEGER,\n\tbr: CMCD_KEY_TYPE_NUMBER,\n\tmtp: CMCD_KEY_TYPE_INTEGER,\n\ttb: CMCD_KEY_TYPE_NUMBER,\n\tnor: CMCD_KEY_TYPE_STRING,\n}\n","/**\n * Maps CMCD keys to their maximum string length.\n *\n * @internal\n */\nexport const CMCD_STRING_LENGTH_LIMITS: Record<string, number> = {\n\tsid: 64,\n\tcid: 128,\n\tcdn: 128,\n\th: 128,\n\tcen: 64,\n}\n\n/**\n * Maximum length for custom key values.\n *\n * @internal\n */\nexport const CMCD_CUSTOM_KEY_VALUE_MAX_LENGTH = 64\n","/**\n * Maps token keys to their valid values.\n *\n * @internal\n */\nexport const CMCD_TOKEN_VALUES: Record<string, readonly string[]> = {\n\te: ['bc', 'ps', 'pr', 'e', 't', 'c', 'b', 'm', 'um', 'pe', 'pc', 'rr', 'as', 'ae', 'abs', 'abe', 'sk', 'ce'] as const,\n\tot: ['m', 'a', 'v', 'av', 'i', 'c', 'tt', 'k', 'o'] as const,\n\tsf: ['d', 'h', 's', 'o'] as const,\n\tst: ['v', 'l', 'll'] as const,\n\tsta: ['s', 'p', 'k', 'r', 'a', 'w', 'e', 'f', 'q', 'd'] as const,\n}\n","import { SfItem } from '@svta/cml-structured-field-values'\nimport { CMCD_KEY_TYPE_BOOLEAN, CMCD_KEY_TYPE_INTEGER, CMCD_KEY_TYPE_NUMBER, CMCD_KEY_TYPE_NUMBER_LIST, CMCD_KEY_TYPE_STRING, CMCD_KEY_TYPE_STRING_LIST, CMCD_KEY_TYPE_TOKEN, CMCD_KEY_TYPES, CMCD_V1_KEY_TYPE_OVERRIDES } from './CMCD_KEY_TYPES.ts'\nimport { CMCD_CUSTOM_KEY_VALUE_MAX_LENGTH, CMCD_STRING_LENGTH_LIMITS } from './CMCD_STRING_LENGTH_LIMITS.ts'\nimport { CMCD_TOKEN_VALUES } from './CMCD_TOKEN_VALUES.ts'\nimport { CMCD_V1 } from './CMCD_V1.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\nimport type { CmcdValidationIssue } from './CmcdValidationIssue.ts'\nimport type { CmcdValidationOptions } from './CmcdValidationOptions.ts'\nimport type { CmcdValidationResult } from './CmcdValidationResult.ts'\nimport { CMCD_VALIDATION_SEVERITY_ERROR, CMCD_VALIDATION_SEVERITY_WARNING } from './CmcdValidationSeverity.ts'\nimport { isCmcdCustomKey } from './isCmcdCustomKey.ts'\nimport { resolveVersion } from './resolveVersion.ts'\n\nconst HUNDRED_ROUNDING_KEYS = /* @__PURE__ */ new Set(['bl', 'dl', 'mtp', 'rtp', 'tbl'])\nconst INTEGER_ROUNDING_KEYS = /* @__PURE__ */ new Set(['br', 'd', 'tb'])\n\nfunction isFiniteNumber(value: unknown): value is number {\n\treturn typeof value === 'number' && Number.isFinite(value)\n}\n\nfunction validateListValue(key: string, value: unknown, issues: CmcdValidationIssue[]): void {\n\tif (!Array.isArray(value)) {\n\t\tissues.push({\n\t\t\tkey,\n\t\t\tmessage: `Key \"${key}\" must be an array.`,\n\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t})\n\t\treturn\n\t}\n\tfor (let i = 0; i < value.length; i++) {\n\t\tconst element = value[i]\n\t\tif (element instanceof SfItem) {\n\t\t\tif (!isFiniteNumber(element.value)) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey,\n\t\t\t\t\tmessage: `Key \"${key}\" array element [${i}] must be a finite number.`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\telse if (!isFiniteNumber(element)) {\n\t\t\tissues.push({\n\t\t\t\tkey,\n\t\t\t\tmessage: `Key \"${key}\" array element [${i}] must be a finite number.`,\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t})\n\t\t}\n\t}\n}\n\nfunction validateStringArrayValue(key: string, value: unknown, issues: CmcdValidationIssue[]): void {\n\tif (!Array.isArray(value)) {\n\t\tissues.push({\n\t\t\tkey,\n\t\t\tmessage: `Key \"${key}\" must be an array.`,\n\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t})\n\t\treturn\n\t}\n\tfor (let i = 0; i < value.length; i++) {\n\t\tconst element = value[i]\n\t\tif (element instanceof SfItem) {\n\t\t\tif (typeof element.value !== 'string') {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey,\n\t\t\t\t\tmessage: `Key \"${key}\" array element [${i}] must be a string.`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\telse if (typeof element !== 'string') {\n\t\t\tissues.push({\n\t\t\t\tkey,\n\t\t\t\tmessage: `Key \"${key}\" array element [${i}] must be a string.`,\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t})\n\t\t}\n\t}\n}\n\n/**\n * Validates that all values in a CMCD payload conform to the expected types and constraints.\n *\n * @example\n * {@includeCode ../test/validateCmcdValues.test.ts#example}\n *\n * @param data - The CMCD payload to validate.\n * @param options - Validation options.\n * @returns The validation result.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#reserved-keys | CTA-5004-B Reserved Keys}\n *\n * @public\n */\nexport function validateCmcdValues(data: Record<string, unknown>, options?: CmcdValidationOptions): CmcdValidationResult {\n\tconst version = resolveVersion(data, options)\n\tconst issues: CmcdValidationIssue[] = []\n\n\tfor (const [key, value] of Object.entries(data)) {\n\t\tif (isCmcdCustomKey(key as CmcdKey)) {\n\t\t\t// Custom key values must be string or token, max 64 chars\n\t\t\tif (typeof value !== 'string') {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey,\n\t\t\t\t\tmessage: `Custom key \"${key}\" value must be a string or token.`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t\telse if (value.length > CMCD_CUSTOM_KEY_VALUE_MAX_LENGTH) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey,\n\t\t\t\t\tmessage: `Custom key \"${key}\" value exceeds maximum length of ${CMCD_CUSTOM_KEY_VALUE_MAX_LENGTH}.`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// Version value check\n\t\tif (key === 'v') {\n\t\t\tif (value !== 1 && value !== 2) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey,\n\t\t\t\t\tmessage: `Key \"v\" must be 1 or 2.`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t})\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// Determine expected type\n\t\tlet expectedType = CMCD_KEY_TYPES[key]\n\t\tif (!expectedType) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif (version === CMCD_V1 && key in CMCD_V1_KEY_TYPE_OVERRIDES) {\n\t\t\texpectedType = CMCD_V1_KEY_TYPE_OVERRIDES[key]\n\t\t}\n\n\t\tswitch (expectedType) {\n\t\t\tcase CMCD_KEY_TYPE_INTEGER:\n\t\t\t\tif (!isFiniteNumber(value) || !Number.isInteger(value)) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Key \"${key}\" must be a finite integer.`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\telse if (HUNDRED_ROUNDING_KEYS.has(key) && (value as number) % 100 !== 0) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Key \"${key}\" should be rounded to the nearest 100.`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_WARNING\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tbreak\n\n\t\t\tcase CMCD_KEY_TYPE_NUMBER:\n\t\t\t\tif (!isFiniteNumber(value)) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Key \"${key}\" must be a finite number.`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\telse if (HUNDRED_ROUNDING_KEYS.has(key) && (value as number) % 100 !== 0) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Key \"${key}\" should be rounded to the nearest 100.`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_WARNING\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\telse if (INTEGER_ROUNDING_KEYS.has(key) && !Number.isInteger(value)) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Key \"${key}\" should be rounded to an integer.`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_WARNING\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tbreak\n\n\t\t\tcase CMCD_KEY_TYPE_BOOLEAN:\n\t\t\t\tif (typeof value !== 'boolean') {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Key \"${key}\" must be a boolean.`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tbreak\n\n\t\t\tcase CMCD_KEY_TYPE_STRING:\n\t\t\t\tif (typeof value !== 'string') {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Key \"${key}\" must be a string.`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\telse if (key in CMCD_STRING_LENGTH_LIMITS && value.length > CMCD_STRING_LENGTH_LIMITS[key]) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Key \"${key}\" exceeds maximum length of ${CMCD_STRING_LENGTH_LIMITS[key]}.`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tbreak\n\n\t\t\tcase CMCD_KEY_TYPE_TOKEN: {\n\t\t\t\tconst validValues = CMCD_TOKEN_VALUES[key]\n\t\t\t\tif (validValues && !validValues.includes(value as string)) {\n\t\t\t\t\tissues.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmessage: `Key \"${key}\" has invalid token value \"${String(value)}\". Expected one of: ${validValues.join(', ')}.`,\n\t\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcase CMCD_KEY_TYPE_NUMBER_LIST:\n\t\t\t\tvalidateListValue(key, value, issues)\n\t\t\t\tbreak\n\n\t\t\tcase CMCD_KEY_TYPE_STRING_LIST:\n\t\t\t\tvalidateStringArrayValue(key, value, issues)\n\t\t\t\tbreak\n\t\t}\n\t}\n\n\treturn {\n\t\tvalid: issues.every(i => i.severity !== CMCD_VALIDATION_SEVERITY_ERROR),\n\t\tissues,\n\t}\n}\n","import type { CmcdValidationOptions } from './CmcdValidationOptions.ts'\nimport type { CmcdValidationResult } from './CmcdValidationResult.ts'\nimport { mergeValidationResults } from './mergeValidationResults.ts'\nimport { validateCmcdKeys } from './validateCmcdKeys.ts'\nimport { validateCmcdStructure } from './validateCmcdStructure.ts'\nimport { validateCmcdValues } from './validateCmcdValues.ts'\n\n/**\n * Validates a CMCD payload by checking keys, values, and structure.\n *\n * @example\n * {@includeCode ../test/validateCmcd.test.ts#example}\n *\n * @param data - The CMCD payload to validate.\n * @param options - Validation options.\n * @returns The validation result.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#data-payload-definition-what-data-to-send | CTA-5004-B Data Payload Definition}\n *\n * @public\n */\nexport function validateCmcd(data: Record<string, unknown>, options?: CmcdValidationOptions): CmcdValidationResult {\n\treturn mergeValidationResults(\n\t\tvalidateCmcdKeys(data, options),\n\t\tvalidateCmcdValues(data, options),\n\t\tvalidateCmcdStructure(data, options),\n\t)\n}\n","import type { CmcdData } from './CmcdData.ts'\nimport type { CmcdEventsValidationResult } from './CmcdEventsValidationResult.ts'\nimport { CMCD_EVENT_MODE } from './CmcdReportingMode.ts'\nimport type { CmcdValidationOptions } from './CmcdValidationOptions.ts'\nimport type { CmcdValidationResult } from './CmcdValidationResult.ts'\nimport { CMCD_VALIDATION_SEVERITY_ERROR } from './CmcdValidationSeverity.ts'\nimport { decodeCmcd } from './decodeCmcd.ts'\nimport { mergeValidationResults } from './mergeValidationResults.ts'\nimport { validateCmcd } from './validateCmcd.ts'\n\n/**\n * Validates a raw CMCD string as an event-mode payload.\n *\n * This function decodes the string internally and validates it with\n * `reportingMode` set to `'event'`. The input may contain multiple\n * newline-separated events (e.g. an `application/cmcd` POST body), in which\n * case each line is validated independently and the results are merged.\n *\n * @param cmcd - The raw CMCD-encoded string to validate. May contain\n * multiple newline-separated event lines.\n * @param options - Validation options (excluding `reportingMode`).\n * @returns The validation result including decoded data per event line.\n *\n * @example\n * {@includeCode ../test/validateCmcdEvents.test.ts#example}\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#body-definition | CTA-5004-B Body Definition}\n *\n * @public\n */\nexport function validateCmcdEvents(cmcd: string, options?: Omit<CmcdValidationOptions, 'reportingMode'>): CmcdEventsValidationResult {\n\tconst opts = { ...options, reportingMode: CMCD_EVENT_MODE } as const\n\tconst lines = cmcd.split(/\\r?\\n/).filter(line => line.length > 0)\n\n\tif (lines.length === 0) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tissues: [{\n\t\t\t\tmessage: 'Empty event mode payload. At least one event line is required.',\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t\t}],\n\t\t\tdata: [],\n\t\t}\n\t}\n\n\tconst decodedLines: CmcdData[] = []\n\tconst lineResults: CmcdValidationResult[] = []\n\n\tfor (let i = 0; i < lines.length; i++) {\n\t\ttry {\n\t\t\tconst data = decodeCmcd(lines[i])\n\t\t\tdecodedLines.push(data)\n\t\t\tlineResults.push(validateCmcd(data, opts))\n\t\t} catch {\n\t\t\tdecodedLines.push({} as CmcdData)\n\t\t\tlineResults.push({\n\t\t\t\tvalid: false,\n\t\t\t\tissues: [{\n\t\t\t\t\tmessage: `Failed to decode event line ${i + 1}: invalid structured field syntax.`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t\t\t}],\n\t\t\t})\n\t\t}\n\t}\n\n\tconst result = mergeValidationResults(...lineResults)\n\treturn { ...result, data: decodedLines }\n}\n","import type { HttpRequest } from '@svta/cml-utils'\nimport { CMCD_MIME_TYPE } from './CMCD_MIME_TYPE.ts'\nimport type { CmcdEventsValidationResult } from './CmcdEventsValidationResult.ts'\nimport type { CmcdValidationOptions } from './CmcdValidationOptions.ts'\nimport { CMCD_VALIDATION_SEVERITY_ERROR } from './CmcdValidationSeverity.ts'\nimport { ensureHeaders } from './ensureHeaders.ts'\nimport { validateCmcdEvents } from './validateCmcdEvents.ts'\n\n/**\n * Validates a full HTTP request as an event-mode payload.\n *\n * Accepts an {@link @svta/cml-utils!HttpRequest | HttpRequest} object.\n *\n * This function validates that the request uses the POST method and has\n * the correct `Content-Type` header (`application/cmcd`) in addition to\n * validating the body content via {@link validateCmcdEvents}.\n *\n * @param request - An `HttpRequest` to validate.\n * @param options - Validation options (excluding `reportingMode`).\n * @returns The validation result including decoded data per event line.\n *\n * @example {@includeCode ../test/validateCmcdEventReport.test.ts#example}\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#event-mode | CTA-5004-B Event Mode}\n *\n * @public\n */\nexport function validateCmcdEventReport(request: HttpRequest, options?: Omit<CmcdValidationOptions, 'reportingMode'>): CmcdEventsValidationResult {\n\tconst issues: CmcdEventsValidationResult['issues'] = []\n\n\tif (request.method !== 'POST') {\n\t\tissues.push({\n\t\t\tmessage: `Invalid HTTP method '${request.method ?? 'GET'}'. Event reports must use POST.`,\n\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t})\n\t}\n\n\tconst contentType = request.headers ? ensureHeaders(request.headers).get('Content-Type') : undefined\n\n\tif (!contentType) {\n\t\tissues.push({\n\t\t\tmessage: `Missing Content-Type header. Event reports must use '${CMCD_MIME_TYPE}'.`,\n\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t})\n\t} else {\n\t\tconst mediaType = contentType.split(';')[0].trim().toLowerCase()\n\t\tif (mediaType !== CMCD_MIME_TYPE) {\n\t\t\tissues.push({\n\t\t\t\tmessage: `Invalid Content-Type '${mediaType}'. Event reports must use '${CMCD_MIME_TYPE}'.`,\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t\t})\n\t\t}\n\t}\n\n\tconst body = request.body\n\tif (body === undefined || body === null) {\n\t\tissues.push({\n\t\t\tmessage: 'Missing request body. Event reports must include a body.',\n\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t})\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tissues,\n\t\t\tdata: [],\n\t\t}\n\t}\n\n\tif (typeof body !== 'string') {\n\t\tissues.push({\n\t\t\tmessage: 'Request body must be a string.',\n\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t})\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tissues,\n\t\t\tdata: [],\n\t\t}\n\t}\n\n\tconst bodyResult = validateCmcdEvents(body, options)\n\n\treturn {\n\t\tvalid: issues.length === 0 && bodyResult.valid,\n\t\tissues: [...issues, ...bodyResult.issues],\n\t\tdata: bodyResult.data,\n\t}\n}\n","import { CMCD_HEADER_MAP } from './CMCD_HEADER_MAP.ts'\nimport type { CmcdData } from './CmcdData.ts'\nimport type { CmcdDataValidationResult } from './CmcdDataValidationResult.ts'\nimport { type CmcdHeaderField, CMCD_HEADER_FIELDS } from './CmcdHeaderField.ts'\nimport type { CmcdKey } from './CmcdKey.ts'\nimport { CMCD_REQUEST_MODE } from './CmcdReportingMode.ts'\nimport type { CmcdValidationOptions } from './CmcdValidationOptions.ts'\nimport type { CmcdValidationResult } from './CmcdValidationResult.ts'\nimport { CMCD_VALIDATION_SEVERITY_ERROR } from './CmcdValidationSeverity.ts'\nimport { decodeCmcd } from './decodeCmcd.ts'\nimport { ensureHeaders } from './ensureHeaders.ts'\nimport { isCmcdCustomKey } from './isCmcdCustomKey.ts'\nimport { mergeValidationResults } from './mergeValidationResults.ts'\nimport { validateCmcd } from './validateCmcd.ts'\n\n/**\n * Validates CMCD HTTP headers by checking shard placement and payload validity.\n *\n * This function accepts raw CMCD header strings, decodes each shard\n * internally, verifies that each key is placed in its correct header shard,\n * then merges all shards and runs full payload validation (keys, values, and\n * structure) on the merged data.\n *\n * @example\n * {@includeCode ../test/validateCmcdHeaders.test.ts#example}\n *\n * @param headers - A `Headers` instance or a record of CMCD header fields to their raw encoded string values.\n * @param options - Validation options (excluding `reportingMode`).\n * @returns The validation result including decoded data.\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#header-field-definition | CTA-5004-B Header Field Definition}\n *\n * @public\n */\nexport function validateCmcdHeaders(headers: Record<string, string> | Headers, options?: Omit<CmcdValidationOptions, 'reportingMode'>): CmcdDataValidationResult {\n\tconst h = ensureHeaders(headers)\n\tconst issues: CmcdValidationResult['issues'] = []\n\tconst decoded: Partial<Record<CmcdHeaderField, Record<string, unknown>>> = {}\n\n\tfor (const headerField of CMCD_HEADER_FIELDS) {\n\t\tconst raw = h.get(headerField)\n\t\tif (!raw) {\n\t\t\tcontinue\n\t\t}\n\n\t\tlet shard: Record<string, unknown>\n\t\ttry {\n\t\t\tshard = decodeCmcd(raw)\n\t\t} catch {\n\t\t\tissues.push({\n\t\t\t\tkey: headerField,\n\t\t\t\tmessage: `Failed to decode \"${headerField}\" header: invalid structured field syntax.`,\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\t\tdecoded[headerField] = shard\n\n\t\tfor (const key of Object.keys(shard)) {\n\t\t\tif (isCmcdCustomKey(key as CmcdKey)) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconst expectedHeader = CMCD_HEADER_MAP[key as keyof typeof CMCD_HEADER_MAP]\n\t\t\tif (expectedHeader && expectedHeader !== headerField) {\n\t\t\t\tissues.push({\n\t\t\t\t\tkey,\n\t\t\t\t\tmessage: `Key \"${key}\" is in \"${headerField}\" but should be in \"${expectedHeader}\".`,\n\t\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\tconst shardResult: CmcdValidationResult = {\n\t\tvalid: issues.length === 0,\n\t\tissues,\n\t}\n\n\tconst merged: Record<string, unknown> = Object.assign({}, ...CMCD_HEADER_FIELDS.map(f => decoded[f]).filter(Boolean))\n\tconst payloadResult = validateCmcd(merged, { ...options, reportingMode: CMCD_REQUEST_MODE })\n\n\tconst result = mergeValidationResults(shardResult, payloadResult)\n\treturn { ...result, data: merged as CmcdData }\n}\n","import type { HttpRequest } from '@svta/cml-utils'\nimport { CMCD_PARAM } from './CMCD_PARAM.ts'\nimport type { CmcdData } from './CmcdData.ts'\nimport type { CmcdDataValidationResult } from './CmcdDataValidationResult.ts'\nimport { type CmcdHeaderField, CMCD_HEADER_FIELDS } from './CmcdHeaderField.ts'\nimport { CMCD_REQUEST_MODE } from './CmcdReportingMode.ts'\nimport type { CmcdValidationOptions } from './CmcdValidationOptions.ts'\nimport { CMCD_VALIDATION_SEVERITY_ERROR } from './CmcdValidationSeverity.ts'\nimport { decodeCmcd } from './decodeCmcd.ts'\nimport { ensureHeaders } from './ensureHeaders.ts'\nimport { validateCmcd } from './validateCmcd.ts'\nimport { validateCmcdHeaders } from './validateCmcdHeaders.ts'\n\n/**\n * Validates CMCD data from a request as a request-mode payload.\n *\n * Accepts a\n * {@link https://developer.mozilla.org/en-US/docs/Web/API/Request | Request}\n * object or an {@link @svta/cml-utils!HttpRequest | HttpRequest} object.\n *\n * The function checks for CMCD data in the HTTP headers first. If CMCD\n * headers are found, validation includes shard-placement checks via\n * {@link validateCmcdHeaders}. Otherwise, the CMCD query parameter is\n * extracted from the URL and validated.\n *\n * @param request - A `Request` or `HttpRequest` to validate.\n * @param options - Validation options (excluding `reportingMode`).\n * @returns The validation result including decoded data.\n *\n * @example\n * {@includeCode ../test/validateCmcdRequest.test.ts#example}\n *\n * @see {@link https://cta-wave.github.io/Resources/common-media-client-data--cta-5004-b.html#request-mode | CTA-5004-B Request Mode}\n *\n * @public\n */\nexport function validateCmcdRequest(request: Request | HttpRequest, options?: Omit<CmcdValidationOptions, 'reportingMode'>): CmcdDataValidationResult {\n\tconst headers = extractHeaderRecord(request.headers)\n\n\tif (headers) {\n\t\treturn validateCmcdHeaders(headers, options)\n\t}\n\n\tconst param = new URL(request.url).searchParams.get(CMCD_PARAM)\n\n\tif (!param) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tissues: [{\n\t\t\t\tmessage: 'No CMCD data found in request headers or query parameters.',\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t\t}],\n\t\t\tdata: {} as CmcdData,\n\t\t}\n\t}\n\n\tlet data: CmcdData\n\ttry {\n\t\tdata = decodeCmcd(param)\n\t} catch {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tissues: [{\n\t\t\t\tmessage: 'Failed to decode CMCD query parameter: invalid structured field syntax.',\n\t\t\t\tseverity: CMCD_VALIDATION_SEVERITY_ERROR,\n\t\t\t}],\n\t\t\tdata: {} as CmcdData,\n\t\t}\n\t}\n\n\tconst result = validateCmcd(data, { ...options, reportingMode: CMCD_REQUEST_MODE })\n\treturn { ...result, data }\n}\n\nfunction extractHeaderRecord(headers: Headers | Record<string, string> | undefined): Partial<Record<CmcdHeaderField, string>> | undefined {\n\tif (!headers) {\n\t\treturn undefined\n\t}\n\n\tconst h = ensureHeaders(headers)\n\tconst result: Partial<Record<CmcdHeaderField, string>> = {}\n\tlet found = false\n\n\tfor (const field of CMCD_HEADER_FIELDS) {\n\t\tconst value = h.get(field)\n\n\t\tif (value) {\n\t\t\tresult[field] = value\n\t\t\tfound = true\n\t\t}\n\t}\n\n\treturn found ? result : undefined\n}\n"],"mappings":"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"}
|