The @svta/cml-cmcd library provides a set of composable validation functions for verifying that CMCD payloads conform to the CTA-5004 (v1) and CTA-5004-A (v2) specifications. These are useful for validating payloads on the receiving end — for example, in an analytics server that collects CMCD event reports, or in a CDN log processor that inspects CMCD request data.
There are three main validation functions, each targeting a different aspect of CMCD compliance:
| Function | Purpose |
|---|---|
validateCmcd |
Orchestrator — runs key, value, and structure checks |
validateCmcdRequest |
Validates a Request or HttpRequest as request-mode data |
validateCmcdEvents |
Validates a multi-line text/cmcd body as event-mode data |
All validators return a CmcdValidationResult:
type CmcdValidationResult = {
valid: boolean; // true if zero errors (warnings are OK)
issues: CmcdValidationIssue[];
};
type CmcdValidationIssue = {
key?: string;
message: string;
severity: CmcdValidationSeverity; // 'error' | 'warning'
};
A common use case is validating CMCD v2 event reports received via POST. The payload is typically a text/cmcd body containing newline-separated CMCD-encoded strings, or application/json.
validateCmcdEventsThe validateCmcdEvents function accepts a raw CMCD string and validates it as an event-mode payload. It supports multi-line text/cmcd bodies directly — each non-empty line is validated independently and the results are merged. An empty payload (no non-empty lines) is treated as an error.
import { validateCmcdEvents } from "@svta/cml-cmcd";
// Validate a complete text/cmcd POST body
const body = `e=ps,sid="session-1",ts=1700000000000,sta=p,v=2
e=t,sid="session-1",ts=1700000001000,bl=(5000),v=2`;
const result = validateCmcdEvents(body);
if (!result.valid) {
console.error("Invalid CMCD event:", result.issues);
}
A single-line string works as well:
import { validateCmcdEvents } from "@svta/cml-cmcd";
const result = validateCmcdEvents(
'e=ps,sid="session-1",ts=1700000000000,sta=p,v=2',
);
text/cmcd manuallyThe validateCmcdEvents function is designed to validate multi-line text/cmcd bodies directly. However, if you need to validate a single-line string, you can decode the CMCD string and validate the data manually (this is what validateCmcdRequest does internally).
import { decodeCmcd, validateCmcd } from "@svta/cml-cmcd";
// Simulated POST body (text/cmcd)
const body = `e=ps,sid="session-1",ts=1700000000000,sta=p,v=2
e=t,sid="session-1",ts=1700000001000,bl=(5000),v=2`;
// Parse each line and validate
const lines = body.split("\n");
for (const line of lines) {
const data = decodeCmcd(line);
const result = validateCmcd(data, { reportingMode: "event" });
if (!result.valid) {
console.error("Invalid CMCD event:", result.issues);
}
}
In request mode, CMCD data is attached to segment requests via query parameters or HTTP headers. The validator ensures that event-only and response-only keys are not present.
validateCmcdRequestThe validateCmcdRequest function accepts a Request object or an HttpRequest object from @svta/cml-utils. It checks for CMCD headers first — if any CMCD header shards are found, it delegates to validateCmcdHeaders for shard-placement verification. Otherwise, it extracts the CMCD query parameter from the URL.
import { validateCmcdRequest } from "@svta/cml-cmcd";
// From a Request with CMCD headers
const request = new Request("https://cdn.example.com/seg.mp4", {
headers: {
"CMCD-Object": "br=5000,d=4000,ot=v",
"CMCD-Request": "bl=25000",
"CMCD-Session": 'sid="abc"',
},
});
const headerResult = validateCmcdRequest(request);
// From a Request with CMCD in the query parameter
const queryRequest = new Request(
"https://cdn.example.com/seg.mp4?CMCD=br%3D5000%2Cbl%3D25000",
);
const queryResult = validateCmcdRequest(queryRequest);
// From an HttpRequest object
const httpRequestResult = validateCmcdRequest({
url: "https://cdn.example.com/seg.mp4?CMCD=br%3D5000%2Cbl%3D25000",
});
The validateCmcdRequest function is designed to validate the CMCD query parameter from the URL. However, if you need to validate the CMCD query parameter manually, you can extract it from the URL and validate the data using the validateCmcd function.
import { fromCmcdQuery, validateCmcd } from "@svta/cml-cmcd";
// Extract CMCD from a request URL's query string
const url = new URL(
"https://cdn.example.com/seg.mp4?CMCD=br%3D5000%2Cbl%3D25000%2Cd%3D4000%2Cot%3Dv%2Csid%3D%22abc%22",
);
const data = fromCmcdQuery(url.searchParams);
const result = validateCmcd(data, { reportingMode: "request" });
if (!result.valid) {
console.error("Invalid CMCD request data:", result.issues);
}
When CMCD is transmitted via HTTP headers, you can validate the headers manually using the validateCmcdHeaders function.
import { validateCmcdHeaders } from "@svta/cml-cmcd";
// Pass raw header strings directly — decoding is handled internally.
// Request mode validation is applied automatically since headers are
// only used in request mode.
const result = validateCmcdHeaders({
"CMCD-Object": "br=5000,d=4000,ot=v",
"CMCD-Request": "bl=25000",
"CMCD-Session": 'sid="abc",sf=d,st=v',
});
if (!result.valid) {
// Issues may include shard placement errors and/or payload validation errors
console.error("Validation issues:", result.issues);
}
The validators automatically detect the CMCD version from the v key in the payload. If v is absent, version 1 is assumed per the spec. You can override this with the version option.
import { validateCmcd } from "@svta/cml-cmcd";
// Version inferred from payload (v=2)
const v2Result = validateCmcd({ v: 2, br: [5000], sid: "abc" });
// Version explicitly set via options
const v1Result = validateCmcd({ br: 5000, sid: "abc" }, { version: 1 });
sta, ec, ab) are rejected when validating as v1bl is an integer in v1 but an inner list (array) in v2v key; v1 payloads should omit itA payload is considered valid if it contains zero errors. Warnings indicate spec recommendations that are not strict violations.
import { validateCmcd, CMCD_VALIDATION_SEVERITY_ERROR } from "@svta/cml-cmcd";
const result = validateCmcd({ v: 2, bl: [150], sid: "abc" });
// Separate errors from warnings
const errors = result.issues.filter(
(i) => i.severity === CMCD_VALIDATION_SEVERITY_ERROR,
);
const warnings = result.issues.filter(
(i) => i.severity !== CMCD_VALIDATION_SEVERITY_ERROR,
);
console.log(`Valid: ${result.valid}`);
console.log(`Errors: ${errors.length}, Warnings: ${warnings.length}`);
// bl=150 produces a warning (should be rounded to nearest 100)
// but the payload is still valid
import { validateCmcdEvents } from "@svta/cml-cmcd";
function validateAndLog(body: string): boolean {
const result = validateCmcdEvents(body);
for (const issue of result.issues) {
const level = issue.severity === "error" ? "ERROR" : "WARN";
const key = issue.key ? `[${issue.key}] ` : "";
console.log(`${level}: ${key}${issue.message}`);
}
return result.valid;
}
Custom keys (keys containing a hyphen, e.g., com.example-mykey) are recognized by all validators:
validateCmcdKeys — accepts custom keys without errorvalidateCmcdValues — checks that custom key values are strings with a max length of 64 characters, and that the key name contains a hyphenvalidateCmcdHeaders — allows custom keys in any header shardimport { validateCmcdValues } from "@svta/cml-cmcd";
const result = validateCmcdValues({
"com.example-debug": "enabled",
"x-player-version": "2.1.0",
});
// result.valid === true