// @ts-check /** * A record of the singular events of a session in the browser's console * (F12), for finding faults: pages, images, notebook pages, exports, the * co-host right, the connection, and what the input device delivers. * Nothing continuous goes here (Andy, 2026-10-08). * * Since 2026-10-10 the same record, plus a trace of the input events * (every press, release and cancellation, not the movement between), is * kept in memory and shown in the Session window with a Copy button, so * that a guest on a tablet, with no console to open, can send it when * the pen misbehaves (Andy's iPad, where the Pencil stopped for a while * now and then). */ /** How many entries are kept; the oldest go first. */ const KEPT = 400; /** @type {string[]} */ const entries = []; /** @type {(() => void) | null} Told of every new entry. */ let listener = null; /** @returns {string} The time to the millisecond, HH:MM:SS.mmm. */ function now() { const date = new Date(); const two = (/** @type {number} */ n) => String(n).padStart(2, '0'); return `${two(date.getHours())}:${two(date.getMinutes())}:${two(date.getSeconds())}.` + String(date.getMilliseconds()).padStart(3, '0'); } /** @param {string} what */ function keep(what) { entries.push(`${now()} ${what}`); if (entries.length > KEPT) entries.shift(); listener?.(); } /** A singular event: the console and the record. @param {string} what */ export function log(what) { console.log(`Kokkoja ${new Date().toLocaleTimeString()}: ${what}`); keep(what); } /** An input event: the record only. @param {string} what */ export function trace(what) { keep(what); } /** @returns {string} The record, one entry a line. */ export function logText() { return entries.join('\n'); } /** @param {(() => void) | null} onEntry Called at every new entry. */ export function watchLog(onEntry) { listener = onEntry; }