Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | 2x 2x 2x 2x 2x 64x 64x 60x 60x 60x 60x 672x 60x 4x 4x 80x 4x 24x 25x 24x 38x 39x 38x 1x 15x 1x 14x 14x 4x 10x 10x 2x 8x 2x 6x 2x 4x | const HEX = '0123456789abcdef';
const ALL_ZEROS = /^0+$/;
const TRACE_ID_RX = /^[0-9a-f]{32}$/;
const SPAN_ID_RX = /^[0-9a-f]{16}$/;
const VERSION_RX = /^[0-9a-f]{2}$/;
/**
* Produce `chars` random lowercase hex characters, cryptographically strong
* when the platform provides `crypto.getRandomValues` (Math.random fallback
* for exotic embedders).
*
* @param {number} chars - even count of hex characters to produce
* @returns {string}
*/
function randomHex(chars) {
// Stryker disable next-line ConditionalExpression,StringLiteral: equivalent - globalThis always exists in every runnable JS environment we can test; the guard is for exotic embedders
const cryptoObj = typeof globalThis !== 'undefined' && globalThis.crypto;
if (cryptoObj && typeof cryptoObj.getRandomValues === 'function') {
const bytes = new Uint8Array(chars / 2);
cryptoObj.getRandomValues(bytes);
let out = '';
for (const byte of bytes) {
out += HEX[byte >> 4] + HEX[byte & 15];
}
return out;
}
let out = '';
for (let i = 0; i < chars; i++) {
out += HEX[(Math.random() * 16) | 0];
}
return out;
}
/**
* Generate a new W3C-compatible trace id (32 lowercase hex chars; the
* all-zero id is invalid per Trace Context and is never produced).
*
* @returns {string}
*/
export function newTraceId() {
let id;
do {
id = randomHex(32);
} while (ALL_ZEROS.test(id));
return id;
}
/**
* Generate a new W3C-compatible span/signal id (16 lowercase hex chars; the
* all-zero id is invalid per Trace Context and is never produced).
*
* @returns {string}
*/
export function newSignalId() {
let id;
do {
id = randomHex(16);
} while (ALL_ZEROS.test(id));
return id;
}
/**
* Format a signal stamp or record as a W3C `traceparent` header value:
* `00-<traceId>-<signalId>-01` (version `00`, flags `01` = sampled).
*
* @param {{ traceId: string, signalId: string }} stamp - a chain stamp or a
* `TraceRecord` (structurally compatible)
* @returns {string} e.g. `00-<32 hex>-<16 hex>-01`
*/
export function toTraceparent({ traceId, signalId }) {
return `00-${traceId}-${signalId}-01`;
}
/**
* Parse a W3C `traceparent` header value into trace continuation context.
*
* Tolerant per the Trace Context spec: case and surrounding whitespace are
* normalized, and future versions with extra dash-separated fields are
* accepted (at least 4 parts; extras ignored). Rejected as malformed: a
* non-hex or forbidden (`ff`) version, and non-hex, wrong-length, or
* all-zero trace/parent ids.
*
* @param {string} header
* @returns {{ traceId: string, parentId: string } | null} null when malformed
*/
export function parseTraceparent(header) {
if (typeof header !== 'string') {
return null;
}
const parts = header.trim().toLowerCase().split('-');
if (parts.length < 4) {
return null;
}
const [version, traceId, parentId] = parts;
if (!VERSION_RX.test(version) || version === 'ff') {
return null;
}
if (!TRACE_ID_RX.test(traceId) || ALL_ZEROS.test(traceId)) {
return null;
}
if (!SPAN_ID_RX.test(parentId) || ALL_ZEROS.test(parentId)) {
return null;
}
return { traceId, parentId };
}
|