export function parsePack(text: string) { if (Buffer.byteLength(text) > 1_048_576) throw Error("pack too large"); const p = JSON.parse(text); if ( p.schemaVersion !== 1 || !Array.isArray(p.rows) || !Array.isArray(p.redactions) || !Number.isFinite(Date.parse(p.observedAt)) ) throw Error("invalid context pack"); for (const r of p.rows) { if ( !r.object?.uid || typeof r.reason !== "string" || typeof r.type !== "string" || !Number.isInteger(r.count) || r.count < 1 || !Array.isArray(r.eventUIDs) || !r.eventUIDs.length || r.eventUIDs.some((x) => typeof x !== "string" || !x) || !Number.isFinite(Date.parse(r.firstOccurrence)) || !Number.isFinite(Date.parse(r.lastOccurrence)) || Date.parse(r.firstOccurrence) > Date.parse(r.lastOccurrence) ) throw Error("invalid timeline row"); } return p; } const escape = (s: any) => String(s ?? "").replace( /[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[ c ]!, ); export function timeline(p: any) { const rows = p.rows .map( (r: any) => `${escape(r.firstOccurrence)}last ${escape(r.lastOccurrence)}${escape(r.object.namespace)}/${escape(r.object.name)}UID ${escape(r.object.uid)} / revision ${escape(r.revision ?? "unknown")}${escape(r.reason)} (${r.count})${escape(r.investigation)}${r.eventUIDs.map(escape).join(", ")}`, ) .join(""); const payload = JSON.stringify(p).replaceAll("<", "\\u003c"); return `Kubernetes event storyboard

Kubernetes event storyboard

Observed ${escape(p.observedAt)}. Occurrence time is shown separately.

${rows}
OccurrenceObject identityEvidenceEvent UIDs

${p.redactions.map(escape).join("; ")}. Event reasons suggest investigations, not proven causes.

`; }