77 lines
2.6 KiB
JavaScript
77 lines
2.6 KiB
JavaScript
// shared/logEvent.js — canonical event shape for UI/download/replay/analyze.
|
|||
|
|
// One source of truth. All four consumers import this.
|
||
|
|
//
|
||
|
|
// Canonical event:
|
||
|
|
// {
|
||
|
|
// id, ts, type, message,
|
||
|
|
// encounterId, encounterName, encounterPath,
|
||
|
|
// payload, // forward patch (null for no-op)
|
||
|
|
// undo_payload, // { encounterPath, updates, redo } or null
|
||
|
|
// undone, // bool
|
||
|
|
// snapshot // { round, currentTurnParticipantId, turnOrderIds, activeIds } or null
|
||
|
|
// }
|
||
|
|
//
|
||
|
|
// Old logs (pre-refactor): { timestamp, message, encounterName, undo }.
|
||
|
|
// normalizeEvent fills defaults + lifts legacy undo into undo_payload.
|
||
|
|
|
||
|
|
const DEFAULTS = {
|
||
|
|
ts: 0,
|
||
|
|
type: 'unknown',
|
||
|
|
message: '',
|
||
|
|
encounterId: null,
|
||
|
|
encounterName: null,
|
||
|
|
encounterPath: null,
|
||
|
|
payload: null,
|
||
|
|
undo_payload: null,
|
||
|
|
undone: false,
|
||
|
|
snapshot: null,
|
||
|
|
};
|
||
|
|
|
||
|
|
// Canonical lean event shape:
|
||
|
|
// {
|
||
|
|
// id, ts, type, message,
|
||
|
|
// encounterId, encounterName, encounterPath,
|
||
|
|
// participantId, participantName, // nullable (pause/nextTurn have none)
|
||
|
|
// delta, // type-specific scalars (nullable)
|
||
|
|
// undo, // id-based inverse (nullable)
|
||
|
|
// undone, // bool
|
||
|
|
// snapshot // {round, currentTurnParticipantId, turnOrderIds, activeIds}
|
||
|
|
// }
|
||
|
|
// Legacy logs (pre-refactor, no type): display message only. Not undoable.
|
||
|
|
// Old bloated logs (payload/undo_payload): normalized to lean — payload dropped,
|
||
|
|
// undo_payload lifted to undo. Both display fine; undo expands via expandUndo.
|
||
|
|
function normalizeEvent(raw) {
|
||
|
|
if (!raw) return null;
|
||
|
|
if (!raw.type || raw.type === 'unknown') return null;
|
||
|
|
const id = raw.id || (raw.path ? raw.path.split('/').pop() : null);
|
||
|
|
return {
|
||
|
|
id,
|
||
|
|
ts: raw.ts || raw.timestamp || 0,
|
||
|
|
type: raw.type,
|
||
|
|
message: raw.message || '',
|
||
|
|
encounterId: raw.encounterId || null,
|
||
|
|
encounterName: raw.encounterName || null,
|
||
|
|
encounterPath: raw.encounterPath || null,
|
||
|
|
participantId: raw.participantId || null,
|
||
|
|
participantName: raw.participantName || null,
|
||
|
|
delta: raw.delta || null,
|
||
|
|
undo: raw.undo || raw.undo_payload || null,
|
||
|
|
undone: !!raw.undone,
|
||
|
|
snapshot: raw.snapshot || null,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
// Serialize array of raw log entries (DB rows) → canonical JSON string.
|
||
|
|
// Legacy logs (no type) dropped by normalizeEvent. Sorted ascending by ts.
|
||
|
|
function serializeEvents(rawLogs) {
|
||
|
|
return JSON.stringify(
|
||
|
|
(rawLogs || [])
|
||
|
|
.map(normalizeEvent)
|
||
|
|
.filter(Boolean)
|
||
|
|
.sort((a, b) => a.ts - b.ts),
|
||
|
|
null, 2
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
module.exports = { normalizeEvent, serializeEvents, DEFAULTS };
|