Jev's request log: every request this page makes of Jev, newest first, shown in the pane under the editor (JevLog.jsx) in place of popups. The booth adds a line when a section is asked about and fills it in when the answer lands (JevBoothEffects); ⏭ and autoplay add what Jev picked (JevPicks.jsx). Kept for the page's life, across songs, at most LOG_MAX lines; nothing is stored or sent anywhere.
7export const LOG_MAX = 200;
9let entries = []; 10let nextId = 1; 11const listeners = new Set(); 12const changed = () => { 13 for (const l of listeners) l(); 14}; 15 16export const jevLog = { 17 subscribe(l) { 18 listeners.add(l); 19 return () => listeners.delete(l); 20 }, 21 get: () => entries, 22 // A new line at the top: { status: 'asking' | 'answered' | 'fallback' | 'picked' | 'error', text, song?, ms? }. 23 // Returns its id, to update it when its answer lands. 24 add(entry, now = Date.now()) { 25 const id = nextId++; 26 entries = [{ ...entry, id, at: now }, ...entries].slice(0, LOG_MAX); 27 changed(); 28 return id; 29 }, 30 // Fills in a line in place: it keeps its place in the log. 31 update(id, fields) { 32 if (!entries.some((e) => e.id === id)) return; 33 entries = entries.map((e) => (e.id === id ? { ...e, ...fields } : e)); 34 changed(); 35 }, 36 clear() { 37 entries = []; 38 changed(); 39 }, 40};