const { query } = require('../../utils/db') // SQL for installed_modules — the module system's record of what is installed and // what happened to it on the last boot (db/schema.sql, docs/website/MODULE_SYSTEM.md // §2.4). Rows are keyed by module id. All state rules live in modules.model.js; // this file only moves rows. const COLS = `id, name, version, state, failure_stage, failure_reason, source, sha256, installed_at, started_at, updated_at` const listAll = () => query(`SELECT ${COLS} FROM installed_modules ORDER BY id`) const getOne = (id) => query(`SELECT ${COLS} FROM installed_modules WHERE id = ?`, [id]) // Write (or refresh) the row for an installed module. A re-install or an upgrade // updates the metadata and deliberately leaves `state` alone: upgrading an enabled // module must not silently disable it, and re-installing a disabled one must not // silently switch it back on. A brand-new row lands in `installed`, the transient // state the next restart resolves. const upsert = ({ id, name, version, source, sha256 }) => query( `INSERT INTO installed_modules (id, name, version, source, sha256, state) VALUES (?, ?, ?, ?, ?, 'installed') ON DUPLICATE KEY UPDATE name = VALUES(name), version = VALUES(version), source = VALUES(source), sha256 = VALUES(sha256)`, [id, name, version, source ?? null, sha256 ?? null], ) // Move one row to a new state. `failureStage`/`failureReason` are written on every // call — a non-failing transition passes nulls, which is what clears a stale reason // off a module that has since come up. `stampStarted` sets started_at to now. const setState = ({ id, state, failureStage = null, failureReason = null, stampStarted = false }) => query( `UPDATE installed_modules SET state = ?, failure_stage = ?, failure_reason = ? ${stampStarted ? ', started_at = CURRENT_TIMESTAMP' : ''} WHERE id = ?`, [state, failureStage, failureReason, id], ) // Boot reset: every row the operator has not disabled goes back to `enabled` with // no failure recorded, so the load that follows writes this boot's outcome rather // than leaving the last one on display. `disabled` is untouched — it is a decision, // not an outcome. const resetForBoot = () => query( `UPDATE installed_modules SET state = 'enabled', failure_stage = NULL, failure_reason = NULL WHERE state <> 'disabled'`, ) // Drop the row entirely. Only the explicit purge does this (§2.5); a plain // uninstall disables the module and keeps its row and its data. const remove = (id) => query('DELETE FROM installed_modules WHERE id = ?', [id]) module.exports = { listAll, getOne, upsert, setState, resetForBoot, remove }