Source: errorMiddleware.js

/**
 * @module errorMiddleware
 * @description Zentraler Express-Fehler-Handler der members-API.
 *
 * Warum ein eigenes Modul: der Handler enthielt lange nur
 * `res.status(500).send('Something broke!')`. Seit dem `memberA`-Trigger
 * (Migration `20260925-links-single-membera-trigger`) gibt es einen Fehler, der
 * **kein** Defekt ist — die Datenbank weist eine Aenderung ab, die eine
 * Invariante brechen wuerde. Solche Faelle brauchen eine eigene, testbare
 * Abbildung. Als Inline-Closure in `http-server.js` war das nicht testbar.
 */

/**
 * Datenbank-Signale, die eine **Invariante** durchsetzen, statt einen Defekt zu
 * melden.
 *
 * `SIGNAL SQLSTATE '45000'` setzt bei MariaDB `errno` auf 1644
 * (`ER_SIGNAL_EXCEPTION`). Die Zuordnung ist bewusst eng: nur wenn **beide**
 * Werte passen, gilt es als Konflikt. Ein 1644 mit anderem SQLState waere ein
 * unbekanntes Signal und soll weiter als 500 sichtbar sein, damit es nicht
 * stillschweigend als "normaler Konflikt" verschwindet.
 *
 * @param {any} err - Fehler aus der Query-Schicht
 * @returns {boolean}
 */
export const isInvariantViolation = (err) =>
    err?.errno === 1644 && err?.sqlState === '45000';

/**
 * Express-Fehler-Handler (4 Argumente — nur so erkennt Express ihn als solchen).
 *
 * @param {any} err
 * @param {import('express').Request} req
 * @param {import('express').Response} res
 * @param {import('express').NextFunction} _next
 * @returns {void}
 */
export const errorMiddleware = (err, req, res, _next) => {
    if (isInvariantViolation(err)) {
        // Die DB hat gerade eine Korruption verhindert — z. B. einen zweiten
        // aktiven `memberA`-Link. Das ist ein Konflikt (409), kein Crash (500).
        // Die Objekt-UID aus der DB-Meldung bleibt im Log; die Antwort geht an
        // einen Client, der sie nicht braucht, und bleibt deshalb generisch.
        console.error('Datenbank-Invariante verletzt:', err.message);
        res.status(409).json({
            success: false,
            code: 'DB_INVARIANT_VIOLATION',
            message: 'conflict: the change violates a database invariant and was rejected',
        });
        return;
    }

    console.error(err.stack);
    res.status(500).send('Something broke!');
};

export default errorMiddleware;