// Log-file mode resolution for fileuploader.log: // - "single" → one file: fileuploader.log // - "daily" → per-day: fileuploader-YYYY-MM-DD.log // - "session" → per-launch: fileuploader-session-YYYY-MM-DD_HH-MM-SS-.log // // Pure functions only — no fs, no Date.now() at call time — so they unit-test // cleanly and the main.js call sites pass in `new Date()` + the session stamp. // // MIGRATION TRAP this lib protects against: the legacy boolean was named // `sessionLog` but actually toggled *daily* mode. A naive rename would silently // flip every per-day user onto per-session. normalizeLogMode below maps the // legacy `sessionLog: true` to "daily", NOT "session". Read logMode everywhere // downstream; do not derive from sessionLog at call sites. // // Loaded both as CommonJS (main.js, tests) and as a browser global // (renderer/app.js via index.html script tag) so a single implementation backs // runtime and tests — same pattern as queue-prune.js / queue-dedup.js. (function (root) { 'use strict'; const VALID_MODES = new Set(['single', 'daily', 'session']); function normalizeLogMode(globalSettings) { const gs = globalSettings && typeof globalSettings === 'object' ? globalSettings : {}; if (typeof gs.logMode === 'string' && VALID_MODES.has(gs.logMode)) { return gs.logMode; } // Legacy boolean migration: sessionLog *named* like "session" but actually // implemented "daily" — preserve daily users on the migration path. if (gs.sessionLog === true) return 'daily'; return 'single'; } function _two(n) { return String(n).padStart(2, '0'); } function formatDateStamp(date) { return `${date.getFullYear()}-${_two(date.getMonth() + 1)}-${_two(date.getDate())}`; } function formatSessionStamp(date, pid) { const d = `${date.getFullYear()}-${_two(date.getMonth() + 1)}-${_two(date.getDate())}`; const t = `${_two(date.getHours())}-${_two(date.getMinutes())}-${_two(date.getSeconds())}`; // PID disambiguates a same-second close→reopen — a human can't but two // automated runs might. Cheap belt to a suspenders-not-required problem. const pidStr = pid !== undefined && pid !== null ? `-${pid}` : ''; return `${d}_${t}${pidStr}`; } /** * Compute the log filename for the given mode + clock. * @param {Object} args * @param {string} args.baseName e.g. "fileuploader" * @param {string} args.ext e.g. ".log" * @param {string} args.mode "single" | "daily" | "session" * @param {Date} args.date current timestamp * @param {string} [args.sessionId] required when mode === "session" * @returns {string} the bare filename (no directory) */ function resolveLogFileName(args) { const a = args || {}; const base = String(a.baseName || 'fileuploader'); const ext = String(a.ext || '.log'); const mode = VALID_MODES.has(a.mode) ? a.mode : 'single'; if (mode === 'single') return `${base}${ext}`; if (mode === 'daily') { const date = a.date instanceof Date ? a.date : new Date(); return `${base}-${formatDateStamp(date)}${ext}`; } // session const sid = a.sessionId && String(a.sessionId).trim(); if (sid) return `${base}-session-${sid}${ext}`; // Defensive: if a session-id wasn't passed, fall back to single rather // than emit a malformed name. main.js always supplies one. return `${base}${ext}`; } const api = { normalizeLogMode, resolveLogFileName, formatDateStamp, formatSessionStamp, VALID_MODES }; if (typeof module !== 'undefined' && module.exports) { module.exports = api; } else if (root) { root.LogMode = api; } })(typeof window !== 'undefined' ? window : this);