/** * Fire-and-forget alert notification module. * Email sending is not yet implemented (Entra app pending). * Logs a formatted preview of what would be emailed to stderr. * Never throws — callers do not need to guard this. */ const os = require('os'); const TO = 'mike@azcomputerguru.com'; const FROM = 'sysadmin@dataforth.com'; const HOST = os.hostname(); const PREFIX = '[NOTIFY]'; const SEP_EQ = '='.repeat(60); const SEP_DAS = '-'.repeat(60); /** * Log a formatted email preview to stderr. * * @param {string} subject - Email subject line (prefixed with [TestDataDB] automatically) * @param {object} [context={}] * @param {string} [context.stage] - Pipeline stage where the alert fired * @param {string} [context.error] - Error message or description * @param {string[]} [context.details] - Additional detail lines * @param {object} [context.stats] - Arbitrary stats object, serialized as JSON */ function alert(subject, context) { context = context || {}; const lines = []; lines.push(`${PREFIX} ${SEP_EQ}`); lines.push(`${PREFIX} TO: ${TO}`); lines.push(`${PREFIX} FROM: ${FROM} (pending Entra app)`); lines.push(`${PREFIX} SUBJECT: [TestDataDB] ${subject}`); lines.push(`${PREFIX} ${SEP_DAS}`); lines.push(`${PREFIX} Host: ${HOST}`); lines.push(`${PREFIX} Time: ${new Date().toISOString()}`); if (context.stage !== undefined) { lines.push(`${PREFIX} Stage: ${context.stage}`); } if (context.error !== undefined) { lines.push(`${PREFIX}`); lines.push(`${PREFIX} ${context.error}`); } if (Array.isArray(context.details) && context.details.length > 0) { lines.push(`${PREFIX}`); for (const line of context.details) { lines.push(`${PREFIX} ${line}`); } } if (context.stats !== undefined) { lines.push(`${PREFIX} Stats: ${JSON.stringify(context.stats)}`); } lines.push(`${PREFIX} ${SEP_EQ}`); lines.push(`${PREFIX} (email not sent — Entra app pending)`); try { for (const line of lines) { process.stderr.write(line + '\n'); } } catch (_) { // stderr write failure — nothing we can do } } module.exports = { alert };