2baf29b3ae
Deliver encrypted health zone, observation API, baseline maturity pipeline, page-data bindings, and H5/WeChat channel integration for health P0. Co-authored-by: Cursor <cursoragent@cursor.com>
69 lines
2.5 KiB
JavaScript
69 lines
2.5 KiB
JavaScript
import { healthEventFingerprint, mapHealthEventToPgPayload } from './health-event-serialize.mjs';
|
|
|
|
export function createInMemoryHealthEventStore() {
|
|
const rowsByUser = new Map();
|
|
let nextId = 1;
|
|
|
|
return {
|
|
async list(userId, { status = 'open', limit = 100 } = {}) {
|
|
const rows = rowsByUser.get(String(userId)) ?? [];
|
|
return rows
|
|
.filter((row) => !status || row.status === status)
|
|
.slice(0, limit);
|
|
},
|
|
async listUnreadAlerts(userId, { limit = 20 } = {}) {
|
|
const rows = rowsByUser.get(String(userId)) ?? [];
|
|
return rows
|
|
.filter((row) => row.status === 'open' && (row.severity === 'watch' || row.severity === 'alert'))
|
|
.slice(0, limit);
|
|
},
|
|
async acknowledge(userId, eventId) {
|
|
const rows = rowsByUser.get(String(userId)) ?? [];
|
|
const index = rows.findIndex((row) => Number(row.id) === Number(eventId));
|
|
if (index < 0) return null;
|
|
rows[index] = { ...rows[index], status: 'acknowledged', acknowledgedAt: Date.now() };
|
|
return rows[index];
|
|
},
|
|
async acknowledgeAll(userId) {
|
|
const rows = rowsByUser.get(String(userId)) ?? [];
|
|
let count = 0;
|
|
for (let i = 0; i < rows.length; i += 1) {
|
|
if (rows[i].status === 'open' && (rows[i].severity === 'watch' || rows[i].severity === 'alert')) {
|
|
rows[i] = { ...rows[i], status: 'acknowledged', acknowledgedAt: Date.now() };
|
|
count += 1;
|
|
}
|
|
}
|
|
return count;
|
|
},
|
|
async insertIfNew(userId, event, { now = Date.now() } = {}) {
|
|
const key = String(userId);
|
|
const rows = rowsByUser.get(key) ?? [];
|
|
const fingerprint = healthEventFingerprint(event);
|
|
const duplicate = rows.find(
|
|
(row) => row.status === 'open' && healthEventFingerprint(row) === fingerprint,
|
|
);
|
|
if (duplicate) return { row: duplicate, created: false };
|
|
const payload = mapHealthEventToPgPayload(event, now);
|
|
const row = {
|
|
id: nextId++,
|
|
userId: key,
|
|
eventType: payload.event_type,
|
|
severity: payload.severity,
|
|
detectedAt: now,
|
|
ruleId: payload.rule_id,
|
|
metricsInvolved: JSON.parse(payload.metrics_involved),
|
|
evidenceObservationIds: [],
|
|
agentSummary: payload.agent_summary,
|
|
status: 'open',
|
|
message: payload.agent_summary,
|
|
metricType: event.metricType ?? null,
|
|
symptomCode: event.symptomCode ?? null,
|
|
createdAt: now,
|
|
};
|
|
rows.unshift(row);
|
|
rowsByUser.set(key, rows);
|
|
return { row, created: true };
|
|
},
|
|
};
|
|
}
|