Files
AtreidesAssetsFree/server/data/notifications.js
T

98 lines
4.2 KiB
JavaScript
Raw Permalink Normal View History

2026-10-29 11:57:29 +01:00
// Generated, do not edit. sha256:2e1c42ef1941376d221fab1a61b5e60c9be06530764fa9486b752263252805ed
import * as db from '../db.js';
import { ENUMS } from '../../shared/config.js';
import { nowIso, todayIso } from './_shared.js';
import { listPendingAiProposals } from './ai-proposals.js';
import { listPendingProposals } from './proposals.js';
import { dueCreditsAll } from './interest-credits.js';
import { listOpenValuationDiffs } from './valuations.js';
import { lightningBalanceDiffs } from './positions.js';
import { listDueReservations } from './reservations.js';
const dateToInt = d => Number(String(d).slice(0, 10).replace(/-/g, ''));
const NOTIFICATION_SOURCES = {
reconcile: { action: true, state() {
const p = listPendingProposals();
return { count: p.length, highWater: p.reduce((m, x) => Math.max(m, x.id), 0) };
} },
interest: { action: true, state() {
const due = dueCreditsAll();
return { count: due.length, highWater: due.reduce((m, d) => Math.max(m, dateToInt(d.periodEnd)), 0) };
} },
valuation: { action: true, state() {
const diffs = listOpenValuationDiffs();
return { count: diffs.length + lightningBalanceDiffs().length, highWater: diffs.reduce((m, v) => Math.max(m, v.id), 0) };
} },
schedule_ended: { action: false, state() {
const rows = db.all(`SELECT id, endsOn FROM InterestSchedule WHERE endsOn < ?`, [todayIso()]);
return { count: rows.length, highWater: rows.reduce((m, r) => Math.max(m, dateToInt(r.endsOn)), 0) };
} },
source_proposal: { action: true, state() {
const rows = db.all(`SELECT assetId, MAX(id) AS mid FROM PriceSource WHERE status = 'proposed' GROUP BY assetId`);
return { count: rows.length, highWater: rows.reduce((m, r) => Math.max(m, r.mid), 0) };
} },
ai_proposal: { action: true, state() {
const rows = listPendingAiProposals();
return { count: rows.length, highWater: rows.reduce((m, r) => Math.max(m, r.id), 0) };
} },
reservation: { action: true, state() {
const rows = listDueReservations();
return { count: rows.length, highWater: rows.reduce((m, r) => Math.max(m, dateToInt(r.occurredAt)), 0) };
} },
};
export async function refreshNotifications() {
let changed = false;
for (const kind of ENUMS.NOTIFICATION_KIND) {
const src = NOTIFICATION_SOURCES[kind];
if (!src) continue;
const { count, highWater } = src.state();
const active = db.one(`SELECT id, count, highWater FROM Notification WHERE kind = ? AND dismissedAt IS NULL ORDER BY id DESC LIMIT 1`, [kind]);
if (count === 0) {
if (src.action && active) { db.run(`DELETE FROM Notification WHERE id = ?`, [active.id]); changed = true; }
continue;
}
if (active) {
if (active.count !== count || active.highWater !== highWater) {
db.run(`UPDATE Notification SET count = ?, highWater = ? WHERE id = ?`, [count, highWater, active.id]);
changed = true;
}
continue;
}
const last = db.one(`SELECT highWater FROM Notification WHERE kind = ? ORDER BY id DESC LIMIT 1`, [kind]);
if (!last || highWater > last.highWater) {
db.run(`INSERT INTO Notification (kind, count, highWater, createdAt) VALUES (?,?,?,?)`, [kind, count, highWater, nowIso()]);
changed = true;
}
}
if (changed) await db.persist();
}
export function listActiveNotifications() {
return db.all(`SELECT id, kind, count, highWater, createdAt FROM Notification WHERE dismissedAt IS NULL ORDER BY id DESC`);
}
export async function currentNotifications() {
await refreshNotifications();
return listActiveNotifications();
}
export function notificationDetail(n) {
if (n.kind !== 'schedule_ended') return null;
const rows = db.all(`
SELECT s.accountId, ac.name AS account, po.symbol AS asset
FROM InterestSchedule s
JOIN Account ac ON ac.id = s.accountId
JOIN Asset po ON po.id = s.payoutAssetId
WHERE s.endsOn < ?
ORDER BY s.endsOn DESC, s.id DESC`, [todayIso()]);
if (!rows.length) return null;
return { accountId: rows[0].accountId, account: rows[0].account, asset: rows[0].asset, extra: rows.length - 1 };
}
export async function dismissNotification(id) {
db.run(`UPDATE Notification SET dismissedAt = ? WHERE id = ? AND dismissedAt IS NULL`, [nowIso(), id]);
await db.persist();
}