← back to Grant
lib/audit.ts
36 lines
import { query } from './db';
/**
* Log an audit event to the audit_events table.
*
* @param eventType - e.g. 'grant.created', 'login', 'org.updated'
* @param entityType - e.g. 'grant', 'user', 'organization'
* @param entityId - primary key of the affected entity (nullable)
* @param orgId - organization ID for multi-tenant scoping (nullable)
* @param userId - user who performed the action (nullable)
* @param metadata - arbitrary JSON payload with extra context
* @param ipAddress - client IP if available
*/
export async function auditLog(
eventType: string,
entityType: string,
entityId: string | null,
orgId?: string | null,
userId?: string | null,
metadata?: Record<string, unknown>,
ipAddress?: string,
): Promise<void> {
const metaJson = metadata ? JSON.stringify(metadata) : null;
try {
await query(
`INSERT INTO audit_events (event_type, entity_type, entity_id, org_id, user_id, metadata, ip_address)
VALUES ($1, $2, $3, $4, $5, $6, $7)`,
[eventType, entityType, entityId, orgId ?? null, userId ?? null, metaJson, ipAddress ?? null],
);
} catch (err) {
// Audit failures should never crash the calling operation
console.error('[audit] Failed to write audit event:', (err as Error).message);
}
}