- UNREGISTERED_MODELS set: 9 model numbers not in Hoffman API catalog; skipped silently instead of generating errors - batch-500 fallback: when a bulk batch returns HTTP 500, retry each record individually so good records get stamped and only truly-bad records count as errors - FAIL-parameter filter: records with any FAIL on a parameter line are excluded from the push before the batch is assembled - notify.js integration: wired in existing notification module Files added: - projects/dataforth-dos/database/upload-to-api.js - projects/dataforth-dos/database/notify.js Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
72 lines
2.2 KiB
JavaScript
72 lines
2.2 KiB
JavaScript
/**
|
|
* 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 };
|