receivedSpans
The spans a page sent, as /__tcm/traces takes them: at most 200, each checked field by field (ids as W3C's,
a kind a page records, times near now, a definition the codebase has, a few plain attributes); a span that
doesn't fit is left out, a field that doesn't is dropped. Undefined if it isn't a batch of spans at all.
import type { ReceivedSpan } from "#codebase/tcmts/cli/web"; export function receivedSpans( body: unknown, known: (hash: string) => boolean, now = Date.now(), ): ReceivedSpan[] | undefined { const list = (body as { spans?: unknown } | null)?.spans; if (!Array.isArray(list) || list.length > 200) return undefined; const id = (v: unknown, n: number) => typeof v === "string" && v.length === n && /^[0-9a-f]+$/.test(v) && !/^0+$/.test(v) ? v : undefined; const hash = (v: unknown) => typeof v === "string" && /^[a-z2-7]{52}$/.test(v) && known(v) ? v : undefined; const out: ReceivedSpan[] = []; for (const raw of list) { if (!raw || typeof raw !== "object") continue; const s = raw as Record<string, unknown>; const trace = id(s.trace, 32); const span = id(s.id, 16); const kind = s.kind === "client" || s.kind === "view" || s.kind === "navigate" || s.kind === "error" ? s.kind : undefined; const name = typeof s.name === "string" && s.name && s.name.length <= 200 ? s.name : undefined; const start = typeof s.start === "number" && Math.abs(s.start - now) < 86_400_000 ? s.start : undefined; const dur = typeof s.dur === "number" && s.dur >= 0 && s.dur <= 3_600_000 ? s.dur : undefined; if (!trace || !span || !kind || !name || start === undefined || dur === undefined) continue; const attrs: ReceivedSpan["attrs"] = {}; if (s.attrs && typeof s.attrs === "object") for (const [k, v] of Object.entries(s.attrs).slice(0, 20)) { if (!/^[\w.]{1,64}$/.test(k)) continue; if (k === "tcm.from") { const from = hash(v); if (from) attrs[k] = from; } else if (typeof v === "string") attrs[k] = v.slice(0, 500); else if ((typeof v === "number" && Number.isFinite(v)) || typeof v === "boolean") attrs[k] = v; } const parent = id(s.parent, 16); const h = hash(s.hash); const link = typeof s.link === "string" && /^00-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f]{2}$/.test(s.link) ? s.link : undefined; out.push({ trace, id: span, ...(parent ? { parent } : {}), kind, name, ...(h ? { hash: h } : {}), start, dur, ...(typeof s.error === "string" ? { error: s.error.slice(0, 4000) } : {}), attrs, ...(link ? { link } : {}), }); } return out; }