You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sims-hq/apps/hq/src/audit.ts

36 lines
1.3 KiB
TypeScript

import { uuidv7 } from '@sims/domain'
import type { DB } from './db'
export interface AuditRow {
id: string; at_wall: string; user_id: string; action: string
entity: string; entity_id: string; before_json: string | null; after_json: string | null
}
// listAudit orders by id DESC (UUIDv7 is time-ordered). Successive writes often land in
// the same millisecond, where UUIDv7's random tail would make the order arbitrary — so we
// bump the id timestamp monotonically per process to keep audit ids strictly ordered.
let lastIdMs = 0
function nextIdMs(): number {
const now = Date.now()
lastIdMs = now > lastIdMs ? now : lastIdMs + 1
return lastIdMs
}
export function writeAudit(
db: DB, userId: string, action: string, entity: string, entityId: string,
before?: unknown, after?: unknown,
): void {
db.prepare(
`INSERT INTO audit_log (id, at_wall, user_id, action, entity, entity_id, before_json, after_json)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
).run(
uuidv7(nextIdMs()), new Date().toISOString(), userId, action, entity, entityId,
before === undefined ? null : JSON.stringify(before),
after === undefined ? null : JSON.stringify(after),
)
}
export function listAudit(db: DB, limit = 200): AuditRow[] {
return db.prepare(`SELECT * FROM audit_log ORDER BY id DESC LIMIT ?`).all(limit) as AuditRow[]
}